function test(){
console.log(this)
}
test();//打印window
var t=new test()//打印test(){}
首先我们要明白上面这个this指向问题,普通函数调用,this指向window,而通过new来实例化一个构造函数的对象,则this指向函数。
1.call、apply和bind 的相同点和不同点
相同点:call、apply和bind都是JS函数的公有的内部方法,他们都是重置函数的this,改变函数的执行环节。
不同点:bind是创建一个新的函数,而call和aplay是用来调用函数;call和apply作用一样,只不过call为函数提供的参数是一个个地罗列出来,而apply为函数提供的参数是一个数组。
2.call的用途。
首先,在函数调用的时候,我们都习惯直接调用,比如说function test(){};test();其实这并不是函数调用的本质,本质是test.call();test()只不过是本质的语法糖,它只能调用,而不能改变函数的执行环境。如下所示。
function test(){
console.log("hello world");
}
//函数的一般调用
test();
//函数调用的本质
test.call()
那么call是如何改变函数的执行环境的?如下所示:
//这个myName变量相当于给window这个对象添加了一个myName属性
var myName="yyl"
function test(){
//此时的this就是指window
console.log(this.myName)//打印yyl
}
test()
var obj={myName:"hhh"}
test.call(obj)//打印hhh
这也就解释了我们之前写的那篇原型中,子函数要想继承父函数需要在子函数中写{Father.call(this)},这个this指向的是Son函数,那么就改变了Father的this指向,将其指向到Son函数中,也就实现了Son函数的实例调用Father的属性。如下所示。
function Father() {
this.health = "very good"
}
function Son() {
Father.call(this);
}
var son = new Son();
console.log(son.health)//打印very good
当然,这样写也可以。
function Father() {
this.health = "very good"
}
function Son() {}
var son = new Son();
Father.call(son);
console.log(son.health)//打印very good
3.apply的用途。
apply除了后面的参数形式与call有区别,其他都一样。比如上面所有用到call的地方都可以用apply来代替。千万不要小看了这个这个参数形式,有些情况下就只能用apply不能用call,比如使用Math.max去获取数组(这个数组有很多元素)的最大值时,若是用call,需要将数组的所有元素陈列出来,而使用apply直接写一个数组就可以。如下:
var arr=[1,3,2,6,4];
//1.普通调用方法,是下面这个call方法的语法糖
console.log(Math.max(1,2,3,6,4))//打印6
//调用的实质
console.log(Math.max.call(null,1,2,3,6,4));//打印6
//使用apply方法
console.log(Math.max.apply(null,arr));//打印6
4.bind的用途。
直接上代码:
var myName="yyl";
function test1(){
console.log(this.myName);
}
test1();//打印yyl
var obj={myName:"hhh"}
var test2=test1.bind(obj);
test2();//打印hhh
可以看出bind与call的唯一区别就是call直接改变函数test的指向,而bind是生成了一个新函数test2,该函数改变了指向。