Javascript中this的解释

  在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);

Javascript专题