Объектный метод используется между лексической областью или this-обязательным? - PullRequest
0 голосов
/ 08 января 2019

У меня возникают проблемы с определением того, какая концепция объясняет причину, по которой значение свойства "count" объекта сохраняется в приведенном ниже коде.

Я прочитал и просмотрел раздел this и прототип объекта из Getify's You Not Know JS а также их раздел, объясняющий лексическое это . Тем не менее, я не могу понять мой код ниже. Это лексический обзор? Или эта привязка позволяет сохранить значение 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 голосов
/ 08 января 2019

Это переплет .

Область действия - это понятие о том, какие переменные доступны и какие переменные язык скрывает от вас. На машинном языке все адреса памяти доступны для чтения и записи, поэтому на машинном языке и некоторых языках ассемблера концепция scope не существует (все переменные в основном глобальные). Более поздние языки представили понятие глобальных против локальных переменных с введением функций. Эта концепция получила дальнейшее развитие в замыканиях - возможность создавать несколько экземпляров областей действия .

Связывание - это понятие того, какое свойство / атрибут принадлежит какому объекту. В таких языках, как Java и C ++, которые реализуют раннее связывание, концепция связывания просто определяет, как методы обращаются к свойствам (обычно это позволяет языку не нуждаться в ключевом слове "this"). В поздних языках связывания есть немного более сложные правила, потому что связывание определяется во время выполнения, а не во время компиляции. Javascript является не только поздним связыванием, но и динамическим, что позволяет программистам изменять, какой объект этот указывает на использование таких вещей, как Function.prototype.call(). И присвоение методов одного объекта другому объекту во время выполнения (например, b.foo = a.foo)

0 голосов
/ 09 января 2019

TL; DR Механизм, который связывает свойство count со значением this, представляет собой неявное связывание (Getify's You Not Know JS), неявное Переплет

Первый Если я пришел к ложному выводу в своем объяснении, не могли бы вы сообщить, с чем вы согласны или не согласны, и поделиться, как я должен думать об этой проблеме? Я хочу улучшить, Спасибо!

Объяснение: Когда вызывается obj.method(), у нас есть поиск свойства для this.count. Если мы проверяем сайт вызова во время вызова obj.method(), obj переменная существует в глобальной области видимости. Свойства obj доступны через цепочку прототипов. Когда мы выполняем поиск свойства this.count, мы пытаемся получить доступ к свойству внутри объекта obj. Когда свойство не найдено, мы ищем цепочку прототипов для свойства. obj.count содержит / владеет свойством count в то время, когда мы получаем доступ к свойству count через привязку this.

Причины моей проблемы: Я смешал понятия о том, как this -связывание работает в arrow-fcns., Лексической области видимости и слишком буквальном толковании «this».

Примеры

Ниже приведены примеры кода, которые были источником моей путаницы. Моя проблема возникла из-за объединения соглашений о том, как связывание 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 -привязки. Я цитирую фрагмент из книги Гетифы

    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 -привязке

0 голосов
/ 08 января 2019

Проблема не имеет ничего общего с this или scoping. :-) Вы видите undefined s, потому что 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, он просто получает свое значение (ссылку на функцию) и затем записывает это (вы увидите некоторое представление функции в консоли) .

...