JavaScript 中 this 和 self 的区别

每个人都知道 javascript 中的 this,但是也有在野外遇到的 self实例,比如 给你

那么,在 JavaScript 中 thisself有什么不同呢?

126237 次浏览

除非在其他地方设置,否则 self的值为 window,因为 JavaScript允许您以简单的 x而不是 window.x的形式访问 window的任何属性 x。因此,self实际上是 window0,这与 window1不同。

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工作草案 < em > Window Object < strong > here 中找到定义的 window.self

虽然我在这里迟到了,但我遇到了一个例子,也可以有助于进一步了解 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将是未定义的。

由于人们在服务工作者的语境中可能会遇到这种情况,因此这里稍微增加了一点内容,在这种情况下,它的意思稍微有些不同。

您可能会在服务工作者模块中看到这一点:

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

在这里,自我引用 WorkerGlobalScope,这是设置事件侦听器的标准方法。

来自 Mozilla 文档:

通过使用 self,您可以以一种不仅在窗口上下文中(self 将解析为 window.self)而且在 worker 上下文中(self 将解析为 WorkerGlobalScope.self)的方式引用全局作用域。

ECMA 5的参考需要澄清。

我猜是指 ECMA-262第5版。值得注意的是,ECMA-262(简称 ECMAScript,或者更准确地说 Javascript)是一个通用脚本语言,在互联网浏览器中是 实施。来自5.1版标准:

中包含的函数代码的执行上下文时执行以下步骤 函数对象 F,调用方提供 this Arg,调用方提供 argumentsList:

  1. 如果函数代码是严格的代码,则将 ThisBinding 设置为 thisArg。
  2. 否则,如果 thisArg 为 null 或未定义,则将 ThisBinding 设置为全局对象。
  3. 否则,如果 Type (thisArg)不是 Object,则将 ThisBinding 设置为 ToObject (thisArg)。
  4. 否则将 ThisBinding 设置为 thisArg
  5. ... (不是关于“这个”)

术语“全局对象”指的是作用域链顶端的任何对象。对于浏览器来说,这将是一个“窗口”对象,但这是一个实现选择(Windows Script Host 有一个不可见的全局对象,但没有严格的模式,所以不合格的引用访问其属性,没有全局“自我”)。此外,“严格模式”必须显式启用,否则它不是活动的(标准的第14.1节)。因此,未定义的“ this”仍然会解析为“ ECMA5”中的全局对象(窗口) ,严格模式不激活。

所以问题的答案是:

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

“自我”没有特殊的句法意义,只是一个标识符。浏览器倾向于定义 window.self (只是全局 window 对象的一个属性) = window。这导致对“ self”的不限定引用与“ window”相同,除非“ self”已经在一个封闭范围内重新定义(如上面的“ var self = 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”由定义它的人(运行时实现者或最终程序员)定义。

在全局范围(浏览器环境)中找到“窗口”、“自我”和“此”控制台输出的一些组合,以查看它所指向的位置。

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