前言
在绝大多数情况下,函数的调用方式决定了this
的值。this
不能在执行期间被赋值,并且在每次函数被调用时this
的值也可能会不同。
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象
ES2015 引入了箭头函数,箭头函数不提供自身的 this 绑定(this
的值将保持为闭合词法上下文的值)
为什么要学习this?如果你学过面向对象编程,那你肯定知道干什么用的,毕竟这是js中必须要掌握的东西。
■ this
例子1:
function a(){
var user = "追梦子";
console.log(this.user); //undefined
console.log(this); //Window
}
a();
按照我们上面说的this最终指向的是调用它的对象,这里的函数a实际是被Window对象所点出来的,下面的代码就可以证明。
function a(){
var user = "追梦子";
console.log(this.user); //undefined
console.log(this); //Window
}
window.a();
和上面代码一样吧,其实alert也是window的一个属性,也是window点出来的。
例子2:
var o = {
user:"追梦子",
fn:function(){
console.log(this.user); //this指向o
}
}
o.fn();//this指向o
//追梦子
这里的this指向的是对象o,因为你调用这个fn是通过o.fn()执行的,那自然指向就是对象o,这里再次强调一点,this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,一定要搞清楚这个。
其实例子1和例子2说的并不够准确,下面这个例子就可以推翻上面的理论。
如果要彻底的搞懂this必须看接下来的几个例子
例子3:
var o = {
user:"追梦子",
fn:function(){
console.log(this.user); //this指向?
}
}
window.o.fn();//this指向?
//追梦子
这段代码和上面的那段代码几乎是一样的,但是这里的this为什么不是指向window,如果按照上面的理论,最终this指向的是调用它的对象,这里先说个而外话,window是js中的全局对象,我们创建的变量实际上是给window添加属性,所以这里可以用window点o对象。
这里先不解释为什么上面的那段代码this为什么没有指向window,我们再来看一段代码。
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
o.b.fn();
这里同样也是对象o点出来的,但是同样this并没有执行它,那你肯定会说我一开始说的那些不就都是错误的吗?其实也不是,只是一开始说的不准确,接下来我将补充一句话,我相信你就可以彻底的理解this的指向的问题。
- 情况1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window
function a(){
var user = "追梦子";
console.log(this); //Window
}
a();
- 情况2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。
var o = {
user:"追梦子",
fn:function(){
console.log(this.user); //this指向o
}
}
o.fn();//this指向o
//追梦子
- 情况3:如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
o.b.fn();
例子3可以证明,如果不相信,那么接下来我们继续看几个例子
var o = {
a:10,
b:{
// a:12,
fn:function(){
console.log(this.a); //undefined
}
}
}
o.b.fn();
尽管对象b中没有属性a,这个this指向的也是对象b,因为this只会指向它的上一级对象,不管这个对象中有没有this要的东西。
还有一种比较特殊的情况,例子4:
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
这里this指向的是window,是不是有些蒙了?其实是因为你没有理解一句话,这句话同样至关重要。
this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子4中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window,这和例子3是不一样的,例子3是直接执行了fn。
this讲来讲去其实就是那么一回事,只不过在不同的情况下指向的会有些不同,上面的总结每个地方都有些小错误,也不能说是错误,而是在不同环境下情况就会有不同,所以我也没有办法一次解释清楚,只能你慢慢地的去体会。
构造函数版this:
function Fn(){
this.user = "追梦子";
}
var a = new Fn();
console.log(a.user); //追梦子
这里之所以对象a可以点出函数Fn里面的user是因为new关键字可以改变this的指向,将这个this指向对象a,为什么我说a是对象,因为用了new关键字就是创建一个对象实例,理解这句话可以想想我们的例子3,我们这里用变量a创建了一个Fn的实例(相当于复制了一份Fn到对象a里面),此时仅仅只是创建,并没有执行,而调用这个函数Fn的是对象a,那么this指向的自然是对象a,那么为什么对象a中会有user,因为你已经复制了一份Fn函数到对象a中,用了new关键字就等同于复制了一份。
function Fn(){
this.user = "追梦子";
}
var a = new Fn();
/*相当于复制了一份Fn到对象a里面
a{
Fn{
this.user = "追梦子";
}
}
*/
console.log(a.user); //追梦子
除了上面的这些以外,我们还可以自行改变this的指向,关于自行改变this的指向请看JavaScript中call,apply,bind方法的总结这篇文章,详细的说明了我们如何手动更改this的指向。
更新一个小问题当this碰到return时
function fn()
{
this.user = '追梦子';
return {};
}
var a = new fn();
console.log(a.user); //undefined
再看一个
function fn()
{
this.user = '追梦子';
return function(){};
}
var a = new fn();
console.log(a.user); //undefined
再来
function fn()
{
this.user = '追梦子';
return 1;
}
var a = new fn;
console.log(a.user); //追梦子
_____
function fn()
{
this.user = '追梦子';
return undefined;
}
var a = new fn;
console.log(a.user); //追梦子
这是什么意思呢?
如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象或者不写则那么this还是指向函数的实例。
return {}; return function(){};返回的是一个对象,this就指向这个对象,但是这个对象里并没有user属性,所以只能打印出undefined
return 1; return undefined;返回的是不是一个对象,this还是指向函数的实例,又因为实例时完全复制的原型fn,里面存有user属性,所以可以打印出user的值
function fn()
{
this.user = '追梦子';
return undefined;
}
var a = new fn;
console.log(a); //fn {user: "追梦子"}
还有一点就是虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。
function fn()
{
this.user = '追梦子';
return null;
}
var a = new fn;
console.log(a.user); //追梦子
知识点补充:
- 在严格版中的默认的this不再是window,而是undefined。
- new操作符会改变函数this的指向问题,虽然我们上面讲解过了,但是并没有深入的讨论这个问题,网上也很少说,所以在这里有必要说一下。
function fn(){
this.num = 1;
}
var a = new fn();
console.log(a.num); //1
为什么this会指向a?
- 首先new关键字会创建一个空的对象
- 然后会自动调用一个函数apply方法
- 将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代
注意: 当你new一个空对象的时候,js内部的实现并不一定是用的apply方法来改变this指向的,这里我只是打个比方而已.
if (this === 动态的可改变的) return true;
常用
代码案例:
const test = {
prop: 42,
func: function() {
return this.prop; //这里的this就是test
},
};
console.log(test.func());//这里的this就是test
// expected output: 42
全局上下文
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this
都指向全局对象
// 在浏览器中, window 对象同时也是全局对象:
console.log(this === window); // true
a = 37;
console.log(window.a); // 37
this.b = "MDN";
console.log(window.b) // "MDN"
console.log(b) // "MDN"
函数上下文
在函数内部,this
的值取决于函数被调用的方式
因为下面的代码不在严格模式下,且 this
的值不是由该调用设置的,所以 this
的值默认指向全局对象,浏览器中就是 window
function f1(){
return this;
}
//在浏览器中:
f1() === window; //在浏览器中,全局对象是window
//在Node中:
f1() === globalThis;
然而,在严格模式下,如果进入执行环境时没有设置 this
的值,this
会保持为 undefined
,如下:
function f2(){
"use strict"; // 这里是严格模式
return this;
}
f2() === undefined; // true
函数上下文中的 this
var obj = {a: 'Custom'};
var a = 'Global';
function whatsThis() {
return this.a;
}
whatsThis(); // 'Global'
whatsThis.call(obj); // 'Custom'
whatsThis.apply(obj); // 'Custom'
this 和对象转换
function add(c, d) {
return this.a + this.b + c + d;
}
var o = {a: 1, b: 3};
// 第一个参数是用作“this”的对象
// 其余参数用作函数的参数
add.call(o, 5, 7); // 16
// 第一个参数是用作“this”的对象
// 第二个参数是一个数组,数组中的两个成员用作函数参数
add.apply(o, [10, 20]); // 34
在非严格模式下使用 call
和 apply
时,如果用作 this
的值不是对象,则会被尝试转换为对象。null
和 undefined
被转换为全局对象。原始值如 7
或 'foo'
会使用相应构造函数转换为对象。因此 7
会被转换为 new Number(7)
生成的对象,字符串 'foo'
会转换为 new String('foo')
生成的对象。
function bar() {
console.log(Object.prototype.toString.call(this));
}
bar.call(7); // [object Number]
bar.call('foo'); // [object String]
bar.call(undefined); // [object global]
作为对象的方法
当函数作为对象里的方法被调用时,this
被设置为调用该函数的对象。
下面的例子中,当 o.f()
被调用时,函数内的 this
将绑定到 o
对象。
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); // 37
请注意,这样的行为完全不会受函数定义方式或位置的影响。在前面的例子中,我们在定义对象o
的同时,将其中的函数定义为成员 f
。但是,我们也可以先定义函数,然后再将其附属到o.f
。这样做的结果是一样的:
var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // 37
这表明函数是从 o
的 f
成员调用的才是重点。
同样,this
的绑定只受最接近的成员引用的影响。在下面的这个例子中,我们把一个方法g
当作对象o.b
的函数调用。在这次执行期间,函数中的this
将指向o.b
。事实证明,这与他是对象 o
的成员没有多大关系,最近的引用才是最重要的。
o.b = {g: independent, prop: 42};
console.log(o.b.g()); // 42
原型链中的 this
对于在对象原型链上某处定义的方法,同样的概念也适用。如果该方法存在于一个对象的原型链上,那么 this
指向的是调用这个方法的对象,就像该方法就在这个对象上一样。
var o = {
f: function() {
return this.a + this.b;
}
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
在这个例子中,对象 p
没有属于它自己的 f
属性,它的 f
属性继承自它的原型。虽然最终是在 o
中找到 f
属性的,这并没有关系;查找过程首先从 p.f
的引用开始,所以函数中的 this
指向p
。也就是说,因为f
是作为p
的方法调用的,所以它的this
指向了p
。这是 JavaScript 的原型继承中的一个有趣的特性。
作为构造函数
当一个函数用作构造函数时(使用new关键字),它的this
被绑定到正在构造的新对象。
虽然构造函数返回的默认值是 this
所指的那个对象,但它仍可以手动返回其他的对象(如果返回值不是一个对象,则返回 this
对象)。
/*
* 构造函数这样工作:
*
* function MyConstructor(){
* // 函数实体写在这里
* // 根据需要在this上创建属性,然后赋值给它们,比如:
* this.fum = "nom";
* // 等等...
*
* // 如果函数具有返回对象的return语句,
* // 则该对象将是 new 表达式的结果。
* // 否则,表达式的结果是当前绑定到 this 的对象。
* //(即通常看到的常见情况)。
* }
*/
function C(){
this.a = 37;
}
var o = new C();
console.log(o.a); // logs 37
function C2(){
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a); // logs 38
在刚刚的例子中(C2
),因为在调用构造函数的过程中,手动的设置了返回对象,与this
绑定的默认对象被丢弃了。(这基本上使得语句 “this.a = 37;
”成了“僵尸”代码,实际上并不是真正的“僵尸”,这条语句执行了,但是对于外部没有任何影响,因此完全可以忽略它)。
<!DOCTYPE html>
<html>
<body>
<h1>JavaScript <b>this</b> 关键词</h1>
<p>在本例中,<b>this</b> 代表 <b>person</b> 对象。</p>
<p>因为 person 对象“拥有” fullName 方法。</p>
<p id="demo"></p>
<script>
// 创建对象:
var person = {
firstName: "Bill",
lastName : "Gates",
id : 678,
fullName : function() {
return this.firstName + " " + this.lastName;
}
};
// 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.fullName();
</script>
</body>
</html>
//
Javascript this 关键词
在本例中,this 代表 person 对象。
因为 person 对象“拥有” fullName 方法。
Bill Gates
this 是什么?
JavaScript this 关键词指的是它所属的对象。
它拥有不同的值,具体取决于它的使用位置:
- 在方法中,this 指的是所有者对象。
- 单独的情况下,this 指的是全局对象。
- 在函数中,this 指的是全局对象。
- 在函数中,严格模式下,this 是 undefined。
- 在事件中,this 指的是接收事件的元素。
像 call() 和 apply() 这样的方法可以将 this 引用到任何对象。
方法中的 this
在对象方法中,this 指的是此方法的“拥有者”。
在本页最上面的例子中,this 指的是 person 对象。
person 对象是 fullName 方法的拥有者。
<!DOCTYPE html>
<html>
<body>
<h1>JavaScript <b>this</b> 关键词</h1>
<p>在本例中,<b>this</b> 代表 <b>person</b> 对象。</p>
<p>因为 person 对象“拥有” fullName 方法。</p>
<p id="demo"></p>
<script>
// 创建对象:
var person = {
firstName: "Bill",
lastName : "Gates",
id : 678,
fullName : function() {
return this.firstName + " " + this.lastName;
}
};
// 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.fullName();
</script>
</body>
</html>
//
Javascript this 关键词
在本例中,this 代表 person 对象。
因为 person 对象“拥有” fullName 方法。
Bill Gates
单独的 this
在单独使用时,拥有者是全局对象,因此 this 指的是全局对象。
在浏览器窗口中,全局对象是 [object Window]:
实例
<!DOCTYPE html>
<html>
<body>
<h1>JavaScript <b>this</b> 关键词</h1>
<p>在本例中,<b>this</b> 引用 window 对象:</p>
<p id="demo"></p>
<script>
var x = this;
document.getElementById("demo").innerHTML = x;
</script>
</body>
</html>
//
Javascript this 关键词
在本例中,this 引用 window 对象:
[object Window]
在严格模式中,如果单独使用,那么this指的是全局对象[object Window]:
实例
<!DOCTYPE html>
<html>
<body>
<h1>JavaScript <b>this</b> 关键词</h1>
<p>在本例中,<b>this</b> 引用 window 对象:</p>
<p id="demo"></p>
<script>
"use strict";
var x = this;
document.getElementById("demo").innerHTML = x;
</script>
</body>
</html>
//
Javascript this 关键词
在本例中,this 引用 window 对象:
[object Window]
函数中的 this(默认)
在 JavaScript 函数中,函数的拥有者默认绑定 this。
因此,在函数中,this 指的是全局对象 [object Window]。
实例
<!DOCTYPE html>
<html>
<body>
<h1>JavaScript <b>this</b> 关键词</h1>
<p>在本例中,<b>this</b> 代表“拥有” myFunction 的对象:</p>
<p id="demo"></p>
<script>
document.getElementById("demo").innerHTML = myFunction();
function myFunction() {
return this;
}
</script>
</body>
</html>
//
Javascript this 关键词
在本例中,this 代表“拥有” myFunction 的对象:
[object Window]
函数中的 this(严格模式)
JavaScript 严格模式不允许默认绑定。
因此,在函数中使用时,在严格模式下,this 是未定义的(undefined)。
实例
<!DOCTYPE html>
<html>
<body>
<h1>JavaScript <b>this</b> 关键词</h1>
<p>在函数中,默认地,<b>this</b> 引用全局对象。</p>
<p>在严格模式中,<b>this</b> 是 <b>undefined</b>,因为严格模式不允许默认绑定:</p>
<p id="demo"></p>
<script>
"use strict";
document.getElementById("demo").innerHTML = myFunction();
function myFunction() {
return this;
}
</script>
</body>
</html>
//
Javascript this 关键词
在函数中,默认地,this 引用全局对象。
在严格模式中,this 是 undefined,因为严格模式不允许默认绑定:
undefined
事件处理程序中的 this
在 HTML 事件处理程序中,this 指的是接收此事件的 HTML 元素:
实例
<!DOCTYPE html>
<html>
<body>
<h1>JavaScript <b>this</b> 关键词</h1>
<button onclick="this.style.display='none'">单击来删除我!</button>
</body>
</html>
//
Javascript this 关键词
单击来删除我!
对象方法绑定
在此例中,this 是 person 对象(person 对象是该函数的“拥有者”):
实例
<!DOCTYPE html>
<html>
<body>
<h1>JavaScript <b>this</b> 关键词</h1>
<p>在本例中,<b>this</b> 代表“拥有” fullName 方法的 person 对象。</p>
<p id="demo"></p>
<script>
// 创建对象:
var person = {
firstName : "Bill",
lastName : "Gates",
id : 678,
myFunction : function() {
return this;
}
};
// 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.myFunction();
</script>
</body>
</html>
//
Javascript this 关键词
在本例中,this 代表“拥有” fullName 方法的 person 对象。
[object Object]
实例
<!DOCTYPE html>
<html>
<body>
<h1>JavaScript <b>this</b> 关键词</h1>
<p>在本例中,<b>this</b> 代表 <b>person</b> 对象。</p>
<p>因为 person 对象“拥有” fullName 方法。</p>
<p id="demo"></p>
<script>
// 创建对象:
var person = {
firstName: "Bill",
lastName : "Gates",
id : 678,
fullName : function() {
return this.firstName + " " + this.lastName;
}
};
// 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.fullName();
</script>
</body>
</html>
//
Javascript this 关键词
在本例中,this 代表 person 对象。
因为 person 对象“拥有” fullName 方法。
Bill Gates
换句话说,this.firstName意味着this(person)对象的firstName属性。
显式函数绑定
call() 和 apply() 方法是预定义的 JavaScript 方法。
它们都可以用于将另一个对象作为参数调用对象方法。
您可以在本教程后面阅读有关 call() 和 apply() 的更多内容。
在下面的例子中,当使用 person2 作为参数调用 person1.fullName 时,this 将引用 person2,即使它是 person1 的方法:
实例
<!DOCTYPE html>
<html>
<body>
<h1>JavaScript <b>this</b> 关键词</h1>
<p>在本例中,<strong>this</strong> 引用 person2,即使它是 person1 的方法:</p>
<p id="demo"></p>
<script>
var person1 = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person2 = {
firstName:"Bill",
lastName: "Gates",
}
var x = person1.fullName.call(person2);
document.getElementById("demo").innerHTML = x;
</script>
</body>
</html>
//
Javascript this 关键词
在本例中,this 引用 person2,即使它是 person1 的方法:
Bill Gates
学懂 JavaScript 语言,一个标志就是理解下面两种写法,可能有不一样的结果。
var obj = {
foo: function () {}
};
var foo = obj.foo;
// 写法一
obj.foo()
// 写法二
foo()
上面代码中,虽然obj.foo
和foo
指向同一个函数,但是执行结果可能不一样。请看下面的例子。
var obj = {
foo: function () { console.log(this.bar) },
bar: 1
};
var foo = obj.foo;
var bar = 2;
obj.foo() // 1
foo() // 2
这种差异的原因,就在于函数体内部使用了this
关键字。很多教科书会告诉你,this
指的是函数运行时所在的环境。对于obj.foo()
来说,foo
运行在obj
环境,所以this
指向obj
;对于foo()
来说,foo
运行在全局环境,所以this
指向全局环境。所以,两者的运行结果不一样。
这种解释没错,但是教科书往往不告诉你,为什么会这样?也就是说,函数的运行环境到底是怎么决定的?举例来说,为什么obj.foo()
就是在obj
环境执行,而一旦var foo = obj.foo
,foo()
就变成在全局环境执行?
本文就来解释 JavaScript 这样处理的原理。理解了这一点,你就会彻底理解this
的作用。
二、内存的数据结构
JavaScript 语言之所以有this
的设计,跟内存里面的数据结构有关系。
var obj = { foo: 5 };
上面的代码将一个对象赋值给变量obj
。JavaScript 引擎会先在内存里面,生成一个对象{ foo: 5 }
,然后把这个对象的内存地址赋值给变量obj
。
也就是说,变量obj
是一个地址(reference)。后面如果要读取obj.foo
,引擎先从obj
拿到内存地址,然后再从该地址读出原始的对象,返回它的foo
属性。
原始的对象以字典结构保存,每一个属性名都对应一个属性描述对象。举例来说,上面例子的foo
属性,实际上是以下面的形式保存的。
{
foo: {
[[value]]: 5
[[writable]]: true
[[enumerable]]: true
[[configurable]]: true
}
}
注意,foo
属性的值保存在属性描述对象的value
属性里面。
三、函数
这样的结构是很清晰的,问题在于属性的值可能是一个函数。
var obj = { foo: function () {} };
这时,引擎会将函数单独保存在内存中,然后再将函数的地址赋值给foo
属性的value
属性。
{
foo: {
[[value]]: 函数的地址
...
}
}
由于函数是一个单独的值,所以它可以在不同的环境(上下文)执行。
var f = function () {};
var obj = { f: f };
// 单独执行
f()
// obj 环境执行
obj.f()
四、环境变量
JavaScript 允许在函数体内部,引用当前环境的其他变量。
var f = function () {
console.log(x);
};
上面代码中,函数体里面使用了变量x
。该变量由运行环境提供。
现在问题就来了,由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this
就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。
var f = function () {
console.log(this.x);
}
上面代码中,函数体里面的this.x
就是指当前运行环境的x
。
var f = function () {
console.log(this.x);
}
var x = 1;
var obj = {
f: f,
x: 2,
};
// 单独执行
f() // 1
// obj 环境执行
obj.f() // 2
上面代码中,函数f
在全局环境执行,this.x
指向全局环境的x
。
在obj
环境执行,this.x
指向obj.x
。
回到本文开头提出的问题,obj.foo()
是通过obj
找到foo
,所以就是在obj
环境执行。一旦var foo = obj.foo
,变量foo
就直接指向函数本身,所以foo()
就变成在全局环境执行。
核心原始
首先,让我们看一下核心函数调用原语,即Function的call
方法[1]。调用方法相对简单。
argList
从参数1到结尾创建参数列表()- 第一个参数是
thisValue
- 调用
this
set为thisValue
和argList
作为其参数列表的函数
例如:
function hello(thing) {
console.log(this + " says hello " + thing);
}
hello.call("Yehuda", "world") //=> Yehuda says hello world
正如你所看到的,我们调用hello
与方法this
设置为"Yehuda"
和一个参数"world"
。这是JavaScript函数调用的核心原语。您可以将所有其他函数调用视为对该原语的替代。(“ desugar”是采用一种方便的语法,并以更基本的核心原语进行描述)。
[1]在ES5规范中,该call
方法是根据另一个更底层的原语进行描述的,但是它是该原语之上非常薄的包装,因此在此我进行了一些简化。有关更多信息,请参见本文结尾。
简单函数调用
显然,一直调用函数call
会很烦人。JavaScript允许我们使用parens语法(hello("world")
。直接调用函数。
function hello(thing) {
console.log("Hello " + thing);
}
// this:
hello("world")
// desugars to:
hello.call(window, "world");
仅当使用严格模式 [2] 时,此行为在ECMAScript 5中已更改:
// this:
hello("world")
// desugars to:
hello.call(undefined, "world");
简短的版本是:的函数调用fn(...args)
与相同fn.call(window [ES5-strict: undefined], ...args)
。
请注意,对于内联声明的函数也是如此:(function() {})()
与相同(function() {}).call(window [ES5-strict: undefined)
。
[2]实际上,我撒了点谎。ECMAScript 5规范说undefined
(几乎)总是通过,但是thisValue
在非严格模式下,被调用的函数应将其更改为全局对象。这允许严格模式调用者避免破坏现有的非严格模式库。
会员职能
调用方法的下一个非常常见的方法是作为对象(person.hello()
)的成员。在这种情况下,调用将终止:
var person = {
name: "Brendan Eich",
hello: function(thing) {
console.log(this + " says hello " + thing);
}
}
// this:
person.hello("world")
// desugars to this:
person.hello.call(person, "world");
请注意,该hello
方法如何以这种形式附加到对象并不重要。请记住,我们之前将其定义hello
为独立函数。让我们看看如果我们动态地将对象附加到对象上会发生什么:
function hello(thing) {
console.log(this + " says hello " + thing);
}
person = { name: "Brendan Eich" }
person.hello = hello;
person.hello("world") // still desugars to person.hello.call(person, "world")
hello("world") // "[object DOMWindow]world"
注意,该函数没有其“ this”的持久概念。它总是在调用时根据其调用方调用的方式进行设置。
https://www.google.com/search?q=this+%E6%8C%87%E4%B8%8A%E4%B8%8B%E6%96%87%E4%BD%9C%E7%94%A8&oq=this+%E6%8C%87%E4%B8%8A%E4%B8%8B%E6%96%87%E4%BD%9C%E7%94%A8&aqs=chrome..69i57.20087j0j8&sourceid=chrome&ie=UTF-8www.google.com https://blog.fundebug.com/2019/08/15/what-is-javascript-this/blog.fundebug.com 4、对作用于上下文和this的理解_郭小刀-CSDN博客blog.csdn.net