this第一奥义:
- 对于许多刚刚接触前端的学者来说,this时常出现在编程中。虽然知道this用途的强大,但对于提示的作用并不是过于了解,而今天就让Damon跟大家说说this在JS中能够扮演的角色。
前提先知:
-
对于在开始讲解this之间我们需要知道,从java或者是从PHP等标准语言对于this的看法来说。大多数情况下,虽说this能够使用的场景有许多,但是this作为表示类方法中的当前对象的实例,是无法使用在方法之外进行使用。
-
函数调用:执行构成函数主体的代码:例如,parseInt函数调用是’’‘parseInt(‘15’)’’’。
-
调用的上下文:指 this 在函数体内的值。例如,’’'map.set(‘key’, ‘value’)的调用上下文是 map。
-
函数的作用域:是指在函数体中可访问的变量、对象和函数的集合。
JS调用方式:
- 在就是中使用this的情况就与前文所的有所不同,this在这更多是表示函数当前执行上下文,而在js调用函数时常是用一下这些方法:
- 函数的调用:
alert('Hello World!')
- 方法的调用:
console.log('Hello World!')
- 方法的调用:```console.log(‘Hello World!’) ``````
- 隐式调用: alert.call(undefined, ‘Hello World!’) ```
- 函数的调用:
- 对于以上的调用方式,每种调用类型以自己的方式定义上下文,所以在日常编程中也是容易出现混淆的情况。另外一点就是在严格模式中,调用函数会出现影响上下文的情况。
函数调用角色
-
首先,在我们日常编辑的时候,当一个表达式为函数接着一个(,一些用逗号分隔的参数以及一个)时,函数调用被执行。在这里我们从日常的比如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’参数。
在函数调用中的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>
-
严格模式下的函数调用 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文件可能包含严格和非严格模式。因此,对于相同的调用类型,可以在单个脚本中具有不同的上下文行为:
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
方法调用中 this 扮演什么角色?
-
在方法调用中,this是拥有这个方法的对象。当调用对象上的方法时,this就变成了对象本身。
-在这里我们来看个案例:首先创建一个对象,该对象有一个递增数字的方法const 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
-
调用calc.increment()使increment函数的上下文成为calc对象。所以使用this.num来增加num属性是有效的。再来看看另一个例子。JS对象从原型继承一个方法,当在对象上调用继承的方法时,调用的上下文仍然是对象本身
const myDog = Object.create({ sayName: function() { console.log(this === myDog); // => true return this.name; } }); myDog.name = 'Milo'; // 方法调用 this 指向 myDog myDog.sayName(); // => 'Milo'
-
Object.create()创建一个新对象myDog,并根据第一个参数设置其原型。myDog对象继承sayName方法。执行myDog. sayname()时,myDog是调用的上下文。在EC6 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'
构造函数中的 this所扮演的角色
-
在构造函数调用中 this 指向新创建的对象。构造函数调用的上下文是新创建的对象。它利用构造函数的参数初始化新的对象,设定属性的初始值,添加事件处理函数等等。
-
来看看下面示例中的上下文
function Foo () {
console.log(this instanceof Foo); // => true
this.property = ‘Default Value’;
}
// Constructor invocation
const fooInstance = new Foo();
fooInstance.property; // => ‘Default Value’ -
new Foo() 正在进行构造函数调用,其中上下文是fooInstance。在Foo内部初始化对象:this.property被赋值为默认值。同样的情况在用class语法(从ES6起)时也会发生,唯一的区别是初始化在constructor方法中进行:
class Bar { constructor() { console.log(this instanceof Bar); // => true this.property = 'Default Value'; } } // Constructor invocation const barInstance = new Bar(); barInstance.property; // => 'Default Value'