代码之家  ›  专栏  ›  技术社区  ›  FK82

javascript“this”操作符如何处理作用域?

  •  2
  • FK82  · 技术社区  · 14 年前

    编辑: 我不得不道歉,我发布的代码中实际上不存在我发布的问题,因为我过于简单化了。我稍后再寄点东西。

    删除也可以,但是现在答案太多了,所以我不能自己做。

    编辑2: 好的,这里是:

    让,

    function F() {
    
        this.field = "value" ;
    
        var init = function(value) {
            this.field = value ;
        } ;
    
        this.method = function() {
            return this.field ;
        } ;
    
        init( arguments[0] ) ;
    
    } 
    

    现在,实例化 F 类型,

    var f = new F("newValue") ;
    

    将值设置为 Window 对象AS this 从闭包中调用时指向它。

    结合 Function ,

    function F() {
    
        var self = this ;
    
        this.field = "value" ;
    
        var init = function(value) {
            self.field = value ;
        } ;
    
        this.method = function() {
            return this.field ;
        } ;
    
        init( arguments[0] ) ;
    
    }
    

    将解决问题。

    然而,这种奇怪行为的原因是什么?

    5 回复  |  直到 14 年前
        1
  •  2
  •   DVK    14 年前

    这是(对)调用函数的对象。

    所以在你 f.method() 呼叫, this 是“F”。不是“F”。

    事实是 var self = this; 作品不是因为这个陈述本身,而是因为 method2() 是一个 closure

    更具体地说,变量 self 里面 方法2() 范围由确定 F() -换句话说,“自我”在里面 方法2() 总是引用 自己 当定义了“f”时就存在了(当时,它当然是“f”,因为当时的当前对象上下文是“f”)。

        2
  •  1
  •   Pointy    14 年前

    打电话是不对的 this 一个“操作员”。它是运行时在函数激活时建立的对象引用。

    JavaScript只是一种不同的语言,它以不同的方式进行操作。那 在程序员的控制下是非常强大的。

    而且,除非您没有发布的其他东西正在为“f”设置原型对象,否则代码绝对不起作用。“method”和“method2”都不能从对“f”实例的引用中调用。

        3
  •  1
  •   Jeremy Elbourn    14 年前

    对于方法的定义,您可能希望执行以下操作:

    this.method = function()
    {
        return this.field;
    }
    
        4
  •  1
  •   letronje    14 年前

    这就是你要找的例子吗?

    var F = function() {
    
         var self = this ; //!! points correctly to the Function Object
    
         this.field = "someValue" ;
    
         var helper1 = function(){
             return self.field;
         }
         var helper2 = function(){
             return this.field;  
         } 
         this.method = function(){
             return helper1();
         }
         this.method2 = function(){
             return helper2();
         }
     }
    
     var f = new F() ;
         console.log(f.method()) ; 
         console.log(f.method2()) ; 
    

    在方法的情况下,它调用使用self的helper,该helper在创建时指向f,因此可以工作。

    在method2的情况下,它使用helper2,helper2使用这个方法。但是在helper2中,这个函数的含义是“全局”范围,因此返回未定义的值。

        5
  •  1
  •   FK82    14 年前

    事实证明,这是ecmascript(因此是javascript)的ecma规范的一个黑暗角落:

    最后分配一个值用于这个关键字。如果指定的值引用对象,则属性访问器的前缀是该对象的this关键字引用属性。如果分配的值(内部)为空,则此关键字将引用全局对象。

    (http://jibbering.com/faq/notes/closures/;感谢@brian flanagan提供链接)

    显然,在执行分配给变量的函数时(在另一个变量中 Function )上下文丢失,因此作用域设置为空,并且 this 将引用 Window Object .


    我不太确定这是否是 功能 初始化为局部变量。通常,我希望一个闭包能够访问它在内存中创建的作用域,包括它在作用域链中的前一个作用域。

    这种行为不同于 财产 A的 功能 对象 ,上下文不会丢失,并且 将正确指向成员的所有者 功能 (这是 功能 对象 或者一个成员,取决于有多少层)。


    此问题的解决方案(同时保持私有 功能 成员,即只能从内部访问的成员 功能 的作用域)正在将函数包装到另一个 功能 使用 Function.prototype.apply (或) Function.prototype.call )要手动设置上下文:

    function F() {
    
        this.field = "value" ;
    
        var self = this ;
    
        var init = function(value) {
    
            (function() {
                this.field = value ;
            }).apply(self,value) ;
    
        } ;
    
        this.method = function() {
            return this.field ;
        } ;
    
        init( arguments[0] ) ;
    
    } 
    

    这和 Function.prototype.bind 在Javascript 1.85和Protopejs库中引入。

    编辑: 在中忘记了带括号的函数 init . 这将导致 SyntaxError .