javascript 继承

//一.原型链示例
//第一种方式:可能会对对象constructor属性产生一定的负面影响
function Shape(){
    this.name = 'shape';
    this.toString = function(){
      return this.name;
    }
}

function TwoShape(){
    this.name = '2D Shape';
}

function Triangle(side,height){
    this.name = 'Triangle';
    this.side = side;
    this.height = height;
    this.getArea = function(){
        return this.side*this.height / 2;
    }
}

TwoShape.prototype = new Shape();
Triangle.prototype = new TwoShape();

var my  = new Triangle(5,10);
my.constructor;//function Shape() 因为没有对其相关的constructor进行重置,认为是Shape的构造函数
my instanceof  Shape;//true
my instanceof  TwoShape;//true
my instanceof Triangle; //true
my instanceof Array;//false

//将对象直接创建在TwoShape对象的prototype属性中,并没有去扩展这些对象的原有原型,用构造器Shape()另建了一个新的实体,然后用它去覆盖该对象的原型
//这样做的重点:javascript是一种完全依靠对象的语言,无类的概念,因而需要直接用new Shape()构造一个实体,才能通过该实体的属性完成相关的继承工作,而不是直接继承自
//Shape()构造器,这确保了在继承实现之后,我们对Shape()所进行的任何修改、重写以及删除,都不会影响TwoDShape()产生影响,因为我们所继承的只是由该构造器所创建的一个实体

//第二种,完成继承关系设定之后,对这些对象的constructor属性进行相应的重置 非常好的习惯
function Shape(){
  this.name = 'shape';
  this.toString = function(){
    return this.name;
  }
}

function TwoShape(){
  this.name = '2D Shape';
}

function Triangle(side,height){
  this.name = 'Triangle';
  this.side = side;
  this.height = height;
  this.getArea = function(){
    return this.side*this.height / 2;
  }
}

TwoShape.prototype = new Shape();
Triangle.prototype = new TwoShape();

TwoShape.prototype.constructor = TwoShape;
Triangle.prototype.constructor = Triangle;

var my = new Triangle(5,10);
my.getArea();//25
my.toString();//Triangle

my.constructor;//function Triangle(side, height) 相关的constructor进行重置,认为是Triangle的构造函数
my instanceof  Shape;//true
my instanceof  TwoShape;//true
my instanceof Triangle; //true
my instanceof Array;//false
Shape.prototype.isPrototypeOf(my);//true
TwoShape.prototype.isPrototypeOf(my);//true
Triangle.prototype.isPrototypeOf(my);//true
String.prototype.isPrototypeOf(my);//false

/*
* javascript引擎在my.toString()被调用时做的事
* 1.遍历my对象中的所有属性,没找到一个叫toString()的方法
* 2.查看my._proto_所指向的对象,该对象应该是在继承关系构建过程中由new TwoShape()所创建的实体
* 3.遍历TwoShape实体的过程中没有找到toString()方法,继续查找该实体的_proto_属性,该_proto_属性指向的实体由new Shape()所创建
* 4.在new Shape()所创建的实体中找到toString()方法
* 5.该方法就会在my对象中被调用,并且其this也指向了my
* */

//二.将共享属性迁移到原型中去
//1.不迁移到原型中,使某些不能通过实体改变的属性出现一些效率低下的情况
function Shape(){
    this.name = 'shape';
}
//用new Shape()新建对象时,每个实体都会有一个全新的name属性,并在内存中拥有自己的独立的存储空间

//2.添加到所有共享的原型对象中去,虽然效率有提高,但是也针对对象实体中不可变的属性而言或者不可变的方法
function Shape(){};
Shape.prototype.name = 'shape';
js代码示例
function Shape(){};
Shape.prototype.name = 'shape';
Shape.prototype.toString = function(){return this.name};

function TwoDShape(){};
TwoDShape.prototype = new Shape();
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = '2D shape';

function Triangle(side,height){
  this.side = side;
  this.height = height;
};
Triangle.prototype = new TwoDShape();
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function(){return this.side * this.height / 2;};

var my  = new Triangle(5,10);
my.getArea();//25
my.toString();//Triangle
my.hasOwnProperty('side');//true
my.hasOwnProperty('name');//true
TwoDShape.prototype.isPrototypeOf(my);//false
my instanceof  Shape//false

//三、只继承于原型
/*
* 1.不要单独为继承关系创建新对象
* 2.尽量减少运行时方法搜索,例如toString();
* */

js代码示例
function Shape(){};
Shape.prototype.name = 'shape';
Shape.prototype.toString = function(){return this.name};

function TwoDShape(){};
TwoDShape.prototype = Shape.prototype;
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = '2D shape';

function Triangle(side,height){
  this.side = side;
  this.height = height;
};
Triangle.prototype = TwoDShape.prototype;
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function(){return this.side * this.height / 2;};

var my = new Triangle(5,10);
my.getArea();//25
my.toString();//Triangle
Shape.prototype.name;//Triangle
var s = new Shape();
s.name;//Triangle

/*
 * javascript引擎在my.toString()被调用时做的事
 * 1.遍历my对象中的所有属性,没找到一个叫toString()的方法
 * 2.搜索该对象的原型属性,而此原型属性指向了TwoDShape的原型,TwoDShape的原型指向Shape.prototype,采用引用传递,只需两步
 * */
//副作用:子对象与父对象指向的是同一对象,子对象对其原型进行了修改,父对象也就随即被改变,继承关系亦如此

//临时构造器 --- new F()
//利用中介来打破这种连锁关系
js代码示例
function Shape(){};
Shape.prototype.name = 'shape';
Shape.prototype.toString = function(){return this.name};

function TwoDShape(){};
var F = function(){};
F.prototype = Shape.prototype;
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = '2D shape';

function Triangle(side,height){
  this.side = side;
  this.height = height;
};
var F = function(){};
F.prototype = TwoDShape.prototype;
Triangle.prototype = new F();
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function(){return this.side * this.height / 2;};

var my = new Triangle(5,10);
my.getArea();//25
my.toString();//Triangle
my.__proto__.__proto__.__proto__.constructor;//Shape()
var s = new Shape();
s.name;//shape
//尽量将要共享的属性与方法添加到原型中,然后只围绕原型构建继承关系


//四、uber---子对象访问父对象的方式
js代码示例
function Shape(){};
Shape.prototype.name = 'shape';
Shape.prototype.toString = function(){
    var result = [];
    if(this.constructor.uber){
        result[result.length] = this.constructor.uber.toString();
    }
    result[result.length] = this.name;
    return result.join(',');
};

function TwoDShape(){};
var F = function(){};
F.prototype = Shape.prototype;
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.uber = Shape.prototype;
TwoDShape.prototype.name = '2D shape';

function Triangle(side,height){
  this.side = side;
  this.height = height;
};
var F = function(){};
F.prototype = TwoDShape.prototype;
Triangle.prototype = new F();
Triangle.prototype.constructor = Triangle;
TwoDShape.uber = TwoDShape.prototype;
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function(){return this.side * this.height / 2;};

var my = new Triangle(5,10);
my.toString();//google下是不行的,待定
/*
* 1.将uber属性设置成了指向其父级原型的引用
* 2.对toString()方法进行了更新
* */

//五、继承部分封装为函数
js代码示例
function extend(Child,Parent){
  var F = function(){};
  F.prototype = Parent.prototype;
  Child.prototype = new F();
  Child.prototype.constructor = Child;
  Child.uber = Parent.prototype;
}

extend(TwoDShape,Shape);
extend(Triangle,TwoDShape);
var ss = new Triangle(5,10);
ss.toString();//shape
//YUI库实现继承关系时所采用的方法
//YAHOO.lang.extend(Triangle,TwoDShape);

//六、属性拷贝
js示例代码
function extend2(Child,Parent){
  var p = Parent.prototype;
  var c = Child.prototype;
  for(var i in p){
    c[i] = p[i];
  }
  c.uber = p;
}
/*
* 已经完成对child的原型进行扩展,无需再重置Child.prototype.constructor属性,因为它不会再被完全覆盖了,因此constructor属性所指向的值是正确的
* 仅适用于只包含基本数据类型的对象,所有的对象类型(包括函数与数组)都是不可复制的,因为它们只支持引用传递
* */

var Person = function(){};
var Men = function(){};
Person.prototype.name = 'person';
Person.prototype.toString = function(){return this.name;};

extend(Men,Person);

var td = new Men();
td.name;//person
Men.prototype.name;//person
td.__proto__.name;//person
td.hasOwnProperty('name');//false
td.__proto__.hasOwnProperty('name');//false

extend2(Men,Person);

var td = new Men();
td.name;//person
Men.prototype.name;//person
td.__proto__.name;//person
td.hasOwnProperty('name');//false
td.__proto__.hasOwnProperty('name');//true
td.__proto__.hasOwnProperty('toString');//true
td.__proto__.toString === Person.prototype.toString;//true

//七、对象之间的继承
js代码示例
//extendCopy是浅拷贝
function extendCopy(p){
  var c = {};
  for(var i in p){
    c[i] = p[i];
  }
  c.uber = p;
  return c;
}
//单纯的属性全拷贝是一种非常简单的模式,但适用范围很广,如Firebug后台有一个extend()函数,jQuery的早期版本,原型采取的就是这种基本模式
var animal ={
  name:'animal',
  toString:function(){
    return this.name;
  }
}

var twoDee = extendCopy(animal);
twoDee.name = 'dog';
twoDee.toString = function(){
  return this.uber.toString()+','+this.name;
};

var dog = extendCopy(twoDee);
dog.name='1dog';
dog.getName =function(){
  return this.name;
}

dog.toString();//"animal,dog,1dog"

//八、深拷贝
js代码示例
function deepCopy(p,c){
  var c = c || {};
  for(var i in p){
    if(typeof p[i] === 'object'){
      c[i] = (p[i].constructor === Array) ? []:{};
    }else{
      c[i] = p[i];
    }
  }
}
var Parent ={
    nums:[1,2,3],
    letters:['a','b','c'],
    obj:{
        prop:1
    },
    bool:true
};

var mydeep = deepCopy(parent);
var myshallow = extendCopy(parent);
mydeep.nums.push(4,5,6);
mydeep.nums;//[1,2,3,4,5,6]
parent.nums;//[1,2,3]
myshallow.nums.push(10);
myshallow.nums;//[1,2,3,10]
parent.nums//[1,2,3,10]
mydeep.nums;//[1,2,3,4,5,6]

//八、object() 原型继承
//只需将某个对象传递给它,并由此创建一个新对象。
js代码示例
function object(o){
    function F(){};
    F.prototype = o;
    return new F();
}

function object(o){
    var n;
    function F(){}
    F.prototype = o;
    n = new F();
    n.uber = o;
    return n;
}

//九、原型继承与属性拷贝的混合应用
/**
 * 继承目标:将一些现有功能归为己用
 * [1].使用原型继承的方式克隆现存对象
 * [2].而对其他对象使用属性拷贝的方式
 */
js代码示例
function objectPlus(o,stuff){
    var n;
    function F(){}
    F.prototype = o;
    n = new F();
    n.uber = o;
    for(var i in stuff){
        n[i] = stuff[i];
    }
    return n;
}
//对象o用于继承,对象stuff用于拷贝

//十、多重继承
//一个子对象继承多个父对象
js代码示例
function multi(){
    var n = {},stuff,j= 0,len = arguments.length;
    for(j = 0; j <len; j++){
        stuff = arguments[j];
        for(var i in stuff){
            n[i] = stuff[i];
        }
    }
    return n;
}

//十一、寄生式继承
//创建对象的函数中直接吸收其他对象的功能,然后对其进行扩展并返回
js代码示例
function triangle(s,h){
    var that = object(twoD);
    that.name = 'Triangle';
    that.getArea = function(){return this.side * this.height / 2;};
    that.side = s;
    that.heigth = h;
    return that;
}

//十二、构造器借用
js代码示例
function Shape(id){
    this.id = id;
}
Shape.prototype.name = 'shape';
Shape.prototype.toString = function(){return this.name;};
function Triangle(){
    Shape.apply(this,arguments);
}
Triangle.prototype.name = 'Triangle';
var t = new Triangle(101);
t.name;//Triangle
t.id;//101
t.toString();//[object object]

//稍作修改
function Triangle(){
    Shape.apply(this,arguments);
}
Triangle.prototype = new Shape();
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = 'Triangle';

//十三、借用构造器与原型复制
js代码示例
function Shape(id){
    this.id = id;
}
Shape.prototype.name = 'shape';
Shape.prototype.toString = function(){return this.name;};

function Triangle(){
    Shape.apply(this,arguments);
}
extend2(Triangle,Shape);
Triangle.prototype.name = 'Triangle';
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaobangsky

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值