在词法范围还是this-binding之间使用对象方法?

时间:2019-01-08 08:25:26

标签: javascript this lexical-scope

我在确定什么概念解释为什么将对象的属性“ count”的值保留在下面的代码中时感到困难。

我已阅读并阅读了Getify的You Don't Know JS此和对象原型部分 以及他们解释lexical this的部分。 但是,我无法在下面理解我的代码。 这是词汇作用域吗? 还是这个绑定可以保留count的值?

下面是示例代码:

var obj = {
    count: 0,
    method: function() {
        console.log("in method: " + this.count)
        return this.count++;
    },
    timeOutMethod: function() { // I understand here we explicitly bind this, no problem here
        setTimeout(function() {
            console.log(this.count++)
        }.bind(this), 100)
    }
}

// here is where I have issue, when the method is invoked as a function
for (var i = 0; i<10; i++) {
    console.log(obj.method()) // invoked as a function
}

// I've left this small block in for convenience
// I have no trouble with understanding why this block outputs what it outputs
for (var i = 0; i<10; i++) {
    console.log(obj.method) // "gets its value (a reference to a function) and then logs that" from TJ Crowder
}

我希望对obj.method()的第一个方法调用的输出能够输出

// 0
// in method 0
// 1
// in method 1
// 2
.
.
.
// 10
// in method 10

我对输出内容没有问题。我的问题再次是,这是词汇作用域吗? 还是这个绑定可以保留count的值?

感谢您抽出宝贵的时间来提供帮助。

编辑1 在下面Tj Crowder的帖子的帮助下,我编辑了代码段以清除错误,因为它使我的问题分散了注意力。

3 个答案:

答案 0 :(得分:3)

此问题与this 作用域无关。 :-)您看到undefined是因为method不返回任何内容,因此调用它会得到值undefined,您将通过console.log进行记录。要使其返回 count的值,您可以添加一个return

method: function() {
    console.log(this.count)
    return this.count++;
//  ^^^^^^
},

这将返回this.count的值,该值与增量之前的值相同(这似乎是您从预期输出中得到的值)。

实时示例:

var obj = {
    count: 0,
    method: function() {
        console.log("in method: " + this.count)
        return this.count++;
    },
    timeOutMethod: function() { // I understand here we explicitly bind this, no problem here
        setTimeout(function() {
            console.log(this.count++)
        }.bind(this), 100)
    }
}

// here is where I have issue, when the method is invoked as a function
for (var i = 0; i<10; i++) {
    console.log(obj.method()) // invoked as a function
}
.as-console-wrapper {
  max-height: 100% !important;
}


另外,对此:

for (var i = 0; i<10; i++) {
    console.log(obj.method) // invoked as a property
}
根本不调用 method

,它只是获取其值(对函数的引用),然后记录该值(您将在控制台)。

答案 1 :(得分:1)

它具有绑定力

作用域是可访问的变量以及语言对您隐藏的变量的概念。在机器语言中,所有内存地址都是可读写的,因此在机器语言和某些汇编语言中,作用域的概念不存在(所有变量基本上都是全局变量)。后来的语言通过函数的引入引入了全局变量与局部变量的概念。此概念进一步演变为闭包-创建作用域的多个实例的功能。

绑定是哪个属性/属性属于哪个对象的概念。在实现早期绑定的Java和C ++之类的语言中,绑定的概念仅控制方法访问属性的方式(通常,这使该语言不需要“ this”关键字)。后期绑定语言的规则稍微复杂一些,因为绑定是在运行时而不是编译时确定的。 JavaScript不仅是后期绑定,而且是动态绑定-允许程序员更改指向的对象,以使用诸如Function.prototype.call()之类的对象。并在运行时将一个对象的方法分配给另一个对象(例如b.foo = a.foo

答案 2 :(得分:0)

TL; DR 将属性count绑定到this值的机制是隐式绑定 (Getify's You Don't Know JS), Implicit Binding

首先:如果我在解释中得出了错误的结论,您是否愿意提供您同意或不同意的内容,并分享我应如何考虑这个问题?我想要改善,谢谢!

说明:调用obj.method()时,我们将对this.count进行属性查找。如果我们在调用obj.method()时检查呼叫站点,则obj是全局范围内的变量。 obj的属性通过原型链访问。当我们执行this.count的属性查找时,我们尝试访问obj中的属性。当找不到该属性时,我们将查找该属性的原型链。在我们通过“ this”绑定访问obj.count属性时,count包含/拥有属性count

我的问题的原因:我混合了this绑定如何在箭头框架中操作,词法范围以及对“ this”的解释过于文字化的概念。 / p>

示例

下面是使我感到困惑的代码示例。 我的问题源于将this-绑定如何以不同的代码样式进行操作的约定混为一谈。我混合了以下内容:

  1. this关键字如何在箭头功能(即词法作用域)中运行

    function wait() {
        setTimeout(() => {
            console.log(this) // lexically bound
        }, 100);
    }
    
    wait();
    
    function foo() {
        // console.log(this) - will output {a: 2}
        return (a) => {
            console.log(this.a) // 'this' value is adopted from foo's lexical scope
        }
    }
    
    var obj = {
        a: 2
    }
    
    var obj2 = {
        a: 3
    }
    
    // foo is 'this'-bound to obj1
    // bar, a reference to the returned arrow-function will also be 'this'-bound to obj1
    // the arrow function binding cannot be overridden
    var bar = foo.call(obj) 
    bar.call(obj2)
    
  2. 不是理解this的实际工作原理,而是将词法作用域用作解决方法。在这里,data.count增加了

    function foo() {
        return data.count++; // the obj property data.count is accessed via global scope
    }
    
    var data = {
        count: 0,
    }
    
    for (var i = 0; i<10; i++) {
        foo()
    }
    
    console.log(data.count)
    
  3. 最后,对this-绑定的解释过于文字化,可能会引起另一个误解。我引用的摘录来自Getify的书

    function foo(num) {
        console.log( "foo: " + num );
    
        // keep track of how many times `foo` is called
        this.count++;
    }
    
    foo.count = 0;
    
    var i;
    
    for (i=0; i<10; i++) {
        if (i > 5) {
            foo( i );
        }
    }
    // foo: 6
    // foo: 7
    // foo: 8
    // foo: 9
    
    // how many times was `foo` called?
    console.log( foo.count ); // 0 -- not what we expected
    

此外:感谢@TJ Crowder和@slebetman在澄清关于范围和this绑定的其他误解方面所提供的帮助