2016-04-13 3 views
1

Я знаю, что в этой теме было еще несколько вопросов, но ни один из них, похоже, не дает окончательного ответа.Обозначение класса JavaScript и ключевое слово «this»

Я строй HTML/CSS/JS мобильного приложения, и пытаюсь следующий стилем обозначений для определения некоторых классов:

стилизации

var Thing = (function() 
{ 
    var _instance; 

    var _firstName; 
    var _lastName; 

    function Thing(firstName, lastName) 
    { 
     _instance = this; 

     _firstName = firstName; 
     _lastName = lastName; 
    } 

    Thing.prototype.getMyName = function() 
    { 
     return _firstName + " " + _lastName; 
    } 

    Thing.prototype.speak = function() 
    { 
     return ("My name is " + _instance.getMyName()); 
    } 

    return Thing; 
}()); 

Преимущество этого являются:

  • Переменные участника инкапсулированы и могут быть указаны непосредственно (например, без префикса this).
  • Я могу использовать переменную _instance и поэтому избегать двусмысленности вокруг идентификатора this.
  • Обозначения достаточно чисты и удобочитаемы.

Я также дал следующие альтернативы попробовать:

Стиль B

function Thing(firstName, lastName) 
{ 
    this._firstName = firstName; 
    this._lastName = lastName; 
} 

Thing.prototype.getMyName = function() 
{ 
    return this._firstName + " " + this._lastName; 
}; 

Thing.prototype.speak = function() 
{ 
    return "My name is " + this.getMyName(); 
}; 

Стиль C

class Thing 
{ 
    constructor (firstName, lastName) 
    { 
     this._firstName = firstName; 
     this._lastName = lastName; 
    } 

    getMyName() 
    { 
     return this._firstName + " " + this._lastName; 
    } 

    speak() 
    { 
     return ("My name is " + this.getMyName()); 
    } 
} 

Но, несмотря на свои преимущества, я нашел B и C сложно работать из-за проблем, связанных с ключевым словом this; то есть в зависимости от контекста вызывающего абонента this может ссылаться на разные вещи в методах класса. Кроме того, в обоих случаях использование переменной _instance, как у меня есть, в A невозможно, так как всем участникам необходимо префикс this..

Однако, как указано в комментариях, Стиль A не работает при создании нескольких экземпляров класса.

Каков наилучший способ написать такие классы, но избежать проблем с this?

+2

Ваш «Стиль А» просто не работает. Вы пытались создать несколько экземпляров? Также вы никогда не инициализируете '_instance'. – Bergi

+2

Стиль А отличается от остальных. Эти переменные в закрытии повторно используются для каждого экземпляра. – elclanrs

+0

Спасибо @Bergi, я отредактировал для инициализации '_instance'. – Benp44

ответ

2

Если вы хотите, чтобы избежать методы прототипа с поздней привязкой this любой ценой, вы можете использовать следующий стиль в ES6:

class Thing { 
    constructor(firstName, lastName) { 
     this.getMyName =() => firstName + " " + lastName; 
     this.speak =() => "My name is " + this.getMyName(); 
    } 
} 

(вы можете также использовать function декларацию, но class имеет преимущество в том, что оно предотвращает вызовы без new)

+0

Но в нетривиальном случае, когда класс имеет много больших методов, содержащий все из них в конструкторе, безусловно, будет немного громоздким? (хотя я действительно признаю «лексическое» использование функций стрелок, которые я безуспешно пытался включить в решение) – Benp44

+1

@ Benp44: Ну, по-видимому, это то, что вы хотите. Вы не можете использовать прототипы без 'this'. – Bergi

1

Вы создаете закрытие, а затем разделяете замыкание между экземплярами объектов с помощью конструктора Thing. Он не будет работать должным образом.

var elton = new Thing("Elton", "Johnnavartangula"); 
elton.getMyName(); // <- "Elton Johnnavartangula" 
var fenry = new Thing("Fenry", "Honda"); 
elton.speak(); // <- "My name is Fenry Honda" 

обмена рядовыми среди конкретизированных объектов другая тема и может быть сделано несколькими способами, как в одном из моих previous answer или как

function Source(){ 
var priv = "secret"; 
return {gp : function(){return priv}, 
     sp : function(v){priv = v} 
     } 
} 
sharedProto = Source(); // priv is now under closure to be shared 
var p1 = Object.create(sharedProto); // sharedProto becomes o1.__proto__ 
var p2 = Object.create(sharedProto); // sharedProto becomes o2.__proto__ 
Смежные вопросы