JavaScript中,继承的对象函数并不是通过复制而来,而是通过原型链继承(通常被称为 原型式继承 —— prototypal inheritance)。
1.创建父类Person,并给Person函数的原型(prototype)添加了greeting和copy的方法。
// copy返回的其实是 new Person.prototype.constructor()
function Person(first, last, age) {
this.name = {
first,
last
};
this.age = age;
}
Person.prototype.greeting = function() {
alert('Hi! I\'m ' + this.name.first + '.');
};
Person.prototype.copy = function() {
return new this.constructor(this.name.first, this.name.last, this.age);
};
2. 创建Teacher继承Person(构造器和原型(prototype)的引用)。
2.1 Teacher继承Person构造器,并且添加了Teacher构造器属性subject
function Teacher (first, last, age, subject) {
Person.call(this, first, last, age); //继承Person构造器属性
this.subject = subject || '';
}
2.2 Teacher继承Person的原型(prototype)
Teacher.prototype = Person.prototype;
或者 (没有明白为什么要这样)
Teacher.prototype = Object.create(Person.prototype);
//Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
Teacher.prototype.constructor = Teacher;
每一个函数对象(Function
)都有一个prototype
属性,并且只有函数对象有prototype
属性,因为prototype
本身就是定义在Function
对象下的属性。当我们输入类似var person1=new Person(...)
来构造对象时,JavaScript实际上参考的是Person.prototype
指向的对象来生成person1
。另一方面,Person()
函数是Person.prototype
的构造函数,也就是说Person===Person.prototype.constructor
(不信的话可以试试)。
在定义新的构造函数Teacher
时,我们通过function.call
来调用父类的构造函数,但是这样无法自动指定Teacher.prototype
的值,这样Teacher.prototype
就只能包含在构造函数里构造的属性,而没有方法。因此我们将Person.prototype
作为Teacher.prototype
的原型对象,使之与Teacher
关联。
任何您想要被继承的方法都应该定义在构造函数的prototype
对象里,并且永远使用父类的prototype
来创造子类的prototype
,这样才不会打乱类继承结构。
2.3 实例化Teacher对象,如果Person属性修改了的话,Teacher也会同步更新
//为Person添加了一个新的原型方法setName
Person.prototype.setName = function (g) {
this.gender = g
}
var a = new Teacher();
console.log(a);
/*
* 打印结果如下
* {
* name: {},
* age: undefined,
* gender: undefined,
* interests: undefined,
subject: "",
_proto: {
greeting: fn(),
copy: fn (),
setName: fn(),
constructor: ƒ Teacher(first, last, age, gender, interests, subject)
__proto__: Object
}
* }
*/
3. 错误原型继承: 这里this.propotype = Person.prototype;只是添加了一个构造器属性prototype,并不是对Person原型的继承
function Teacher (first, last, age, subject) {
Person.call(this, first, last, age); //继承Person构造器属性
this.propotype = Person.prototype;
this.subject = subject || '';
}
Teacher.prototype.greeting = function () {
alert('ddddd')
}
var a = new Teacher();
console.log(a);
/*
* 打印结果如下
* {
* name: {},
* age: undefined,
* gender: undefined,
* interests: undefined,
subject: "",
_proto: { //依旧是Teacher的原型,而不是Person的原型
constructor: ƒ Teacher(first, last, age, gender, interests, subject)
__proto__: Object
},
prototype: { // 因为this.prototype = Person.prototype, 通过实例a调用的时候,this指代的实例a,相当于给a添加了一个新的属性prototpye,并不是修改了Teacher的原型
greeting: fn(),
copy: fn(),
constructor: ƒ Person(first, last, age, gender, interests, subject),
__proto__: {}
}
* }
*/