2015-01-13 4 views
0

Почему _this. не работает, но this. работает.Javascript scope и self = this, _this = this, that = this

Я думал, что вся точка _this=this должна была обеспечить механизм для вызова функций объекта, у вас есть «гарантированная» ссылка обратно на экземпляр объекта, так как теперь он находится в закрытии функции объекта, чтобы имитировать традиционный класс поведение. Я читал так много частей о сфере видимости, и по какой-то причине я просто не вижу этого. Что мне не хватает?

var PersonClass = function PersonClass(_name, _age) { 
    _this=this; 
    this.name=_name; 
    this.age=_age; 

    console.log("created "+this.name+":"+this.age); 

    function changeAge(num) { 
     console.log("changing age for:" + _this.name); 
     _this.age=num; 
    } 

    PersonClass.prototype.changeAge=changeAge; 
    PersonClass.prototype.getAge=function() { 
     console.log(_this.name+":"+_this.age); 
     return _this.age; 
    }; 
    PersonClass.prototype.getAge2=function() { 
     console.log(this.name+":"+this.age);   
     return this.age; 
    }; 
}; 

// comments indicate what value is displayed in console 
var john=new PersonClass("john",1); // john:1 
var sue=new PersonClass("sue",2); // sue:2 

john.getAge(); // sue:2 
john.getAge2(); // john:1 

john.changeAge(10); // sue 
sue.getAge(); // sue:10 
sue.getAge2(); // sue:10 
john.getAge(); // sue:10 
john.getAge2(); // john:1 
+7

Вероятно потому, что вы не 'var'd его. Вы тоже делаете что-то очень необычное с прототипированием там. Как вы его написали, это должны быть методы экземпляра, не унаследованные методы –

+0

Это сломанный mish-mash двух разных способов написания «классов» в JS. – Alnitak

+0

Не используйте глобальные переменные и не собирайте локальные объекты в прототипных методах. – SLaks

ответ

2

Когда вы звоните

new PersonClass() 

в первый раз, методы прототипа созданы.

Когда вы звоните

new PersonClass() 

второй раз, методы прототипа заменяются и теперь имеет последние _this в области замыкания.

Итак, переместите методы прототипа вне функции конструктора.

+0

http://jsfiddle.net/sday/w20rtmqn/ Я сделал это с первым GetAge, у которого есть эта ссылка, но ничего не изменилось. PersonClass.prototype.getAge = СеЬАд; // затем объявим отдельную функцию. (это то, что вы имели в виду?) – sday

+0

@sday Первый способ: http://jsfiddle.net/w20rtmqn/2/. Второй способ: http://jsfiddle.net/w20rtmqn/3/. Не изменяйте конструктор конструктора внутри конструктора. –

+0

Очень полезно спасибо. У меня возникло ощущение, что после доступа к этому классу существует следующий вопрос с помощью прослушивателя кликов. – sday

2

Проблема заключается в том, что scope ваших внутренних функций не разрешается до this, поэтому они теряют всякую ссылку на область, созданную при инициализации new PersonClass(). Метод bind разрешит scope внутренних функций на this родительского класса функций.

var PersonClass = function PersonClass(_name, _age) 
{ 
    var _this=this; 
    this.name=_name; 
    this.age=_age; 

    console.log("created "+this.name+":"+this.age); 

    this.changeAge = function(num) 
    { 
     console.log("changing age for:" + _this.name); 
     _this.age = num; 
    }.bind(this); 

    this.getAge = function() 
    { 
     console.log(_this.name+":"+_this.age); 
     return _this.age; 
    }.bind(this); 

    this.getAge2 = function() 
    { 
     console.log(this.name+":"+this.age);   
     return this.age; 
    }; 
}; 

// comments indicate what value is displayed in console 
var john = new PersonClass("john",1); // john:1 
var sue = new PersonClass("sue",2); // sue:2 

john.getAge(); // sue:2 
john.getAge2(); // john:1 

john.changeAge(10); // sue 
sue.getAge(); // sue:10 
sue.getAge2(); // sue:10 
john.getAge(); // sue:10 
john.getAge2(); // john:1 

Yup, это сделаю.

Эй, смотрите, это работает! Here's the updated Fiddle

Просто предоставить больше информации о bind

Допустим, мне есть object:

