JavaScript call和apply
一、js精度不准
0.14 * 100 这个就是bug,js有时候会发生精度一小点的偏差
console.log(0.14 * 100); // 14.000000000000002
js尽量避免小数操作,即使要小数操作要加 Math.ceil() 向上取整,向上取整就是0.1都会认为是1, Math.floor() 是向下取整
Math.ceil(123.456); // 向上取整 124 Math.floor(123.9999); // 向下取整 123
Math.random() 产生 0 ~ 1 之间的随机数,开区间数(0 , 1)两边不可能到头
console.log(Math.random()); // 0.26011405302191126 console.log(Math.random()); // 0.011724293403471586 console.log(Math.random()); // 0.9351609567822634
1. 现在产生十次,0到1之间的随机小数,
2. 然后保留两位小数变成 0.00 - 0.99, toFixed() 方法可把Number四舍五入为指定小数位数的数字
3. 再乘以100生成0到100之间的整数,会发现有时候不准
for(var i = 0; i < 10; i ++){ var num = Math.random().toFixed(2) * 100; console.log(num); }
为什么不准?
跟 0.14 x 100 一样,会发生精度的小偏差,
所以再处理这样的情况,一般不用 toFixed() ,直接先乘100然后取整,取整就没有精度问题了
for(var i = 0; i < 10; i ++){ var num = Math.floor(Math.random() * 100); console.log(num); }
网上说 toFixed() 保留两位小数有问题,其实就是js精度不准
js小数点后最多能容纳多少位?
可正常计算的范围是,小数点后15位,小数点前16位
console.log(0.000000000000001 + 0.000000000000001); //小数点后15位返回 2e-15 console.log(0.0000000000000001 + 0.0000000000000001); //小数点后16位返回 2e-16 console.log(0.00000000000000001 + 0.00000000000000001); //小数点后17位返回 2e-17 console.log(0.000000000000000001 + 0.000000000000000001); //小数点后18位返回 2e-18 console.log(0.0000000000000000001 + 0.0000000000000000001); //小数点后19位返回 2e-19
小数点前17位就出现不精准的问题了
console.log(100000000000001 + 100000000000001); // 小数点前15位 200000000000002 console.log(1000000000000001 + 1000000000000001); // 小数点前16位 2000000000000002 console.log(10000000000000001 + 10000000000000001); // 小数点前17位 20000000000000000
小数点后6位是正常显示,小数点后7位是科学计数法表示了
console.log(0.0000001 + 0.0000001); // 小数点后7位 2e-7 console.log(0.000001 + 0.000001); // 小数点后6位 0.000002
二、call和apply
作用:改变this指向
区别:后面传的参数形式不同
call和apply这个知识点非常小但应用非常的广,作用是改变this的指向
任何一个方法都可以用call()方法,其实call()才是这个方法执行的真实面目,
正常是这样 test() 执行函数
function test(){ console.log('lalaala'); } test();
其实 test() 执行内部会经历一个变化,这是 test.call() 它应有的面目
function test(){ console.log('lalaala'); } test.call();
test() ---> test.call() test.call()和正常执行test()是一样的
call()有一个高深的用法,括号里面可以传参数
function Person(name, age){ this.name = name; this.age = age; } var obj = { } // Person()和Person.call()是一样的,但是call()里面可以传参数, Person.call(obj); // 1.把对象obj传进去会让Persn里面预设的this全部变成obj Person.call(obj, 'Glee', 37); // 2.从第二位开始传参数 console.log(obj); // 3.现在对象obj变成这样 {name: "Glee", age: 37} /** * 不用new操作Person函数时,函数里面的this默认指向window, * Person.call(obj) 但是把obj传进去,this就变成了obj * * function Person(name, age){ * // 里面变化 this == obj * obj.name = name; * obj.age = age; * } * */
call()的根本作用是改变this指向,
第一位参数是改变this的指向,
第二位参数以后的参数,当做正常的实参传到实参里面,
借用Person方法来实现obj的功能,构造完后obj变成 {name: "Glee", age: 37}
比如在一个部门开发,你写的方法如果能实现我的功能,那我就不用再写了
function Person(name, age, sex){ this.name = name; this.age = age; this.sex = sex; } function Student(name, age, sex, tel, grade){ // 1.Person.call(this) 这个this就是new对象的第一步,隐式生成的this // var this = {name:"", age:"", sex:""} // 2.相当于把Person里面的三行属性拿过来了(拿到隐式的this里) // this.name = name; // this.age = age; // this.sex = sex; Person.call(this, name, age, sex); this.tel = tel; this.grade = grade; } var Li = new Student('Glee', 37, 'femate', 132, 2006); console.log(Li); // Student {name: "Glee", age: 37, sex: "femate", tel: 132, grade: 2006}
Student的功能完美涵盖了Person的功能,利用Person方法实现了Student功能,
这个例子是真实,实战开发的一个企业级的应用但是比较简单,call()只有一个应用就是改变this指向,改变this指向导出了一个功能,叫借用别人的函数实现自己的功能。
工厂车间模块化造车,Wheel轮子、sit座椅、Model汽车框架等,把这些东西组装起来。
function Wheel(wheelSize, style){ this.weelSize = wheelSize; // 车轮尺寸 this.style = style; // 车轮风格 } function Sit(comfortable, sitColor){ this.comfortable = comfortable; // 座椅舒适程度 this.sitColor = sitColor; // 座椅颜色 } function Model(height, width, len){ this.height = height; // 汽车模型的长 this.width = width; // 汽车模型的宽 this.len = len; // 汽车模型的高 } function Car(wheelSize, style, comfortable, sitColor, height, width, len){ Wheel.call(this, wheelSize, style); Sit.call(this, comfortable, sitColor); Model.call(this, height, width, len); } var car = new Car('车轮直径100CM', '黑色的车轮', '真皮座椅', '座椅卡其色', '车高1800CM', '车长1900CM', '车重4900公斤'); console.log(car); // Car {weelSize: "车轮直径100CM", style: "黑色的车轮", comfortable: "真皮座椅", sitColor: "座椅卡其色", height: "车高1800CM", …}
造车的工厂Car函数里一行都没写,用的都是别的工厂的零部件,这是企业里协调配合开发,总有一些人在写零部件,零部件就是基础框架(编程都用的东西,会先写好),
当然企业级的开发不可能这么简单,this就等于一行(this.height = height),后面可能等于一个立即执行函数一顿处理,完后把结果返回。
apply()和call()功能是一样的几乎没区别,唯一一点区别传参列表不一样,
第一位都是改变this指向的对象,
第二位call()一位一位的传实参进去,apply()只能传一位实参并且传的实参必须是数组形式,也就是说apply()必须传一个数组。
call()需要把实参按照形参的个数传进去,apply()需要传一个arguments
function Wheel(wheelSize, style){ this.weelSize = wheelSize; this.style = style; } function Sit(comfortable, sitColor){ this.comfortable = comfortable; this.sitColor = sitColor; } function Model(height, width, len){ this.height = height; this.width = width; this.len = len; } function Car(wheelSize, style, comfortable, sitColor, height, width, len){ Wheel.apply(this, [wheelSize, style]); Sit.apply(this, [comfortable, sitColor]); Model.apply(this, [height, width, len]); } var car = new Car('车轮直径100CM', '黑色的车轮', '真皮座椅', '座椅卡其色', '车高1800CM', '车长1900CM', '车重4900公斤');
58同城的面试题
JavaScript的call和apply方法是做什么的,两者有什么区别?改变this指向,传参列表不同。