JS嵌套原型访问父节点

JS nested prototype access parent node

根据以下代码,我在访问原型中的 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();

I need this without using the instance that I've just created like following:

myClass.events.test_a(myClass);

一般来说,最好避免以这种方式设计结构。

但是您可以通过在构造函数中绑定 events 函数来实现,这意味着创建事件对象的 "own" 副本。请参阅此 minimal-changes 版本中的 *** 条评论:

// 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 属性 指向函数,所以最好这样做。

您可以调用 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();

我建议使用现代 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("---");

Typescript 也可能是替代方案,因为它包含转译器。

imo。编写过时的代码是不合理的,只是因为您的一部分目标受众仍在使用过时的浏览器并且您需要支持它们。是的,我也有使用 IE10 的客户,需要支持该浏览器。