2016-09-27 2 views
0

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

Вот пример моего кода:

MyClass = function(callback){ 

    this.tabs = []; 
    var tabs_callback = function(){}; 

    this.setTabsCallback = function(callback) { 
     tabs_callback = callback; 
    } 

    var _doStuff = function(callback) { 

     // doing stuff 

     this.tabs = [1, 2, 3]; 

     console.log("Inside doStuff"); 
     console.log(this.tabs); 

     tabs_callback(); 
    } 

    this.doStuff = function() { 
     _doStuff(); 
    } 
} 


var myObject = new MyClass(); 

myObject.setTabsCallback(function() { 

    console.log("Inside callback"); 
    console.log(myObject.tabs); 
}); 

myObject.doStuff(); 

И вот что я получаю в консоли:

Inside doStuff 
[ 1, 2, 3 ] 
Inside callback 
[] 

Почему я не в состоянии видеть мою модификацию от функции обратного вызова?

+2

Вероятно сфера применения 'this'. В верхней части функции «MyClass» (возможно, строка выше 'this.tabs = [];') создайте переменную 'var self = this;' и используйте 'self' вместо' this', где вы хотите доступ к публичным свойствам. – jonhopkins

+0

О, отлично! Вы правы, это сработало! большое спасибо –

ответ

1

Поскольку _doStuff определяется как функция, она имеет свой собственный this контекст, поэтому вы не можете получить доступ к this.tabs, определенный за пределами частной функции.

Существует два простых способа решить эту проблему.

Во-первых, вы можете просто создать приватную переменную, которая содержит ссылку на this вне функции:

... 
var that = this; 
var _doStuff = function(callback) { 
    // inside _doStuff, use "that" instead of "this" 
... 

Или, во-вторых, вы можете вместо этого использовать функцию стрелки. Функции Arrow являются относительно новым дополнением к Javascript.Они не создают отдельный контекст со своей собственной this ссылки, поэтому при использовании this объекта он все равно будет ссылаться на тот же объект, вне функции, так что ваша функция будет работать правильно:

.... 
var _doStuff = (callback) => { 
    // now _doStuff doesn't create a new "this" object, so you can still access the one from outside 
... 
1

См. this keyword. Использование функций стрелок является хорошим способом, чтобы предотвратить многие из этих вопросов:

var _doStuff = (callback) => { ...

Но вы все равно должны знать об этом.

1

По умолчанию JS не использует лексический контекст привязки, а при вызове обычных функций, this по умолчанию для window (или null, если вы находитесь в строгом режиме).

Существует много способов избежать этого: вы можете сохранить this переменной, как упомянуто выше. Он будет работать в 100% случаев.

Также вы можете явно привязать _doStuff к контексту, используя метод Function#bind: сделайте что-нибудь вроде _doStuff = _doStuff.bind(this) после его инициализации или вы можете называть его _doStuff.bind(this)(). IE до IE9 (и, может быть, некоторые другие браузеры, я не совсем уверен) не поддерживают bind.

В конце вы можете использовать функцию стрелки, так как она также упоминается выше: они используют лексическую привязку, а this будут такими же, как вы ожидаете. Функции стрелок доступны с ES6, но, я полагаю, если вы создаете такие конструкторы, это не ES6.

1

Когда _doStuf вызывается с помощью функции, как

this.doStuff = function() { 
       _doStuff(); 
       } 

_doStuff связан с глобальным объектом. Следовательно, вы должны либо привязать его определение к this, либо использовать .call(this) при вызове функции _doStuff. Таким образом, изменение вашего кода следующим образом поможет;

MyClass = function(callback){ 
 

 
    this.tabs = []; 
 
    var tabs_callback = function(){}; 
 

 
    this.setTabsCallback = function(callback) { 
 
     tabs_callback = callback; 
 
    } 
 

 
    var _doStuff = function(callback) { 
 

 
     // doing stuff 
 

 
     this.tabs = [1, 2, 3]; 
 

 
     console.log("Inside doStuff"); 
 
     console.log(this.tabs); 
 

 
     tabs_callback(); 
 
    } // <<< you can either use .bind(this) here 
 

 
    this.doStuff = function() { 
 
     _doStuff.call(this); // <<< or use .call(this) here to bind _doStuff to the this 
 
    } 
 
} 
 

 

 
var myObject = new MyClass(); 
 

 
myObject.setTabsCallback(function() { 
 

 
    console.log("Inside callback"); 
 
    console.log(myObject.tabs); 
 
}); 
 

 
myObject.doStuff();

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