this
在JavaScript的世界中,this是一个很让人挠头的概念,为什么呢?第一,它总是指向一个对象,使用起来可以简化代码。第二,它是基于函数的执行环境进行动态绑定的,而不是在函数被声明时的环境被指定。
this的指向
作为对象的方法被调用
此时,this指向该对象。如代码所示:
var obj = {
a:1,
getA:function(){
console.log(this === obj);
console.log(this.a);
}
};
obj.getA();
普通函数调用
此时,指向的是全局对象。如果是在浏览器中,那么这全局对象就是window。如代码所示:
window.name = 'globalName';
var myObject = {
name : 'bill',
getName : function () {
return this.name;
}
}
var getName = myObject.getName();
console.log(getName);
构造器被调用
此时,this指向的是返回的对象。如下代码
var myClass = function () {
this.name = 'bill';
}
var obj = new myClass();
console.log(obj.name);
注意:在构造器的调用中,有一类特殊情况。如果,在构造器中显示地返回了一个object类型的对象,那么最终的this还是指向被返回的对象。如下所示:
var MyClass = function(){
this.name = 'bill';
return {
name : 'cindy'
}
};
var obj = new MyClass();
console.log(obj.name);
被call或者apply调用
此时,this的指向有call或者apply函数的第一个参数决定。如下代码所示
var obj = {
name : 'bill',
getName : function () {
return this.name;
}
};
var obj2 = {
name : 'cindy'
};
console.log(obj.getName());
console.log(obj.getName.call(obj2));
this丢失
啥叫丢失呢?咱们看一段代码先
var obj = {
name : 'bill',
getName : function(){
return this.name;
}
};
console.log(obj.getName());
var getName2 = obj.getName;
console.log(getName2());
为什么会丢失?因为,在将引用赋值给变量getName2之后,getName2被调用的时候,是一种普通函数调用,而普通函数调用,我们已经知道了一直指向全局对象,此时的全局对象中并没定义name的值。因此返回的是undefined。
call和apply
这俩函数,是在ECAMscript3中给Function对象定义的两个方法。实际开发过程中,这哥俩被用到的频率非常高,用处很大!
区别
首先,作用是基本一致的。都是调用对象的方法。唯一的不同就是传入参数的形式不一样
call调用的时候:
var func = function (a,b,c){
console.log([a,b,c])
};
func.call(null,1,2,3);
apply调用:
var func = function (a,b,c){
console.log([a,b,c])
};
func.apply(null,[1,2,3]);
小结:
区别:call传入的参数数量不固定,参数会被依次被传递.而apply使用的是一个带下标的集合,它可以是数组,或者是类数组。
相同点:他们的第一个参数都是代表的是this的指向。
关系:call是在apply的基础上包装的语法糖。
应用场景:但是两者各有不同的应用场景。call更多的是在明确知道函数接收多少参数的情况下进行使用,想要清楚看到形参和实参的对应关系,用call就对了。apply是在不知道具体参数的个数的情况下使用,apply的使用效率会更高。
用途:
- 借用其他对象的方法
- 改变this的指向
- Function.prototype.bind
注意:其他内部的原理,也是通过指定this的指向来实现的。
小结:
在JavaScript的高级应用中,弄清楚this的指向,并熟悉call和apply方法的使用,是每个想要进阶JavaScript的工程师不可避免的话题。
this的指向,分别在四种不同的情况下有不同的表现:
- 通过对象的方法的形式调用,始终指向该对象。
- 通过普通函数的形式调用的时候,始终指向全局对象。如果是在浏览器环境中,则指向全局对象是window
- 通过构造器访问的时候,始终指向被返回的对象
- 通过call和apply调用的时候,由call或者是apply方法的第一个参数来决定。
call和apply,作用一致都可以用来调用其他对象的方法和改变this的指向。两者的区别仅仅在于参数的使用方式上,call需要明确参数的个数和顺序。而apply不需要知道,一股脑通过一个集合传过去就OK了。