直接进入主题:javascript
继承的操做须要有一个父类,这里使用构造函数外加原型来建立一个:html
// super
function Person(name){
this.name = name;
}
Person.prototype.job = 'frontend';
Person.prototype.sayHello = function() {
console.log('Hello '+this.name);
}
var person = new Person('jia ming');
person.sayHello(); // Hello jia ming
复制代码
// 原型链继承
function Child() {
this.name = 'child';
}
Child.prototype = new Person();
var child = new Child();
console.log(child.job); // frontend
// instanceof 判断元素是否在另外一个元素的原型链上
// child是Person类的实例
console.log(child instanceof Person); // true
复制代码
关键点:子类原型等于父类的实例Child.prototype = new Person()
java
原型链的详细讲解本身以前有一篇文章说到深刻理解原型对象和原型链git
特色:github
注意事项:app
// 借用构造函继承
function Child() {
Person.call(this, 'reng');
}
var child = new Child();
console.log(child.name); // reng
console.log(child instanceof Person); // false
child.sayHello(); // 报错,继承不了父类原型上的东西
复制代码
关键点:用call
或apply
将父类构造函数引入子类函数(在子类函数中作了父类函数的自执行(复制))Person.call(this, 'reng')
frontend
针对call, apply, bind
的使用,以前有篇文章谈谈JavaScript中的call、apply和bind提到。函数
特色:post
注意事项:ui
组合继承是原型链继承和借用构造函数继承
的组合。
// 组合继承
function Child(name) {
Person.call(this, name);
}
Child.prototype = new Person();
var child = new Child('jia');
child.sayHello(); // Hello jia
console.log(child instanceof Person); // true
复制代码
关键点:结合了两种模式的优势--向父类传参(call)和复用(prototype)
特色:
注意事项:
// 先封装一个函数容器,用来承载继承的原型和输出对象
function object(obj) {
function F() {}
F.prototype = obj;
return new F();
}
var super0 = new Person();
var super1 = object(super0);
console.log(super1 instanceof Person); // true
console.log(super1.job); // frontend
复制代码
关键点:用一个函数包装一个对象,而后返回这个函数的调用,这个函数就变成了能够随意增添属性的实例或对象。Object.create()
就是这个原理。
特色:
注意事项:
**Object.create()方法规范了原型式继承。**这个方法接收两个参数,一个用做新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。
// 传一个参数的时候
var anotherPerson = Object.create(new Person());
console.log(anotherPerson.job); // frontend
console.log(anotherPerson instanceof Person); // true
复制代码
// 传两个参数的时候
var anotherPerson = Object.create(new Person(), {
name: {
value: 'come on'
}
});
anotherPerson.sayHello(); // Hello come on
复制代码
function object(obj) {
function F(){}
F.prototype = obj;
return new F();
}
var sup = new Person();
// 以上是原型式继承,给原型式继承再套个壳子传递参数
function subobject(obj) {
var sub = object(obj);
sub.name = 'ming';
return sub;
}
var sup2 = subobject(sup);
// 这个函数通过声明后就成了可增添属性的对象
console.log(sup2.name); // 'ming'
console.log(sup2 instanceof Person); // true
复制代码
关键点:就是给原型式继承外面套个壳子。
特色:
注意事项:
它跟组合继承同样,都比较经常使用。
寄生:在函数内返回对象而后调用
组合:
// 寄生
function object(obj) {
function F(){}
F.prototype = obj;
return new F();
}
// object是F实例的另外一种表示方法
var obj = object(Person.prototype);
// obj实例(F实例)的原型继承了父类函数的原型
// 上述更像是原型链继承,只不过只继承了原型属性
// 组合
function Sub() {
this.age = 100;
Person.call(this); // 这个继承了父类构造函数的属性
} // 解决了组合式两次调用构造函数属性的特色
// 重点
Sub.prototype = obj;
console.log(Sub.prototype.constructor); // Person
obj.constructor = Sub; // 必定要修复实例
console.log(Sub.prototype.constructor); // Sub
var sub1 = new Sub();
// Sub实例就继承了构造函数属性,父类实例,object的函数属性
console.log(sub1.job); // frontend
console.log(sub1 instanceof Person); // true
复制代码
重点:修复了组合继承的问题
在上面的问题中,你可能发现了这么一个注释obj.constructor = Sub; // 必定要修复实例
。为何要修正子类的构造函数的指向呢?
由于在不修正这个指向的时候,在获取构造函数返回的时候,在调用同名属性或方法取值上可能形成混乱。好比下面:
function Car() { }
Car.prototype.orderOneLikeThis = function() { // Clone producing function
return new this.constructor();
}
Car.prototype.advertise = function () {
console.log("I am a generic car.");
}
function BMW() { }
BMW.prototype = Object.create(Car.prototype);
BMW.prototype.constructor = BMW; // Resetting the constructor property
BMW.prototype.advertise = function () {
console.log("I am BMW with lots of uber features.");
}
var x5 = new BMW();
var myNewToy = x5.orderOneLikeThis();
myNewToy.advertise(); // => "I am BMW ..." if `BMW.prototype.constructor = BMW;` is not
// commented; "I am a generic car." otherwise.
复制代码
《JavaScript高级程序设计》
更多的内容,请移步个人博客,能给个赞就更好了😄