Может ли метод ссылаться на свой объект в обратном вызове без bind ()? - PullRequest
1 голос
/ 15 февраля 2012

Я делал тестовый пример, чтобы показать, как 'bind' необходим для того, чтобы метод ссылался на свою функцию в обратном вызове.

Но только когда я подумал, что знаю JS - следующий код работает нормально - без необходимости связывания!

pretendThingConstructor = function (greeting) {
    this.greeting = greeting;
    this.sayHello = function() {
        console.log(this.greeting);
    };
}

var pretend_thing = new pretendThingConstructor('hello world');

pretend_thing.sayHello();

setTimeout(function() {  
    pretend_thing.sayHello()
}, 3000);

Когда я запускаю его - через узел, phantomjs или другую среду JS - это работает. «Здравствуй, мир» печатается дважды.

Я ожидал, что второй «привет» - тот, что был запущен после тайм-аута, - потерпит неудачу, поскольку «this» будет относиться к событию, а не к объекту. Но это работает. Почему это?

Ответы [ 3 ]

2 голосов
/ 15 февраля 2012

this изменяется в зависимости от того, как вызывает функцию.Если вы укажете базовый объект , он будет ссылаться на него:

pretend_thing.sayHello()

Здесь pretend_thing - это базовый объект, и поэтому this по-прежнему ссылается на этот объект.С другой стороны, если у вас было:

var f = pretend_thing.sayHello;
f();

Здесь this вместо этого должно ссылаться на window объект.

Вы можете подтвердить это, введя:

console.log (this instanceof pretendThingConstructor);

Внутри вашей функции sayHello.В обоих случаях будет напечатано true.


pretendThingConstructor = function (greeting) {
    this.greeting = greeting;
    this.sayHello = function() {
        console.log(this.greeting);
        console.log(this instanceof pretendThingConstructor);
    };
}

var pretend_thing = new pretendThingConstructor('hello world');
////////////////////////////

pretend_thing.sayHello();

setTimeout(function() {  
    pretend_thing.sayHello();
}, 3000);

выведет:

true
true

, тогда как:

var f = pretend_thing.sayHello;
f();

выводит:

false
1 голос
/ 15 февраля 2012

В области действия функции pretendThingConstructor «this» относится к самой функции.Когда конструктор запускается (когда вы создаете экземпляр объекта с помощью ключевого слова 'new'), метод sayHello (который является анонимным методом) будет назначен свойству 'sayHello' в экземпляре объекта (в вашем случае pretend_thing).

Поскольку вы вызываете метод 'sayHello' ИЗ экземпляра объекта 'pretendThingConstructor' (pretend_thing), 'this' относится к объекту, из которого вы вызываете метод, а не к контексту, к которому вы обращаетесь.Вы выполняете в.

Вы можете изменить значение ключевого слова this, используя метод .apply:

function myHello(){
    this.greeting = 'Hello';
    this.method = function(){
         this.greeting
    }
}

function myGoodbye(){
    this.greeting = 'Goodbye';
    this.say = function(){
         console.log( this.greeting );
    }
}

var hello = new myHello();
var goodbye = new myGoodbye();

hello.say(); // Outputs 'Hello'
goodbye.say(); // Outputs 'Goodbye'

hello.say.apply( goodbye ); // Outputs 'Goodbye'
0 голосов
/ 15 февраля 2012

Да, в этом случае этот объект sayHello является pretend_thing, потому что функция знает , для какого элемента она вызывается. Это теряется, только если вы пытаетесь это сделать:

<- язык: lang-js ->

var say = pretend_thing.say_hello;
setTimeout(function () {
    say(); // this is window or null
}, 15)

// You can do something like
function doThings() {
    console.log(this.thing);
}

var test1 = { doThings: doThings, thing: 1 };
var test2 = { doThings: doThings, thing: 2 };

test1.doThings(); // <- 1
test2.doThings(); // <- 2

Таким образом, контекст зависит от того, где прикреплена функция. Но вы можете переопределить это поведение с помощью привязки.

...