Контекст Javascript во внутреннем объекте класса

1

До использования ES6 мы могли бы создать экземпляр класса, например...

var Animal = function(){}

а потом...

var dog = new Animal()

контекст внутри "класса" будет сам класс (экземпляр)

var Animal = function( name ){

   this.name = name;

   this.getName = function(){

      // the context here (this) is the class (Animal)
      return this.name; // works well

   }

}

Вопрос в том, что если я не хочу загрязнять область корня и использовать под-объекты, для различных целей, то контекст станет объектом, в котором функция сохраняется

var Animal = function( name ){

   this.utilities = {

      this.getName : function(){

         // the context here is the 'utilities' object so...
         return this.name // wouldn't work

      }

   }

}

конечно, мы всегда могли что-то использовать в форме

dog.utilities.getName.call(dog)

но это было бы довольно долго и неудобно...

есть ли способ создать объект "Утилиты" и применить контекст ко всем его функциям, чтобы указать на область корня? без необходимости использовать call и apply каждый раз? (ответ без использования ES6 был бы замечательным...)

  • 0
    "контекст внутри" класса "будет сам класс" Нет. Во-первых, this не "контекст". this именно this , что фактически является просто аргументом специальной функции. Во-вторых, this не относится к классу (например, функции конструктора), это относится к экземпляру (объекту), созданному new .
  • 0
    @T.J.Crowderспасибо за ввод, точка взята. у тебя есть ответ?
Показать ещё 3 комментария
Теги:

3 ответа

1
Лучший ответ

Один из способов гарантировать, что this то, что вы хотите, чтобы он был в различных функциях utilities - использовать функции стрелок для них, поскольку функции стрелок закрываются над this где они определены:

class Animal {
  constructor(name) {
    this.name = name;
    this.utilities = {
      getName: () => {       // This is an arrow function
        return this.name;    //
      }                      //
    };
  }
}
const dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"

Это в основном версия ES2015+ старого var t = this; решение:

function Animal(name) {
  var t = this;
  this.name = name;
  this.utilities = {
    getName() {
      return t.name;
    }
  };
}
var dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"

В обоих случаях это означает, что вы создаете новые функциональные объекты для каждого отдельного экземпляра Animal (код будет разделяться между этими объектами, но объекты разные). Это прекрасно, если не будет много экземпляров Animal.

Кроме того, у вас может быть помощник, с которым вы передаете экземпляр:

const Animal = (function() {
  class Utilities {
    constructor(animal) {
      this.a = animal;
    }
    getName() {
      return this.a.name;
    }
  }
  
  class Animal {
    constructor(name) {
      this.name = name;
      this.utilities = new Utilities(this);
    }
  }
  return Animal;
})();
const dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"

или же

var Animal = (function() {
  function Utilities(animal) {
    this.a = animal;
  }
  Utilities.prototype.getName = function getName() {
    return this.a.name;
  };
  
  return function Animal(name) {
    this.name = name;
    this.utilities = new Utilities(this);
  }
})();
var dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"

... который позволяет утилитам повторно использовать свои функциональные объекты через Utilities.prototype.

  • 0
    Спасибо TJ - я искал решение, которое не является ES6 ... первый фрагмент кода выглядит неплохо, есть ли способ достичь того же поведения, используя старый метод? ...
  • 0
    @levi: Ах, это не ясно из твоего вопроса. Да, через bind . Я обновлю.
Показать ещё 3 комментария
1

Вероятно, вы можете использовать следующее:

var utilities = function (context) {
    return {
        getName: function () {
            console.log(context.name)
        }
    }
}

var Animal = function( name ){
   this.name = name
   this.utilities = utilities.call(null, this)
}

var dog = new Animal('dog')
dog.utilities.getName()

Но, если вы в порядке делаете это: dog.getName() вместо dog.utilities.getName() тогда у вас может быть более чистое решение (IMO) следующим образом:

var Animal = function( name ){
   this.name = name
}

var utilities = {
    getName: function () {
        console.log(this.name)
    }
};

Object.assign(Animal.prototype, utilities)

var dog = new Animal('dog')
dog.getName()

Дай мне знать, если это работает. Благодарю.

НОВЫЙ ОТВЕТ:

var UTILITIES = {
    getName: function () {
        console.log(this.self.name)
    }
}

var Animal = function (name) {
    this.name = name
    this.utilities = Object.create(UTILITIES, {
        self: {
            value: this
        }
    })
}

var dog = new Animal('dog')
dog.utilities.getName()

Вариация включает использование атрибута "я", который указывает на интересующий пример. Теперь это could выглядеть более интуитивно.

  • 0
    Первый фрагмент выглядит немного как ответ T.Js (см. Последний фрагмент), если нет других решений, на которые я бы сослался, но я надеюсь получить еще более чистое решение, сначала что-то в форме T.Js. фрагмент, но написано в чем-то до ES6
  • 0
    this.utilities = utilities.call(null, this) или, вы знаете, this.utilities = utilities(this) (что в точности то же самое).
Показать ещё 1 комментарий
0

Вы можете использовать методы геттера. Я считаю их очень полезными для случаев, когда мне требуется форматированное значение. Таким образом, утилиты/логика известны только этому классу и не отображаются снаружи.

function Person(fname, lname) {
  var _fname = fname;
  var _lname = lname;
  
  Object.defineProperty(this, 'fullName', {
    get: function(){
      return _fname + ' ' + _lname
    }
  });
  
  Object.defineProperty(this, 'firstName', {
    get: function(){
      return _fname
    },
    set: function(value) {
      _fname = value;
    }
  });
  
  Object.defineProperty(this, 'lastName', {
    get: function(){
      return _lname
    },
    set: function(value) {
      _lname = value;
    }
  });
}

var person = new Person('hello', 'world');
console.log(person.fullName);

person.firstName = 'Hello';
console.log(person.fullName);

person.lastName = 'World'
console.log(person.fullName);
  • 0
    Примечание. Если вы считаете, что в этом ответе есть что-то неправильное / необязательное, пожалуйста, оставьте комментарий вместе с вашим голосом. Это действительно помогло бы всем.
  • 0
    Это действительно хорошо, и использование Object.defineProperty - хорошее соглашение, какой браузер я могу использовать для этого? ... но в конце концов я не искал способ использовать объявления классов или глобальные области видимости или свойства, а вызывал функцию внутри объекта с контекстом экземпляра ... в любом случае, спасибо
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню