很多时候, JS 中的 this 对于咱们的初学者很容易产生困惑不解。 this 的功能很强大,但需要一定付出才能慢慢理解它。
对Java、PHP或其他标准语言来看,this 表示类方法中当前对象的实例。大多数情况下,this 不能在方法之外使用,这样就比较不会造成混淆。
在J要中情况就有所不同: this表示函数的当前执行上下文,JS 中函数调用主要有以下几种方式:
函数调用: alert('Hello World!')
方法调用: console.log('Hello World!')
构造函数: new RegExp('\\d')
隐式调用: alert.call(undefined, 'Hello World!')
每种调用类型以自己的方式定义上下文,所以就很容易产生混淆。
此外,严格模式也会影响执行上下文。
理解this关键是要清楚的知道函数调用及其如何影响上下文。
本文主要说明函数的调用方式及如何影响 this,并且说明执行上下文的常见陷阱。
在开始之前,先知道几个术语:
调用函数正在执行创建函数体的代码,或者只是调用函数。 例如,parseInt函数调用是parseInt('15')。
函数调用:执行构成函数主体的代码:例如,parseInt函数调用是parseInt('15')。
调用的上下文:指 this 在函数体内的值。 例如,map.set('key', 'value')的调用上下文是 map。
函数的作用域:是在函数体中可访问的变量、对象和函数的集合。
2.函数调用
当一个表达式为函数接着一个(,一些用逗号分隔的参数以及一个)时,函数调用被执行,例如parseInt('18')。
函数调用表达式不能是属性方式的调用,如 obj.myFunc(),这种是创建一个方法调用。再如 [1,5].join(',')不是函数调用,而是方法调用,这种区别需要记住哈,很重要滴。
函数调用的一个简单示例:
function hello(name) { return 'Hello ' + name + '!'; } // 函数调用 const message = hello('World'); console.log(message); // => 'Hello World!'
hello('World')是函数调用: hello表达式等价于一个函数,跟在它后面的是一对括号以及'World'参数。
一个更高级的例子是IIFE(立即调用的函数表达式)
const message = (function(name) { return 'Hello ' + name + '!'; })('World'); console.log(message) // => 'Hello World!'
IIFE也是一个函数调用:第一对圆括号(function(name) {...})是一个表达式,它的计算结果是一个函数对象,后面跟着一对圆括号,圆括号的参数是“World”。
2.1. 在函数调用中的this
this 在函数调用中是一个全局对象局对象由执行环境决定。在浏览器中,this是 window 对象。
在函数调用中,执行上下文是全局对象。
再来看看下面函数中的上下文又是什么鬼:
function sum(a, b) { console.log(this === window); // => true this.myNumber = 20; // 将'myNumber'属性添加到全局对象 return a + b; } // sum() is invoked as a function // sum() 中的 `this` 是一个全局对象(window) sum(15, 16); // => 31 window.myNumber; // => 20
在调用sum(15,16)时,JS 自动将this设置为全局对象,在浏览器中该对象是window。
当this在任何函数作用域(最顶层作用域:全局执行上下文)之外使用,this 表示 window 对象
console.log(this === window); // => true this.myString = 'Hello World!'; console.log(window.myString); // => 'Hello World!' <!-- In an html file --> <script type="text/javascript"> console.log(this === window); // => true </script>
2.2 严格模式下的函数调用 this 又是什么样的
this 在严格模式下的函数调用中为 undefined严格模式是在 ECMAScript 5.1中引入的,它提供了更好的安全性和更强的错误检查。
要启用严格模式,函数头部写入use strict 即可。
启用后,严格模式会影响执行上下文,this 在常规函数调用中值为undefined。 与上述情况2.1相反,执行上下文不再是全局对象。
严格模式函数调用示例:
function multiply(a, b) { 'use strict'; // 启用严格模式 console.log(this === undefined); // => true return a * b; } multiply(2, 5); // => 10
当multiply(2,5)作为函数调用时,this是undefined。
严格模式不仅在当前作用域中有效,在内部作用域中也是有效的(对于在内部声明的所有函数):
function execute() { 'use strict'; // 开启严格模式 function concat(str1, str2) { // 严格模式仍然有效 console.log(this === undefined); // => true return str1 + str2; } // concat() 在严格模式下作为函数调用 // this in concat() is undefined concat('Hello', ' World!'); // => "Hello World!" } execute();
'use strict'被插入到执行体的顶部,在其作用域内启用严格模式。 因为函数concat是在执行的作用域中声明的,所以它继承了严格模式。
单个JS文件可能包含严格和非严格模式。 因此,对于相同的调用类型,可以在单个脚本中具有不同的上下文行为: