JavaScript 中 this 和 self 的区别

Posted

技术标签:

【中文标题】JavaScript 中 this 和 self 的区别【英文标题】:Difference between this and self in JavaScript 【发布时间】:2013-05-28 08:47:00 【问题描述】:

大家都知道javascript中的this,但是在野外也有遇到self的实例,比如here

那么,thisself 在 JavaScript 中的区别是什么?

【问题讨论】:

And regarding this... @dystroy:有一个:window.self (=== window)。虽然 OP 可能意味着一个微不足道的变量名...... @dystroy:其实我不认为他真的是这个意思,但确实在全球范围内(和浏览器环境)this === self 是真的 :-) 主观:别名 thisself 现在不是一个很好的做法,因为代码具有许多(好吧,不止一个就够糟糕了)回调嵌套级别,作为异步编程的结果。请改用更具描述性的名称。客观地说,this 这个名字本身没有任何信息,只是一个不错的名字选择,因为类定义的词法上下文限定了它。 这是一个有效且有用的问题,应该重新打开它 【参考方案1】:

除非在其他地方设置,否则self 的值是window,因为JavaScript 允许您访问window 的任何属性x,就像x,而不是window.x。所以self真的是window.self,和this不同。

window.self === window; // true

如果您使用的是在全局范围内执行且未处于严格模式的函数,则this 默认为window,因此

function foo() 
    console.log(
        window.self === window, // is self window?
        window.self === this,   // is self this?
        this === window         // is this window?
    );

foo(); // true true true

如果您在不同的上下文中使用函数,this 将引用该上下文,但 self 仍将是 window

// invoke foo with context 
foo.call(); // true false false

您可以在W3C 2006 working draft for the Window Object here 中找到定义的window.self

【讨论】:

为了完整起见,self 在无法访问窗口时的 WebWorker 上下文中很有用 (developer.mozilla.org/en-US/docs/Web/Guide/Performance/…)。使用 self 而不是 window 可以让您以可移植的方式访问全局对象。【参考方案2】:

对此略有补充,因为人们可能会在服务工作者的上下文中遇到这种情况,在这种情况下,它的含义会略有不同。

您可能会在 service worker 模块中看到这一点:

self.addEventListener('install', function(e) 
  console.log('[ServiceWorker] Install');
);

这里的self指的是WorkerGlobalScope,这是设置事件监听器的标准方法。

来自Mozilla docs:

通过使用 self,您可以引用全局范围,这种方式不仅适用于窗口上下文(self 将解析为 window.self),也适用于 worker 上下文(self 将解析为 WorkerGlobalScope.self )。

【讨论】:

谢谢!我一直在寻找这个答案:)【参考方案3】:

虽然我来晚了,但我遇到了一个例子,它也有助于进一步理解this

var myObject = 
 foo: "bar",
 func: function() 
    var self = this;
    console.log("outer func:  this.foo = " + this.foo);
    console.log("outer func:  self.foo = " + self.foo);
    (function() 
        console.log("inner func:  this.foo = " + this.foo);
        console.log("inner func:  self.foo = " + self.foo);
    ());
  
;
myObject.func();

O/P

outer func:  this.foo = bar
outer func:  self.foo = bar
inner func:  this.foo = undefined
inner func:  self.foo = bar

在 ECMA 5 之前,内部函数中的this 将引用全局窗口对象;而从 ECMA 5 开始,内部函数中的 this 将是未定义的。

【讨论】:

这总是在其上下文中定义的。未定义的是this.foo。这是一个巨大的差异,为了实现您提到的在 ECMA 5 之前存在的行为,可以使用箭头函数,或者按照您指定将 self 分配为内部函数之外的 this 并在内部使用 self 而不是 this,更简洁的方式是箭头函数.【参考方案4】:

对 ECMA 5 的引用需要澄清。

我假设它的意思是 ECMA-262 第 5 版。应该注意的是,ECMA-262(又名 ECMAScript 或更准确地说是 Javascript)是一种通用脚本语言,已在 Internet 浏览器中实现 .来自 5.1 版标准:

当控制进入包含在函数代码的执行上下文时,执行以下步骤 函数对象F,调用者提供thisArg,调用者提供argumentsList:

    如果功能码是严格码,设置ThisBinding为thisArg。 否则,如果 thisArg 为 null 或未定义,请将 ThisBinding 设置为全局对象。 否则,如果 Type(thisArg) 不是 Object,则将 ThisBinding 设置为 ToObject(thisArg)。 否则将 ThisBinding 设置为 thisArg ...(不是关于“这个”)

术语“全局对象”指的是位于作用域链顶端的任何对象。对于浏览器,这将是“窗口”对象,但这是一个实现选择(Windows 脚本宿主有一个不可见的全局对象但没有严格模式,因此不合格的引用访问它的属性并且没有全局“自我”)。此外,必须明确启用“严格模式”,否则它不会处于活动状态(标准的第 14.1 节)。因此,未定义的“this”仍将解析为“ECMA 5”中的全局​​对象(窗口),严格模式未激活。

所以问题的答案是:

“this”总是指调用函数的对象。如果函数没有被对象调用(即不是方法调用),那么“this”(传递给函数)是“未定义的”。但是,如果不使用严格模式,则将未定义的“this”设置为全局对象(上面的规则 2)。

“self”没有特殊的句法含义,它只是一个标识符。浏览器倾向于定义window.self(只是全局window对象的一个​​属性)=window.self。这会导致对“self”的非限定引用与“window”相同,除非“self”已在封闭范围内重新定义(例如通过上面的“var self = this;”。祝你好运重新定义“this”。)

所以上面例子的完整解释是:

outer func:  this.foo = bar
// "this" refers to the invoking object "myObject"
outer func:  self.foo = bar
// "self" resolves to the variable in the local scope which has been set to "this" so it is also "myObject"
inner func:  this.foo = undefined
// "this" refers to the invoking object (none) and so is replaced by the global object (strict mode must be off). "window" has no foo property so its "value" is undefined.
inner func:  self.foo = bar
// self resolves to the variable in the enclosing scope which is still "myObject"

该示例的一个有趣变体通过返回对内部函数的引用来创建闭包。

var myObject = 
 foo: "bar",
 func: function() 
    var self = this;
    console.log("outer func:  this.foo = " + this.foo);
    console.log("outer func:  self.foo = " + self.foo);
    return function() 
        console.log("inner func:  this.foo = " + this.foo);
        console.log("inner func:  self.foo = " + self.foo);
    ;
  
;
var yourObject = 
 foo: "blat",
 func: myObject.func() // function call not function object
;
console.log("----");
yourObject.func();

制作

outer func:  this.foo = bar
outer func:  self.foo = bar
----
inner func:  this.foo = blat
inner func:  self.foo = bar

请注意内部函数在被 yourObject 调用之前是如何被调用的。所以 this.foo 现在是 yourObject.foo 但 self 仍然解析为封闭范围内的变量,在返回内部函数对象时,它是(并且在结果闭包中仍然是)myObject。因此,在内部函数中,“this”是指调用内部函数的对象,而“self”是指调用外部函数以创建对内部函数的引用的对象。

总结摘要,“this”由语言标准定义,“self”由定义它的人(运行时实现者或最终程序员)定义。

【讨论】:

【参考方案5】:

在下面查找全局范围(浏览器环境)中“window”、“self”和“this”控制台输出的一些组合,以查看它所指的位置。

console.log( window ); // Window …
console.log( self );   // Window …
console.log( this );   // Window …

console.log( window.window ); // Window …
console.log( window.self );   // Window …
console.log( window.this );   // undefined  

console.log( self.self );     // Window …
console.log( self.window );   // Window …
console.log( self.this );     // undefined

console.log( this.this );     // undefined
console.log( this.window );   // Window …
console.log( this.self );     // Window …

console.log( window.window.window );    // Window …
console.log( self.self.self );          // Window …
console.log( window.self.window.self ); // Window …
console.log( self.window.self.window ); // Window …
console.log( this.this );               // undefined

【讨论】:

以上是关于JavaScript 中 this 和 self 的区别的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript的self和this使用小结

Javascript中的var self = this

JavaScript全局对象Global Object

你应该知道的 javascript面试题 --- 持续更新

javascript 之 第七章第三节(this关键字)

《javascript设计模式与开放实践》学习高阶函数的应用