对创建OOP Javascript的误解

时间:2016-03-09 21:13:53

标签: javascript oop

我无法理解某些事情。我一直在寻找差异,但我似乎无法找到我想要的答案。

我正在尝试学习OOP javascript,我在那里阅读的每个教程似乎都是一种不同的继承方式,并且通常以非常复杂的方式进行解释。我现在遇到的问题与为对象创建方法有关,我使用的是Mozilla开发人员文档中的代码。

您会在下面的大型代码块中看到我尝试在jump中添加Person方法,如下所示:

Person.prototype = {
  jump: function() {
    console.log("Jumping")
  }
}

这不起作用它基本上打破了整个课程,告诉我student1.walk不是一个函数。但是,如果我将方法的声明更改为

Person.prototype.jump = function() {
    console.log("Jumping");
}

当我调用方法时,一切都会像它应该的那样工作。从个人风格的角度来看,虽然我喜欢创建方法的第一种方法,因为我不必继续重复Person.prototype部分,我可以继续添加逗号,然后是我的方法声明。我想知道这两种创建方法的方法之间有什么区别,因为我无法在任何地方找到答案。我想了解为什么它也会使用第一种方法中断。

  var Person = function(firstName) {
      this.firstName = firstName;
    };

    Person.prototype.walk = function(){
      console.log("I am walking!");
    };

    Person.prototype = {
      jump: function() {
        console.log("Jumping");
      }
    }

    Person.prototype.sayHello = function(){
      console.log("Hello, I'm " + this.firstName);
    };

    function Student(firstName, subject) {

      Person.call(this, firstName);

      this.subject = subject;
    }

    Student.prototype = Object.create(Person.prototype); // See note below

    Student.prototype.constructor = Student;

    Student.prototype.sayHello = function(){
      console.log("Hello, I'm " + this.firstName + ". I'm studying "
                  + this.subject + ".");
    };

    Student.prototype.sayGoodBye = function(){
      console.log("Goodbye!");
    };

    var student1 = new Student("Janet", "Applied Physics");
    student1.sayHello();
    student1.walk();
    student1.sayGoodBye();
    student1.jump();

4 个答案:

答案 0 :(得分:7)

问题在于您通过调用Person.prototype = {}来覆盖整个原型链。这使得其他方法消失了,因为它们通过重置而从链中取出。

它与任何其他变量一样

let x = 5; //5
x = 6; // 6

这是一个简单的赋值语句,重新分配你的原型链。

答案 1 :(得分:3)

比较两个陈述:

Person.prototype = {
  jump: function() {
    console.log("Jumping");
  }
};

在这里,您将原型设置为新的对象文字。在下一个声明中:

Person.prototype.jump = function() {
    console.log("Jumping");
};

您正在将原型的跳转属性设置为函数。

如果要一次添加所有功能,请将原型声明一次:

Person.prototype = {
  jump: function() {
    console.log("Jumping")
  },
  walk: function(){
    console.log("I am walking!");
  },
  sayHello: function(){
    console.log("Hello, I'm " + this.firstName);
  }
};

它们之间的区别仅仅在于将方法添加到原型中。我通常更喜欢一次将所有功能添加到原型中,以便我知道代码在哪里制作了sayHello方法。如果我需要根据新信息重新定义方法,我偶尔会使用第二种方法。但这非常罕见。

答案 2 :(得分:2)

永远不要用不同的对象替换构造函数的prototype,除非你知道自己在做什么。

它有这些问题:

  • 更改前创建的实例将不再被instanceof视为实例,并且他们不会从新对象继承属性。
  • 实例创建后,更改不会从旧对象继承属性。
  • 旧对象可能包含一些您未明确设置的数据,例如constructor属性或内部[[Prototype]]。除非您将其复制到新对象,否则这将丢失。

如果您只想向prototype添加多个属性而不是每次都重复,请使用Object.assign

Object.assign(Person.prototype, {
  jump: function() {
    console.log("Jumping");
  },
  sayHello = function(){
    console.log("Hello, I'm " + this.firstName);
  }
});

答案 3 :(得分:1)

javascript中的OOP很难看。我会使用像ds.oop这样的类库。它类似于prototype.js和其他。使多重继承非常容易和极简主义。 (仅2或3 kb)还支持其他一些简洁的功能,如接口和依赖注入

/*** multiple inheritance example ***********************************/

var Runner = ds.class({
    run: function() { console.log('I am running...'); }
});

var Walker = ds.class({
    walk: function() { console.log('I am walking...'); }
});

var Person = ds.class({
    inherits: [Runner, Walker],
    eat: function() { console.log('I am eating...'); }
});

var person = new Person();

person.run();
person.walk();
person.eat();