JS вложенный прототип доступа родительского узла - PullRequest
1 голос
/ 28 июня 2019

Согласно следующему коду, у меня небольшая проблема с доступом к переменной this в прототипах.

var MyClass = function(number) {
  this.number = number || 4;
};
MyClass.prototype = {
  run: function() {
    //direct access to object
    console.log(this.number);

    //access to object with the "self" object
    var self = this;
    setTimeout(function() {
      console.log(self.number);
    }, 1000);

    //access to object with the "self" object as a parameter
    this.events.test_a(self);

    //here is the problem
    this.events.test_b();
  },
  events: {
    test_a: function(self) {
      //access to object with the "self" object as a parameter
      console.log(self.number);
    },
    test_b: function() {
      console.log(this.number); // ? The problem
    }
  }
};

//----

var myClass = new MyClass(110);
myClass.run();

Есть ли способ получить доступ к объекту this и иметь некоторую структуру, подобную следующей?

myClass.events.test_b();

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

myClass.events.test_a(myClass);

Ответы [ 3 ]

3 голосов
/ 28 июня 2019

В общем, лучше избегать проектирования структуры таким способом.

Но вы можете сделать это, связав функции events в конструкторе, что означает создание «собственной» копииобъект событий.См. *** комментарии в этой версии с минимальными изменениями:

// NOTE: Sticking to ES5 as the OP seems to be doing that

var MyClass = function(number) {
  this.number = number || 4;
  // *** Bind the functions on `this.events` to `this`
  var self = this;
  var events = self.events;
  self.events = {};
  Object.keys(events).forEach(function(key) {
    if (typeof events[key] === "function") {
      self.events[key] = events[key].bind(self);
    }
  });
};
// I've added the "name" parameter that's being passed around
// so we can be sure that the results for multiple
// instances are correct
MyClass.prototype = {
  constructor: MyClass, // *** Don't break prototype.constructor
  run: function(name) {
    //direct access to object
    console.log(name, "Direct access in object:", this.number);

    //access to object with the "self" object
    var self = this;
    setTimeout(function() {
      console.log(name, "In setTimeout callback:", self.number);
    }, 1000);

    //access to object with the "self" object as a parameter
    this.events.test_a(name, self);

    //here is the problem
    this.events.test_b(name);
  },
  events: {
    test_a: function(name, self) {
      //access to object with the "self" object as a parameter
      console.log(name, "In test_a:", self.number);
    },
    test_b: function(name) {
      console.log(name, "In test_b:", this.number); // ? Not a problem anymore
    }
  }
};

//----

var mc1 = new MyClass(110);
var mc2 = new MyClass(220);
setTimeout(function() {
    mc1.run("mc1");
}, 1000);
setTimeout(function() {
    mc2.run("mc2");
}, 2000);
.as-console-wrapper {
    max-height: 100% !important;
}

Примечание: смотрите эту строку, которую я добавил к объекту, который вы назначаете prototype:

constructor: MyClass, // *** Don't break prototype.constructor

По умолчанию объект prototype в функции имеет свойство constructor, указывающее назад на функцию, поэтому лучше всего это сделать.

2 голосов
/ 28 июня 2019

Вы можете вызвать events.test_b, передавая контекст MyClass экземпляра следующим образом:

this.events.test_b.call(this);

var MyClass = function(number) {
  this.number = number || 4;
};
MyClass.prototype = {
  run: function() {
    //direct access to object
    console.log(this.number);

    //access to object with the "self" object
    var self = this;
    setTimeout(function() {
      console.log(self.number);
    }, 1000);

    //access to object with the "self" object as a parameter
    this.events.test_a(self);

    //here is the problem
    this.events.test_b.call(this);
  },
  events: {
    test_a: function(self) {
      //access to object with the "self" object as a parameter
      console.log(self.number);
    },
    test_b: function() {
      console.log(this.number); // ? The problem
    }
  }
};

//----

var myClass = new MyClass(110);
myClass.run();
1 голос
/ 01 июля 2019

Я бы рекомендовал использовать современные функции JS и стрелки.

И, возможно, транспортер для обратной совместимости (при необходимости)

class MyClass {
  constructor(number = 4) {
    this.number = number;
  }

  run() {
    //direct access to object
    console.log("run", this.number);

    // no need for "self"
    setTimeout(() => {
      console.log("setTimeout", this.number);
    }, 1000);

    //access to object with the "this" object as a parameter
    this.events.test_a(this);

    //here is the problem
    this.events.test_b();
  }

  events = {
    test_a: (self) => {
      //access to object with the "self" object as a parameter
      console.log("test_a", self.number);
    },

    test_b: () => {
      console.log("test_b", this.number); // ? The problem
    }
  }
};

//----

var a = new MyClass(110);
a.run();
console.log("---");

var b = new MyClass(42);
b.run();
console.log("---");

Машинопись также может быть альтернативой, так как включает транспортер.

имо. устаревший код писать нецелесообразно, просто потому, что часть вашей целевой аудитории все еще использует устаревшие браузеры, и вам необходимо их поддерживать. И да, у меня тоже есть клиенты с IE10, и мне нужно поддерживать их до этого браузера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...