Go to comments

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);

}

image.png

为什么不准?

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指向,传参列表不同。



Leave a comment 0 Comments.

Leave a Reply

换一张