【JS】this
zh-rocco opened this issue · comments
this
this
是和 执行上下文环境 息息相关的一个特殊对象。因此,它也可以称为 上下文对象[context object] (激活执行上下文的上下文)。
this
是执行上下文环境的一个属性,而不是某个变量对象的属性。
this 指向
this
的指向。除去不常用的 with
和 eval
的情况,具体到实际应用中,this
的指向大致可以分为以下 4 种:
- 作为对象的方法调用
- 作为普通函数调用
- 构造器调用
call
,apply
,bind
调用
1. 作为对象的方法调用
当函数作为对象的方法被调用时,this
指向该对象
2. 作为普通函数调用
当函数不作为对象的属性被调用时,也就是我们常说的普通函数方式,此时的 this
总是指向全局对象。在浏览器的 JavaScript 里,这个全局对象是 window
对象。
在 ECMAScript 5 的 strict
模式下,这种情况下的 this
已经被规定为不会指向全局对象,而是 undefined
。
3. 构造器调用
当用
new
运算符调用函数时,该函数 总会返回一个对象,通常情况下,构造器里的this
就指向返回的这个对象。
但用 new
调用构造器时,还要注意一个问题,如果构造器显式地返回了一个 object
类型的对象,那么此次运算结果最终会返回这个对象,而不是我们之前期待的 this
。
var MyClass = function() {
this.name = 'sven';
// 显式地返回一个对象
return {
name: 'anne',
};
};
var obj = new MyClass();
alert(obj.name); // 输出: anne
如果构造器不显式地返回任何数据,或者是返回一个非对象类型的数据,就不会造成上述问题:
var MyClass = function() {
this.name = 'sven';
return 'anne'; // 返回 string 类型
};
var obj = new MyClass();
alert(obj.name); // 输出: sven
4. call
,apply
,bind
调用
当使用
call
或者apply
的时候,如果我们传入的第一个参数为null
,函数体内的this
会指向默认的宿主对象,在浏览器中则是window
;但如果是在严格模式下,函数体内的this
还是为null
。
有时候我们使用 call
或者 apply
的目的不在于指定 this
指向,而是另有用途,比如借用其他对象的方法。那么我们可以传入 null
来代替某个具体的对象:
Math.max.apply( null, [ 1, 2, 5, 3, 4 ] ) // 输出:5
实现一个 bind
:
简易版
Function.prototype.bind = function(context) {
var self = this; // 保存原函数
// 返回一个新的函数
return function() {
return self.apply(context, arguments); // 执行新的函数的时候,会把之前传入的 context 当作新函数体内的 this
};
};
完整版
Function.prototype.bind = function() {
var self = this, // 保存原函数
context = [].shift.call(arguments),
args = [].slice.call(arguments);
// 返回一个新的函数
// 需要绑定的 this 上下文
// 剩余的参数转成数组
return function() {
return self.apply(context, [].concat.call(args, [].slice.call(arguments))); // 执行新的函数的时候,会把之前传入的 context 当作新函数体内的 this,并且组合两次分别传入的参数,作为新函数的参数
};
};
var obj = {
name: 'sven',
};
var func = function(a, b, c, d) {
alert(this.name); // 输出: sven
alert([a, b, c, d]); // 输出: [ 1, 2, 3, 4 ]
}.bind(obj, 1, 2);
func(3, 4);