this 的简要概述
this 在 JavaScript 中是动态作用域。它的行为不同于所有其他词法范围的变量。其他变量没有不同的绑定,具体取决于函数的调用方式;它们的范围来自它们在脚本中出现的位置。 this 但是行为不同,并且可以具有不同的绑定,这取决于它在脚本中出现的位置而不是 如何。因此,对于学习该语言的人来说,它可能是一个困惑的根源,但要成为一名熟练的 JavaScript 开发人员,掌握它是必要的。
由于this 是动态绑定的,因此有多种方法可以根据您调用函数的方式更改其值。
示例
当你在 JavaScript 中执行一个函数时,默认的this 是window。
function foo() {
console.log(this);
}
foo(); // => window
this 值可以通过多种方式进行更改。一种方法是将函数作为对象的方法调用:
var x = {
foo: function() {
console.log(this);
}
};
x.foo(); // => This time it's the x object.
另一种方法是使用call 或apply 告诉函数在某个对象的上下文中执行。
function foo() {
console.log(this);
}
foo.call(x); // => x object again
foo.apply(x); // => x object as well
如果你在null或undefined上call或apply,则会再次出现默认行为:该函数将在window的上下文中执行:
function foo() {
console.log(this);
}
foo.call(null); // => window
foo.apply(undefined); // => window
但是,请注意,在 ECMAScript 5 严格模式中,this 不默认为窗口:
(function() {
'use strict';
function foo() {
console.log(this);
}
foo(); // => undefined
foo.call(null); // => null
foo.apply(undefined); // => undefined
})();
您也可以设置this,在调用之前使用bind将函数绑定到对象:
function foo() {
console.log(this);
}
var bar = {
baz: 'some property'
};
var foobar = foo.bind(bar);
foobar(); // => calls foo with bar as this
Going Father: Lazy Bind / Uncurrying this
更进一步,您有时可能希望采用作用于this 的函数,并允许将this 值作为函数的第一个参数传入。这对于 Array 方法非常有用,例如 forEach。例如,假设您正在处理一个类似数组但实际上不是数组的对象。
var arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
'length': 3
};
如果你想用forEach 迭代这个对象,你可以使用call:
Array.prototype.forEach.call(arrayLike, function(item) {
console.log(item);
});
// Logs: a, b, c
但是,另一种选择是创建一个forEach 函数,该函数可以直接在您的对象上调用:
var forEach = Function.prototype.call.bind(Array.prototype.forEach);
现在您可以随时使用此函数来迭代类似数组的对象:
forEach(arrayLike, function(item) {
console.log(item);
});
// Logs: a, b, c
有时这种方法被称为“uncurrying this”。但是,我更喜欢创建一个可以生成这些“非curried”函数并将其称为“惰性绑定”的函数。
var lazyBind = Function.prototype.bind.bind(Function.prototype.call);
var forEach = lazyBind(Array.prototype.forEach);
var slice = lazyBind(Array.prototype.slice);
var map = lazyBind(Array.prototype.map);
forEach(arrayLike, function(u) {
console.log(u);
});
// Logs: a, b, c
var realArray = slice(arrayLike);
// Converts arrayLike into a real array
forEach(
map(arrayLike, function(u) {
return u + 'Q';
}),
function(u) {
console.log(u);
}
);
// Logs: aQ, bQ, cQ
关于这种技术的一个非常棒的事情是它可以用于创建安全的 JavaScript,如果您不希望页面上的其他脚本窥探您的内部变量,这将很有帮助。不过,这是一种非常先进的元编程技术,您在日常的 JavaScript 中看不到它。