function nonStrictSum(a, b) { // 非严格模式 console.log(this === window); // => true return a + b; } function strictSum(a, b) { 'use strict'; // 启用严格模式 console.log(this === undefined); // => true return a + b; } nonStrictSum(5, 6); // => 11 strictSum(8, 12); // => 20
2.3 陷阱:this 在内部函数中的时候
函数调用的一个常见陷阱是,认为this在内部函数中的情况与外部函数中的情况相同。
正确地说,内部函数的上下文只依赖于它的调用类型,而不依赖于外部函数的上下文。
要将 this 设置为所需的值,可以通过 .call()或.apply()修改内部函数的上下文或使用.bind()创建绑定函数。
下面的例子是计算两个数的和:
function nonStrictSum(a, b) { // 非严格模式 console.log(this === window); // => true return a + b; } function strictSum(a, b) { 'use strict'; // 启用严格模式 console.log(this === undefined); // => true return a + b; } nonStrictSum(5, 6); // => 11 strictSum(8, 12); // => 20
sum()是对象上的方法调用,所以sum中的上下文是numbers对象。calculate函数是在sum中定义的,你可能希望在calculate()中this也表示number对象。
calculate()是一个函数调用(不是方法调用),它将this作为全局对象window(非严格模下)。即使外部函数sum将上下文作为number对象,它在calculate里面没有影响。
sum()的调用结果是NaN,不是预期的结果5 + 10 = 15,这都是因为没有正确调用calculate。
为了解决这个问题,calculate函数中上下文应该与 sum 中的一样,以便可以访问numberA和numberB属性。
一种解决方案是通过调用calculator.call(this)手动将calculate上下文更改为所需的上下文。
const numbers = { numberA: 5, numberB: 10, sum: function() { console.log(this === numbers); // => true function calculate() { console.log(this === numbers); // => true return this.numberA + this.numberB; } // 使用 .call() 方法修改上下文 return calculate.call(this); } }; numbers.sum(); // => 15
call(this)像往常一样执行calculate函数,但 call 会把上下文修改为指定为第一个参数的值。
现在this.numberA + this.numberB相当于numbers.numberA + numbers.numberB。 该函数返回预期结果5 + 10 = 15。
另一种就是使用箭头函数
const numbers = { numberA: 5, numberB: 10, sum: function() { console.log(this === numbers); // => true const calculate = () => { console.log(this === numbers); // => true return this.numberA + this.numberB; } return calculate(); } }; numbers.sum(); // => 15
3.方法调用
方法是存储在对象属性中的函数。例如
const myObject = { // helloFunction 是一个方法 helloFunction: function() { return 'Hello World!'; } }; const message = myObject.helloFunction();
helloFunction是myObject的一个方法,要调用该方法,可以这样子调用 :myObject.helloFunction。
当一个表达式以属性访问的形式执行时,执行的是方法调用,它相当于以个函数接着(,一组用逗号分隔的参数以及)。
利用前面的例子,myObject.helloFunction()是对象myObject上的一个helloFunction的方法调用。[1, 2].join(',') 或/\s/.test('beautiful world')也被认为是方法调用。
区分函数调用和方法调用非常重要,因为它们是不同的类型。主要区别在于方法调用需要一个属性访问器形式来调用函数(obj.myFunc()或obj['myFunc']()),而函数调用不需要(myFunc())。
['Hello', 'World'].join(', '); // 方法调用 ({ ten: function() { return 10; } }).ten(); // 方法调用 const obj = {}; obj.myFunction = function() { return new Date().toString(); }; obj.myFunction(); // 方法调用 const otherFunction = obj.myFunction; otherFunction(); // 函数调用 parseFloat('16.60'); // 函数调用 isNaN(0); // 函数调用
理解函数调用和方法调用之间的区别有助于正确识别上下文。
3.1 方法调用中 this 是肿么样
在方法调用中,this是拥有这个方法的对象当调用对象上的方法时,this就变成了对象本身。
创建一个对象,该对象有一个递增数字的方法