在Javascript中,this是当前函数的执行上下文,因为语言有4个函数调用类型:
函数调用: alert(‘Hello World!’)
方法调用: console.log(‘Hello World!’)
构造器调用: new RegExp(’\d’)
间接调用: alert.call(undefined, ‘Hello World!’)
每个定义了自己的上下文,因此不同的上下文this意思有点不一样。
函数调用
函数调用有两种:
function hello(name) {
…
}
或
var message = (function(name) {
…
}
在这种情况下,this代表全局对象。所谓全局由程序执行的环境决定,如果是在浏览器中是window对象,如果是在Node.js中是process对象。
strict模型是在 ECMAScript 5.1导入,那么在这种模型下,this是未定义的underfined。
为了激活strict模型,需要在函数体顶部使用 ‘use strict’,这样整个函数内容都会使得this变成undefined.
方法调用
一个方法是一个对象中作为属性的函数:
var myObject = {
// helloFunction is a method
helloFunction: function() {
return ‘Hello World!’;
}
};
var message = myObject.helloFunction();
this在方法调用中是指拥有这个方法的对象。
var calc = {
num: 0,
increment: function() {
console.log(this === calc); // => true
this.num += 1;
return this.num;
}
};
// method invocation. this is calc
calc.increment(); // => 1
calc.increment(); // => 2
在 javascript 6中的class语法,方法调用的上下文还是实例自己:
class Planet {
constructor(name) {
this.name = name;
}
getName() {
console.log(this === earth); // => true
return this.name;
}
}
var earth = new Planet(‘Earth’);
// method invocation. the context is earth
earth.getName(); // => ‘Earth’
构造器调用
构造器调用是通过new创建的,在这种情况下this是最新创建的那个对象。
function Foo () {
console.log(this instanceof Foo); // => true
this.property = ‘Default Value’;
}
// Constructor invocation
var fooInstance = new Foo();
fooInstance.property; // => ‘Default Value’
同样,Javascript 6中:
class Bar {
constructor() {
console.log(this instanceof Bar); // => true
this.property = ‘Default Value’;
}
}
// Constructor invocation
var barInstance = new Bar();
barInstance.property; // => 'Def
间接调用
间接调用是指使用.call()或apply()方法调用,在这种情况下this是.call()或apply()的第一个参数。
.call(thisArg[, arg1[, arg2[, …]]])的第一个参数thisArg是作为调用的上下文,后面带着真正参数arg1 arg2…,而在.apply(thisArg, [args])中,接受thisArg作为第一个参数作为调用上下文,后面是类似数组对象。这两个函数都是为了在Javascript中使用函数式编程方法。
var rabbit = { name: ‘White Rabbit’ };
function concatName(string) {
console.log(this === rabbit); // => true
return string + this.name;
}
// Indirect invocations
concatName.call(rabbit, 'Hello '); // => ‘Hello White Rabbit’
concatName.apply(rabbit, ['Bye ']); // => ‘Bye White Rabbit’
bound函数
bound函数是一个使用对象绑定的函数,通常是使用.bind()方法创建,原始函数和bound函数共享同样的代码和作用域,但是执行的上下文不同。
.bind(thisArg[, arg1[, arg2[, …]]])也是执行第一个参数thisArg作为bound函数的上下文。在这种情况下,this是bind()函数的第一个参数。
var numbers = {
array: [3, 5, 10],
getNumbers: function() {
return this.array;
}
};
// Create a bound function
var boundGetNumbers = numbers.getNumbers.bind(numbers);
boundGetNumbers(); // => [3, 5, 10]
// Extract method from object
var simpleGetNumbers = numbers.getNumbers;
simpleGetNumbers(); // => undefined or throws an error in strict mode
箭头函数
箭头函数是定义一个更短形式和词汇上lexically 绑定上下文。
var hello = (name) => {
return 'Hello ’ + name;
};
hello(‘World’); // => ‘Hello World’
// Keep only even numbers
[1, 2, 5, 6].filter(item => item % 2 === 0); // => [2, 6]
在这种情况下,this是指封闭类enclosing上下文。
箭头函数不会创建自己的执行上下文,但是会用this从外部函数拿过来使用。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
log() {
console.log(this === myPoint); // => true
setTimeout(()=> {
console.log(this === myPoint); // => true
console.log(this.x + ‘:’ + this.y); // => ‘95:165’
}, 1000);
}
}
var myPoint = new Point(95, 165);
myPoint.log();
如果箭头函数在大多数作用域顶部也就是任何函数外部定义,那么上下文就是全局对象,浏览器是window,而NodeJS是process:
var getContext = () => {
console.log(this === window); // => true
return this;
};
console.log(getContext() === window); // => true
箭头函数一旦和词汇上下文绑定一次就是永远了,this就不能修改,即使使用上下文修改方法:
var numbers = [1, 2];
(function() {
var get = () => {
console.log(this === numbers); // => true
return this;
};
console.log(this === numbers); // => true
get(); // => [1, 2]
// Use arrow function with .apply() and .call()
get.call([0]); // => [1, 2]
get.apply([0]); // => [1, 2]
// Bind
get.bind([0])(); // => [1, 2]
}).call(numbers)