var myObj = {}; 

И зададим свойство этого object:

myObj.test_property = "Hello World!"; 

Мы можем доступ к этому свойству из других свойств через bind и this.

Допустит, мы делаем еще одно свойства, что это function:

myObj.test_func = function() 
{ 
    alert(this.test_property); 
}.bind(myObj); 

Подождите, вы предполагаете, что это будет делать?

Из-за метода bind область this была разрешена к myObj.

Следовательно, this.test_property равно myObj.test_property, сохраняя область действия.

Пошли дальше ...

Мы объявим другую функцию:

myObj.test_func2 = function(val) 
{ 
    this.test_property = val; 
}.bind(myObj); 

Теперь, позволяет запустить тест:

myObj.test_func(); 
myObj.test_func2("Hello Dude"); 
myObj.test_func(); 

Как вы можете видеть, как test_func и test_func2 доли ту же область.

Here's a JSFiddle illustrating everything I've said about bind

+0

Также очень полезно спасибо. Между вами и Павлом я вижу 3 способа сделать это. Забавно, я думаю, что все три метода в чтении смутили меня до такой степени, что я смешивался и соглашался, как указал Алнитак. Хотя я не пробовал метод привязки. Теперь мне нужно понять плюсы и минусы каждого метода. :) – sday

+0

Я думал, что это. внутри test_func() будет разрешено что-либо в функции ... Я думал, что это закрытие, и это ссылается на что-либо внутри этого закрытия. Наверное, это неверно. Я смущен, узнав, где это указывает. – sday

+0

В моем примере 'this' будет решать все, с чем была связана функция, в этом случае' this' будет разрешаться 'myObj'. В функции 'myObj.test_func',' this.test_func' будет ссылка на себя. – WebWanderer

2

Есть немало проблем с вашим кодом.

  1. _this=this;

    Создает глобальную переменную window._this. Используйте такие инструменты, как jshint, чтобы избежать подобных ошибок.

  2. PersonClass.prototype не должен использоваться в функции конструктора. Вы смешиваете два разных шаблона создания объектов. Внутри функции строительства вы должны использовать что-то вроде

    this.getAge2 = function(){...}

  3. не обязательно является ошибкой, но для вашего связывания это _this образец кода не требуется. Это будет использоваться только тогда, когда ваша функция не будет вызвана на созданном вами объекте, например, используя что-то вроде window.setTimeout(john.getAge, 100)

    Это приводит к тому, что функция getAge становится несвязанной из объекта john при вызове.

Вот ваш код с обсуждаемыми изменениями (то есть не сказать, что я рекомендую эту модель):

var PersonClass = function PersonClass(_name, _age) { 
    var _this=this; 
    this.name=_name; 
    this.age=_age; 

    console.log("created "+this.name+":"+this.age); 

    function changeAge(num) { 
     console.log("changing age for:" + _this.name); 
     _this.age=num; 
    } 

    this.changeAge=changeAge; 
    this.getAge=function() { 
     console.log(_this.name+":"+_this.age); 
     return _this.age; 
    }; 
    this.getAge2=function() { 
     console.log(this.name+":"+this.age);   
     return this.age; 
    }; 
}; 


var john=new PersonClass("john",1); // john:1 
var sue=new PersonClass("sue",2); // sue:2 

john.getAge(); // john:1 
john.getAge2(); // john:1 

john.changeAge(10); // john 
sue.getAge(); // sue:2 
sue.getAge2(); // sue:2 
john.getAge(); // john:10 
john.getAge2(); // john:10 


window.setTimeout(john.getAge, 200); //john:10 
window.setTimeout(john.getAge2, 400); // incorrect 
+0

Hahaha, тайм-аут ** не будет ** исправить это – WebWanderer

+0

@WebWanderer Timeout не используется, чтобы исправить что-либо. Он используется в качестве тестового примера, чтобы продемонстрировать, что функции getAge не привязаны к объекту, а getAge2() - нет. –

+0

Спасибо. Все это началось с более крупного кода, где событие click вызывает все виды хаоса. Отряд, как вы говорите. Эта нить, хотя всего лишь за несколько минут, помогла мне очень тяжело, я читал бесчисленные другие темы по этому вопросу. Думаю, погружение изменило ситуацию. – sday

Смежные вопросы