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
用数学上的表示方式是 [ 0, 1 ) 左闭右开,开区间的意思是不可能到 1
Math.random(); // 0.26011405302191126 Math.random(); // 0.011724293403471586 Math.random(); // 0.9351609567822634
现在产生十次,0 到 1 之间的随机小数,
然后保留两位小数变成 0.00 ~ 0.99, toFixed() 方法可把 Number 四舍五入为指定小数位数的数字
再乘以 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() 有一个高深的用法,括号里面可以传参数,
Person()和Person.call()是一样的,但是call()里面可以传参数
function Person(name, age){ this.name = name; this.age = age; } var obj = { } Person.call(obj); // 1.把对象obj传进去会让Person里面预设的this全部变成obj Person.call(obj, 'Glee', 37); // 2.从第二位开始传参数 console.log(obj); // 3.现在对象obj变成这样 {name: "Glee", age: 37}
不用 new 操作 Person 函数时,函数里面的 this 默认指向 window,
但是把 obj 传进去,Person.call(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指向,传参列表不同。