【问题标题】:Which is safer - using a self or this?哪个更安全 - 使用 self 还是 this?
【发布时间】:2014-02-11 03:07:31
【问题描述】:

使用关键字“this”创建新储物柜是否安全?我担心“this”可能会在运行时指向其他东西。 我是 JavaScript 和闭包的新手。

var Employee = function() {
    this.initialize.apply(this, arguments);
};

_.extend(Employee.prototype, {
    initialize : function(opts) {

        this._locker = new Locker({
            employee : this
        });

        // OR

        var self = this;
        this._locker = new Locker({
            employee : self
        });
    } 

});

【问题讨论】:

  • this 与闭包无关。闭包由代码的编写方式形成,this 由函数的调用方式或使用 bind 设置的方式设置。
  • 我认为您应该先阅读MDN documentation 以了解有关this 的更多信息。然后你会希望看到是否使用this 的问题甚至不适用于这种情况。

标签: javascript closures this


【解决方案1】:

特别看这段代码:

this._locker = new Locker({
    employee : this
});

假设this已经指向了正确的对象,上面没有引入新的作用域;这将与写作相同:

var options = {
    employee : this
};
this._locker = new Locker(options);

【讨论】:

    【解决方案2】:

    在这种情况下,您不需要使用self

    当有人希望将this 的值作为闭包传递到不同的范围时,您会看到self

    var self = this;
    
    var myFunc = function() {
    
        // do something with self (aka this)
    };
    

    在上面的示例中,myFunc 中的 this 在调用函数之前不会被知道 - 谷歌“动态与静态范围” - 它不会是函数外部的“this” .在我的示例中,this 被传递为 self

    注意:您不必使用self 任何其他变量名都可以。

    在您的示例中,您并没有尝试将 this 传递到不同的范围,所以应该没问题。

    【讨论】:

    • 传递 this 很好,它引用它就是问题所在。 this 总是在当前执行上下文中解析,它从未在作用域链上解析,因此在不同的执行上下文中需要它的值时需要传递它。
    • this 不能成为闭包。您必须先将其分配给另一个 var。您可以将此作为参数传递给函数,但这是另一回事。
    【解决方案3】:

    两个 sn-ps 作用相同

    this 的值由如何函数被调用决定,所以你是对的,this 可能在运行时指向其他东西。

    但是,一旦调用了initialize,就已经设置了该调用的this 的值。所以:

        var self = this;
        this._locker = new Locker({
            employee : self
        });
    

    只需添加一个中间步骤,将this 分配给一个临时变量(参见Jack 的答案)

    【讨论】:

    • 有关如何确定值的更多信息,您应该阅读this(正如 Felix Kling 在 cmets 中指出的那样)
    【解决方案4】:

    您更安全的选择是使用“this”,因为您正在使用 apply 并传递“this”。 Apply 将强制“this”关键字成为您传递给函数的 thisArg。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

    “self”在初始化的早期就设置为Window对象,但我认为它之后不会改变,除非你专门改变它。

    【讨论】:

    • 回复"self" is set to the Window object earlier in the initialization。如果您指的是OP,那么没有。当 initialize 被调用时,self 被设置为 this 的值,并且由于它的 this 被设置为实例在调用中,它将引用实例,而不是 window(或更一般地说,全局对象)。
    • 感谢 Rob 的澄清!
    【解决方案5】:

    使用关键字“this”创建新储物柜是否安全?

    是的。

    > var Employee = function() {
    >     this.initialize.apply(this, arguments);
    > };
    

    在使用 new 调用的函数中(即作为构造函数调用),this 将始终指向新实例。使用 apply 意味着 arguments 不是作为对象传递,而是作为值序列传递。所以我认为你应该这样做:

    function Employee () {
        this.initialize(arguments);
    }
    

    请注意,函数声明比函数表达式的代码更少且更可靠。

    > _.extend(Employee.prototype, {
    >     initialize : function(opts) {
    

    由于您使用 apply 调用它并使用 arguments 作为参数对象,因此参数是按值单独传递的。所以 opts 将是最初传递给 Employee 构造函数的参数的第一个值,其他参数将作为这个新函数的 参数 的成员可用对象。

    > 
    >         this._locker = new Locker({
    >             employee : this
    >         });
    >     }
    

    this 的值是在调用函数时设置的(或通过bind)。在这种情况下,initialize 旨在作为实例的方法调用,因此 this 将引用该实例。它可以以其他方式调用,以便 this 引用其他对象(或在严格模式下的任何值),但以下内容对此没有影响。

    这段代码对传递给Locker的值没有任何区别:

    >     var self = this;
    >     this._locker = new Locker({
    >         employee : self
    >     });
    

    您似乎试图避免关闭,但这里没有要避免的关闭。闭包不是由函数调用引起的,而是由函数返回在其中创建的其他函数(通过声明或表达式)引起的。这些函数在完成后仍然可以访问外部函数的词法环境,例如

    var foo = (function() {
      var bar = 'bar';
      return function(){ return bar;};
    }());
    
    foo(); // bar
    

    函数 foo 对在外部函数中声明的变量 bar 有一个闭包。没有其他函数可以访问 bar 来读取或设置它的值,它只对 foo 可用(这是在 javascript 中模拟私有成员的方式)。

    你遇到麻烦的地方是闭包中保存的变量的值在闭包形成后意外更改。这在原始代码中不会发生。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-24
      • 1970-01-01
      • 2017-07-23
      • 1970-01-01
      • 2015-06-22
      • 2012-01-08
      • 2011-10-20
      相关资源
      最近更新 更多