this 关键字
JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。
全局环境
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。
// 浏览器中,window对象同时也是全局对象
console.log(this === window) // true
函数(运行内)环境
在函数内部,this 的值取决于函数被调用的方式。
非严格模式
function f1() {
return this;
}
// 在浏览器中
f1() === window; // true
严格模式
function f2(){
"use strict";
return this;
}
f2() === undefined; // true
如果想要把 this 的值从一个环境传到另一个环境,就要用 call 或者 apply 方法。
call、apply方法
// 将一个对象作为 call 和 apply 的第一个参数,this 会被绑定到这个对象
let obj = { a: 'Custom' };
let a = 'Global';
function whatsThis( arg ) {
return this.a; // this 的值取决于函数的调用方式
}
whatsThis(); // 'Global'
whatsThis.call(obj); // 'Custom'
whatsThis.apply(obj); // 'Custom'
当一个函数在其主体中使用 this 关键字时,可以通过使用函数继承自 Function.prototype 的 call 或 apply 方法将 this 值绑定到调用的特定对象。
function add( c,d ){
return this.a + this.b + c + d;
}
let o = { a: 1, b: 3 };
// 第一个参数是作为‘this’使用的对象
// 后续参数作为参数传递给函数调用
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
// 第一个参数也是作为‘this’使用的对象
// 第二个参数是一个数组,数组里的元素用作函数调用中的参数
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
使用 call 和 apply 函数的时候要注意,如果传递给 this 的值不是一个对象,JavaScript 会尝试使用内部 ToObject 操作将其转化为对象。因此,如果传递的值是一个原始值比如 7 或 ‘foo’,那么会使用相关构造函数将它转换为对象,所以原始值 7 会被转换为对象,像 new Number(7),而字符串 ‘foo’ 转化为 new String( 'foo' )。
bind方法
ES5 引入了 Function.prototype.bind。调用 f.bind(obj) 会创建一个与 f 具有相同函数体和作用域的函数,但是在这个新函数中,this 将永久被绑定到 bind 的第一个参数,无论这个函数是如何被调用的。
function f() {
return this.a;
}
let g = f.bind( { a:"azerty" } );
console.log( g() ); // azerty
let h = g.bind( { a:'yoo' } ); // bind只生效一次!
console.log( h() ); // azerty
let o = { a: 37, f: f, g: g, h: h };
console.log( o.f(), o.g(), o.h() ); // 37, azerty, azerty
各种情况下this 的指向问题:
箭头函数
在箭头函数中,this 与封闭词法环境的 this 保持一致。在全局代码中,它将被设置为全局对象。无论如何,函数的 this 被设置为他被创建时的环境。这同样适用于在其他函数内创建的箭头函数:这些箭头函数的 this 被设置为封闭的词法环境。
注意:箭头函数中,如果将 this 传递给 call、bind、apply,它将被忽略。
作为对象的方法
当函数作为对象里的方法被调用时,它们的 this 是调用该函数的对象。
注意:这样定义的函数不受函数定义方式或位置的影响。同样,this 的绑定只受最靠近的成员引用的影响。
原型链中的 this
如果该方法存在于一个对象的原型链上,那么 this 指向的是调用这个方法的对象,就像该方法在对象上一样。
getter 与 setter 中的 this
用作 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象。
作为构造函数
当一个函数用作构造函数时(使用 new 关键字),它的 this 被绑定到正在构造的新对象。
作为一个DOM事件处理函数
当函数被用作事件处理函数时,它的 this 指向触发事件的元素(一些浏览器在使用非 addEventListener 的函数动态添加监听函数时不遵守这个约定)。
作为一个内联事件处理函数
当代码被内联 on-event 处理函数调用时,它的 this 指向监听器所在的 DOM 元素。
网友评论