这与JavaScript中的self之间的区别



每个人都知道javascript中的this,但也有在野外遇到的self实例,例如这里的

那么,JavaScript中的thisself有什么区别呢?

除非在其他地方设置,否则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工作草案中找到Window对象定义的window.self

这是一个轻微的补充,因为人们可能会在服务人员的环境中遇到这种情况,在这种情况下,这意味着略有不同。

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

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

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

来自Mozilla文档:

通过使用self,您可以引用全局作用域,这种方式不仅在窗口上下文中有效(self将解析为window.self(,而且在工作者上下文中也有效(sell将解析为WorkerGlobalScope.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

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

对ECMA 5的引用需要澄清。

我想这意味着ECMA-262版本5。需要注意的是,ECMA-262(又称ECMAScript,或者不太准确地说,Javascript(是一种通用脚本语言,已在Internet浏览器中实现。来自5.1版标准:

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

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

术语"全局对象"指的是范围链顶部的任何对象。对于浏览器,这将是"窗口"对象,但这是一种实现选择(Windows脚本主机有一个不可见的全局对象,但没有严格模式,因此不合格的引用访问其属性,并且没有全局"self"(。此外,必须明确启用"严格模式",否则它将不活动(标准第14.1节(。因此,在严格模式未激活的情况下,未定义的"this"仍将解析为"ECMA 5"中的全局对象(窗口(。

所以这个问题的答案是:

"this"总是指调用函数的对象。如果函数不是由对象调用的(即不是方法调用(,则"this"(传递给函数(是"未定义的"。但是,如果不使用严格模式,则会将未定义的"this"设置为全局对象(上面的规则2(。

self没有特殊的句法意义,它只是一个标识符。浏览器倾向于定义window.self(只是全局窗口对象的一个属性(=window。这导致对"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

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

为了总结总结,"this"由语言标准定义,"self"由定义它的人(运行时实现者或最终程序员(定义。

在下面找到全局范围(浏览器环境(中"window"、"self"one_answers"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

最新更新