孩儿们,来继承为父的遗产吧,咳咳咳咳。开个玩笑。继承理解为取存在对象已有属性和方法的一种方式.,那么我们有几种方式可以实现呢。接下来请开始个人showtime。
- 1.原型链继承
原理:我们都知道在实例中查找该属性,如果找到了,返回该值,否则,通过__proto__找到原型对象,在原型对象中进行搜索,如果找到,返回该值,否则,继续向上进行搜索,直到找到该属性,或者在原型链中没有找到,返回undefined。
function Parent() {
this.name = '爸爸';
this.family = ['妈妈','哥哥'] //验证引用类型的属性会被所有实例共享
}
Parent.prototype.getName = function() {
console.log(this.name)
console.log(this.family )
}
function Child() {}
Child.prototype = new Parent();
var child = new Child();
child.getName() // '爸爸' ["妈妈", "哥哥"]
child.family.push('姐姐')
var child2 = new Child();
child2.getName() // '爸爸' ["妈妈", "哥哥", "姐姐"]
给你们画个灵魂图你们就知道了为啥是这样的结果 --。--
缺点: 引用类型的属性会被所有实例共享,在创建Child实例时不能想Parent传参
- 2 借用构造函数(经典 经典 经典 重要的事情说三遍)
function Parent (name) {
this.name = name;
this.family = ['妈妈','哥哥']
this.getName = function() {
console.log(this.name)
console.log(this.family)
}
}
function Child(name) {
Parent.call(this,name) //重点是这个哦
}
var child = new Child(爸爸)
child.getName() // '爸爸' ["妈妈", "哥哥"]
child.family.push('姐姐')
var child2 = new Child('我');
child2.getName() // '我' ["妈妈", "哥哥"]
我们明显的可以看到了与上一个相比避免了引用类型的属性被所有实例共享,而且我们还可以从Child中向Parent传参哦
- 3 组合继承(双剑合并来了)
function Parent(name) {
this.name = name;
this.family = ['妈妈','哥哥']
}
Parent.prototype.getName = function () {
console.log(this.name)
console.log(this.family)
}
function Child(name) {
Parent.call(this,name)
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
var child1 = new Child('我');
child1.family.push('爸爸');
child1.getName(); // 我 ["妈妈", "哥哥", "爸爸"]
var child2 = new Child('你')
child2.getName(); // 你 ["妈妈", "哥哥"]
console.log(Child.prototype.constructor)
优点怎么说,集两家之长吧,是JavaScript中最常用的继承模式(ps:你觉得到这就可以了吧,呵呵,你还太年轻了往下看)。
- 4原型式继承 (不是原型链继承哦)
function createObj(o) {
function F(){};
F.prototype= o;
return new F();
}
var parent = {
name : '我',
family : ['妈妈','哥哥']
}
var child1 = createObj(parent);
var child2 = createObj(parent);
console.log(child1.name); // 我
child1.name = "你";
console.log(child2.name); // 我
// 注意这里并不是因为child1和child2有独立的name值,而是因为child1.name直接给
// child1添加了属性,并没有去影响原型上的name值
console.log(child1.family ); //["妈妈", "哥哥"]
child1.family.push('爸爸');
console.log(child2.family ); // ["妈妈", "哥哥", "爸爸"]
简单理解就是把传入的对象变成了创建对象的原型,然后返回这个对象,就类似与我把对象的prototype写成了一个参数。
- 5 寄生组合式继承 -------------------------快疯了--------------------------
创建一个仅用于封装继承过程的函数,该函数在内部以某种方式增强对象(给对象添加属性和方法), 然后返回该对象
function createObj(o) {
var clone = Object.create(o);
clone.say = function () {
console.log('我是新增的方法咯')
}
return clone;
}
有木有感觉和原型式继承差不多,不过上一个是修改创建对象的原型,这个是直接修改对象的属性和方法。
缺点: 每次创建对象都会创建一遍方法
6 寄生组合式继承
我们重顾一下
孩儿们,来继承为父的遗产吧,咳咳咳咳。开个玩笑。继承理解为取存在对象已有属性和方法的一种方式.,那么我们有几种方式可以实现呢。接下来请开始个人showtime。1.原型链继承
原理:我们都知道在实例中查找该属性,如果找到了,返回该值,否则,通过__proto__找到原型对象,在原型对象中进行搜索,如果找到,返回该值,否则,继续向上进行搜索,直到找到该属性,或者在原型链中没有找到,返回undefined。
function Parent() {
this.name = '爸爸';
this.family = ['妈妈','哥哥'] //验证引用类型的属性会被所有实例共享
}
Parent.prototype.getName = function() {
console.log(this.name)
console.log(this.family )
}
function Child() {}
Child.prototype = new Parent();
var child = new Child();
child.getName() // '爸爸' ["妈妈", "哥哥"]
child.family.push('姐姐')
var child2 = new Child();
child2.getName() // '爸爸' ["妈妈", "哥哥", "姐姐"]
给你们画个灵魂图你们就知道了为啥是这样的结果 --。--
缺点: 引用类型的属性会被所有实例共享,在创建Child实例时不能想Parent传参
- 2 借用构造函数(经典 经典 经典 重要的事情说三遍)
function Parent (name) {
this.name = name;
this.family = ['妈妈','哥哥']
this.getName = function() {
console.log(this.name)
console.log(this.family)
}
}
function Child(name) {
Parent.call(this,name) //重点是这个哦
}
var child = new Child(爸爸)
child.getName() // '爸爸' ["妈妈", "哥哥"]
child.family.push('姐姐')
var child2 = new Child('我');
child2.getName() // '我' ["妈妈", "哥哥"]
我们明显的可以看到了与上一个相比避免了引用类型的属性被所有实例共享,而且我们还可以从Child中向Parent传参哦
- 3 组合继承(双剑合并来了)
function Parent(name) {
this.name = name;
this.family = ['妈妈','哥哥']
}
Parent.prototype.getName = function () {
console.log(this.name)
console.log(this.family)
}
function Child(name) {
Parent.call(this,name)
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
var child1 = new Child('我');
child1.family.push('爸爸');
child1.getName(); // 我 ["妈妈", "哥哥", "爸爸"]
var child2 = new Child('你')
child2.getName(); // 你 ["妈妈", "哥哥"]
console.log(Child.prototype.constructor)
优点怎么说,集两家之长吧,是JavaScript中最常用的继承模式(ps:你觉得到这就可以了吧,呵呵,你还太年轻了往下看)。
- 4原型式继承 (不是原型链继承哦)
function createObj(o) {
function F(){};
F.prototype= o;
return new F();
}
var parent = {
name : '我',
family : ['妈妈','哥哥']
}
var child1 = createObj(parent);
var child2 = createObj(parent);
console.log(child1.name); // 我
child1.name = "你";
console.log(child2.name); // 我
// 注意这里并不是因为child1和child2有独立的name值,而是因为child1.name直接给
// child1添加了属性,并没有去影响原型上的name值
console.log(child1.family ); //["妈妈", "哥哥"]
child1.family.push('爸爸');
console.log(child2.family ); // ["妈妈", "哥哥", "爸爸"]
简单理解就是把传入的对象变成了创建对象的原型,然后返回这个对象,就类似与我把对象的prototype写成了一个参数。
- 5 寄生组合式继承 -------------------------快疯了--------------------------
创建一个仅用于封装继承过程的函数,该函数在内部以某种方式增强对象(给对象添加属性和方法), 然后返回该对象
function createObj(o) {
var clone = Object.create(o);
clone.say = function () {
console.log('我是新增的方法咯')
}
return clone;
}
有木有感觉和原型式继承差不多,不过上一个是修改创建对象的原型,这个是直接修改对象的属性和方法。
缺点: 每次创建对象都会创建一遍方法
- 6 寄生组合式继承
我们重顾一下
function Parent(name) {
this.name = name;
this.family = ['妈妈','哥哥']
}
Parent.prototype.getName = function () {
console.log(this.name)
console.log(this.family)
}
function Child(name) {
Parent.call(this,name)
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
var child1 = new Child('我');
child1.family.push('爸爸');
child1.getName(); // 我 ["妈妈", "哥哥", "爸爸"]
var child2 = new Child('你')
child2.getName(); // 你 ["妈妈", "哥哥"]
console.log(Child.prototype.constructor)
发现我们会调用两次父构造函数。
一次是设置子类型实例原型的时候
Child.prototype = new Parent();
一次是创建子类型实例的时候
var child1 = new Child('我');
而其在这里我们也会调用一次Parent构造含糊
Parent.call(this,name)
那么我们怎么避免重复调用呢?加入我们是间接的让Child.prototype 访问到Parent.prototype呢
function Parent(name) {
this.name = name;
this.family = ['妈妈','哥哥']
}
Parent.prototype.getName = function () {
console.log(this.name)
console.log(this.family)
}
function Child(name) {
Parent.call(this,name)
}
// 关键在这
var F = function() {}
F.prototype = Parent.prototype;
child.protype = new F();
var child1 = nwe Child('我')
console.log(child)
这样是不是减少了一次调用父构造函数new Parent()
来我们封装一下这个继承方法
function object(o) {
function F() {};
F.prototype = o;
return new F();
}
function prototype(child,parent) {
var prototype = object(parent.prototype);
prototype.constructor = child;
child.prototype = prototype;
}
prototype(Child,Parent);
而其还避免了在Parent.prototype上面创建不必要的多余的属性,于此同时,原型链还能保持不变。开发人员普遍认为寄生式组合式继承是引用类型最理想的继承范式。
有没有搞的头昏,最后一个,多看几遍 哈哈哈哈