javascript 如何使用构造函数作为原型链?

lh80um4z  于 2023-01-29  发布在  Java
关注(0)|答案(4)|浏览(116)

假设我有一个javascript构造函数:

function Person(name) {
    this.name = name;
    this.hello = function () { return "It's a-me, " + name + "!"; };
}

Person“类型”有一个方便的方法hello,我希望在另一个类型Student上重用它。我希望Student具有以下结构:

function Student(name) {
    this.name = name;
    this.hello = function () { return "It's a-me, " + name + "!"; };
    this.books = [];
}

一种选择是使用上面Student的代码,这是次优的,因为通常的原因,例如,如果我想让它镜像Person类型,那么我必须手动保持他们的代码同步,无论如何,这是不好的。
第二个选项(来自this answer)是执行类似以下操作:

function Student(name) {
    Person.call(this, name);
    this.books = [];
}

当我mario = new Student("mario")时,我得到以下结果:

Object { name: "mario", hello: hello(), books: [] }

我已经成功地实现了我想要的继承,但是这有一个不幸的特性,那就是把所有想要的属性都放到了我的对象中。值得注意的是,例如,在mario上有一个“hello”属性。如果能在原型链中查找到这个“hello”属性,那就太好了。
给定了相关的对象构造函数,我如何巧妙地创建一个原型链?

jtjikinw

jtjikinw1#

使用new创建对象时,构造函数的this值将设置为该对象,并且该对象的原型将设置为正在调用的构造函数的原型。
这就是为什么您的属性当前被添加到创建的对象。

function Student {
    this.name = name
}

const student = new Student('John')

// is (almost) equivalent to the following

const student = {}
student.name = 'John'

但是,如果您想向原型添加属性,以便可以使用继承,那么在ES5 Javascript中,您可以通过将属性直接分配给构造函数的原型来实现。

function Person(name) {
    this.name = name;
}

// Person is a function
// Its prototype is an instance of Object, and it has no properties
// i.e. something like Person.prototype = new Object()

Person.prototype.hello = function() {
    return 'It is I, ' + this.name
}

// Now Person.prototype has one property, "hello", which is a function.

function Student(name) {
    Person.call(this, name)
    this.books = [];
}

// Student is a function
// Its prototype is also an instance of Object with no properties

// the following is the magic line
Student.prototype = Object.create(Person.prototype)

// We replace the prototype of the Student function with a new object, but
// Object.create() allows us to set the prototype to an existing object, in this case Person.prototype,
// Person.prototype is itself an instance of Object, and we previously
// added the "hello" function to it as a property.

const student = new Student('John')

// So what happens here?
// First a new object is created, and its prototype is set to Student.prototype
// Then we call Person.call(this)
// Which executes the body of the Person function
// So you get the properties on the object itself through the body of the Person and Student functions
// And you get the shared functionality through the prototype chain of instance -> Student.prototype -> Person.prototype -> Object.prototype

希望能有所帮助!

4uqofj5v

4uqofj5v2#

你可以根据自己的需要使用原型法或类糖法。下面是一个简单的例子:

function Student(name) {
    this.name = name;
    this.books = [];
}
Student.prototype.hello = function(){
    return "It's a-me, " + this.name + "!";
}
Student.prototype.addBook = function(book){
    this.books.push(book);
}
Student.prototype.getBooks = function(){
    return this.books;
}

let mario = new Student("Mario");

console.log(mario.hello());
mario.addBook("prototyping");
mario.addBook("chain");
console.log(mario.getBooks());

class Person {
  constructor(name) {
    this.name = name;
    this.books = [];
  }
    hello(){
        return "It's a-me, " + this.name + "!";
    }
    addBook(book){
        this.books.push(book);
    }
    getBooks(){
        return this.books;
    }
}

let luigi = new Person("Luigi");
console.log(luigi.hello());
luigi.addBook("classSugar");
luigi.addBook("classType");
console.log(luigi.getBooks());
ix0qys7i

ix0qys7i3#

对于较长的链,请使用Object.assign,下面是使用Object.assign创建既是Person又是Student的GradStudent的示例

(function() {
  //Person
  function Person(name) {
    this.name = name;
  }
  Person.prototype.constructor = Person;
  Person.prototype.name = "";
  Person.prototype.hello = function() {
     return "Hello my name is " + this.name;
  };

  //Student
  function Student(name, books) {
    Person.call(this, name);
    this.books = books;
  }
  Student.prototype.constructor = Student;
  Student.prototype = Object.create(Person.prototype);
  Student.prototype.books = [];
  
  //GradStudent
  function GradStudent(name, books, degree) {
    Person.call(this, name);
    Student.call(this, name,books);
    this.degree = degree;
  }
  GradStudent.prototype.constructor = GradStudent;
  GradStudent.prototype = Object.create(Person.prototype);
  Object.assign(GradStudent.prototype, Student.prototype);
  GradStudent.prototype.degree = "";
  
  
  var gradStudent = new GradStudent("bill",["C", "C++", "JavaScript"], "B.S.");
  console.log(gradStudent.hello() + " I have a " + gradStudent.degree +" I am studying " + gradStudent.books.toString()  );

})();
ycl3bljg

ycl3bljg4#

我可以用以下方法来完成这样的事情:

function Student(name) {
    Object.setPrototypeOf(this, new Person(name));
    this.books = [];
}

然而,我对javascript不够熟悉,不知道这个解决方案可能会出现什么问题,来自其他OO风格的语言,marioprototype作为Person的实际示例感觉很奇怪,但我认为js中的所有东西在某种意义上都是示例,所以这可能只是我的偏见。

相关问题