2017.01.22更新 原型式继承 、寄生式继承,寄生组合继承
开头语:昨天放假一天,原本计划出去爬山,却躺了一天,无语~~~
原型式继承,上代码
var ob = {name:"小明",friends:['小明','小白']};
//原型式继承 参数o,引用类型值,实质就是一个内存地址
function object(o){
function F(){}//创建一个构造函数F
F.prototype = o;
return new F();
}
var ob1 = object(ob);
ob1.name = "小小";
ob1.friends.push("小黑");
var ob2 = object(ob);
console.log(ob2.named);//小明
console.log(ob2.friends);//小明,小白,小黑
上关系图
第一个问题:为什么ob2.named还是小明
答:虽然ob1修改了name 值,但是这是在ob1自身添加了一个name值,在原生对象(ob)并没有改变,所以name还是小明
第二个问题 ob1.friends.push("小黑");console.log(ob2.friends);//小明,小白,小黑ob2没有添加小黑,为什么也随着ob1的变化而变化了。
答:ob1先从自身查找friends,发现没有找到,然后又从原型里查找 ,发现在原型里有这个值,然后追加,以为ob1和ob2共享了一个原型,所以当ob1修改的时候,ob2也发生了变化。
寄生式继承
var ob = {name:"小明",friends:['小花','小白']};
function object(o){
function F(){}//创建一个构造函数F
F.prototype = o;
return new F();
}
//上面再ECMAScript5 有了一新的规范写法,Object.create(ob) 效果是一样的
function createOb(o){
var newob = object(o);//创建对象
newob.sayname = function(){//增强对象
console.log(this.name);
}
return newob;//指定对象
}
var ob1 = createOb(ob);
ob1.sayname();//小明
寄生式组合继承(据说是最好用的继承方式)
//寄生继承 创建一个新的对象返回一个新实例
function object(o){
function F(){}
F.prototype = o;
return new F();
}
//父层,超级层
function Father(name){
this.name = name;
this.friends= ["小花","小草"];
}
Father.prototype.sayname = function(){
console.log(this.name);
}
function Child(name,age){
father.call(this,name);//继承属性
this.age = age;
}
//继承父层的prototype
function inheritPrototype(child,father){
var prototype = object(father.prototype);//返回一个新实例(对象)
prototype.constructor = child;//增强对象
child.prototype = prototype;
}
inheritPrototype(Child,Father);//继承父层的原型
Child.prototype.sayage = function(){
console.log(this.age);
}
var c1 = new Child("小白",20);
c1.friends.push("小小");
c1.sayname();//小白
c1.sayage();//20
var c2 = new Child("小蓝",23);
c2.sayname();//小蓝
c2.sayage();//23
console.log(c2.friends);//"小花","小草"
上关系图
继承也是面向对象的一个重点,能理解里面的知识,对以后大型项目的编程和代码的复用,有很大的好处,到此结束。
----------------------------------------华丽丽且风骚的分割线-------------------------
开头语,昨天下了一夜的雪,天气很冷~~~,鞋底和雪的摩擦,沙沙的声音,甚是好听,上班的路上,一路踩过啦,得出结论,声音很美妙,但是不能听多了,为啥,听多了,鞋子就湿了。早上又复习了一下js的继承,今天先讲三种方式,原型链继承,借用构造函数继承,两者结合的继承。
原型继承上案例
//首先声明一个最顶层
Function Father(name){
this.name = name;
}
father.prototype.father = function(){
console.log(this.name);
}
//实例化
new Father("小花");
这是我们常见创建类用构造函数加原生的构建方式
下面我们画一下它们的关系图

其中__proto__是一个隐形属性,每个浏览器支持的并不一样,原理都是一样的,当我们实例化一个对象后,先从自身属性里找name,找到了就结束了,找不到在从__proto__指向的prototype对象找,继续往下看
//声明一个子类
function Child(age){
this.age = age;
}
//把Father实例化赋给Child.prototype
Child.prototype = new Father();
Child.prototype.sayage = function(){
console.log(this.age);
}
接下来我们看一下他们的关系图

通过这种方式就实现了原型(prototype)链上面的继承.,实例化之后,我们看一下关系网
//实例化
var c1 = new Child("16");
c1.sayname();//undefined

当我们执行c1.sayname();时候,首先自身属性里找,有没有这个方法,发现没有,然后通过__proto__自动查找prototype对象,然后还是没有找到,然后从new Father()里的__proto__里找prototype对象,发现存在这个函数,里面this.name找法一样,找到后发现没有赋值,然后输出undefined 。至此结束,这个整个流程就被成为原型链继承.
原型链继承.第一个问题,当实例化之后,实例修改原型属性时,会影响其他的实例属性,我们使用原型对象的原因就是,原型能在各个实例中共享属性和方法,当然,这也在一些情况下会出现问题。还是上面的例子,我们改造一下
Function Father(name){
this.name = name;
this.num = ['12'];
}
father.prototype.father = function(){
console.log(this.name);
}
function Child(age){
this.age = age;
}
//把Father实例化赋给Child.prototype
Child.prototype = new Father();
Child.prototype.sayage = function(){
console.log(this.age);
}
var c1 = new Child("16");
c1.num.push("13");
console.log(c1.num);//12,13;
var c2 = new Child("17");
console.log(c2.num);//12,13
通过上面的例子,我们发现,虽然没有给c2.num执行操作,但还是收之前实例化操作的影响,假如说你就是为了实现这样,那当然没问题,多数情况下,我们不希望各个实例之间相互影响。
原型链继承.第二个问题,我们创建子类型实例的时候,不能给父类型的构造函数传递参数,或者说,在不影响其他实例的情况下不能传参数。
基于上面的种种问题,我们引出了第二种继承方式:借用构造函数的方式
翠花,上代码~~~
function Father(){
this.num = ['12'];
}
function Child(){
//继承father
Father.call(this);
}
var c1 = new Child();
c1.num.push(13);
console.log(c1.num);//12,13
var c2 = new Child();
console.log(c2.num);//12
通过这种方式,每一个实例都有自己的一份属性和方法,不受其他的实例所影响,我们想到代码的复用问题,所以这种方式还是不完美,接着引出下一种继承方式:组合继承
组合继承就是把前面的两者中方式结合起来,让属性值不受影响,让方法复用
翠花,上代码~~
Function Father(name){
this.name = name;
this.num = ['12'];
}
father.prototype.father = function(){
console.log(this.name);
}
function Child(age,name){
Father.call(this,name);//继承属性
this.age = age;
}
Child.prototype = new Father();//继承方法
Child.prototype.constructor = Child;
Child.prototype.sayage = function(){
console.log(this.age);
}
var c1 = new Child(16,"小花");
c1.sayage();//16
c1.sayname();//小花
c1.num.push(13);
console.log(c1.num)//12,13
var c2 = new Child(18,"小明");
c2.sayage();//18
c2.sayname();//小明
console.log(c2.num)//12
附上关系图
到这里三种继承方式都讲完了,来来干了这碗酸菜.