JavaScript继承

来源:互联网 发布:crocs洞洞鞋淘宝 编辑:程序博客网 时间:2024/06/05 02:17

1)原型链

  ①原型链示例

function Shape() {    this.name = 'shape';    this.toString = function(){        return this.name;    }}function TwoDshape () {    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;    }}TwoDshape.prototype = new Shape();Triangle.prototype = new TwoDshape();   //用new新建对象实体,并赋值覆盖该对象的原型TwoDshape.prototype.constructor = TwoDshape;Triangle.prototype.constructor = Triangle; var my = new Triangle(5,10); my.getArea();       //25console.log(my.toString());//继承的方法,具体步骤(遍历my对象属性没有找到,接着查看my.__proto__所指向的对象,即new TwoDshape()创建的实体,//依然没找到,又继续查找该实体的__proto__所指向的对象,即new Shape()所创建的实体,找到toString方法,并在my对象中被调用,this指向my)//通过instanceof操作符,我们可以验证my对象同时是上面三个构造器的实例my instanceof Shape;          //truemy instanceof  TwoDShape;     //truemy instanceof Triangle;      //true//我们也可以用其他两个构造器来创建对象,用new TwoDshape()所创建的对象也可以获得继承自Shape()的toString()方法var td = new TwoDshape();td.constructor === TwoDshape;   //true;td.toString();          // 2D shapevar s = new Shape();s.constructor === shape;    // true;

  

 ②将共享属性迁移到原型中去

function Shape(){this.name='shape'}//使用new Shape()新建对象,每个实体都有全新的属性并占用独立空间function Shape(){};Shape.prototype.name='shape';//属性移到原型后,使用new新建对象时,不再含自己独立的这个属性

  

2)只继承于原型

Triangle.prototype=Shape.prototype;//减少继承方法的查询步骤Triangle.prototype.name='Triangle';//修改子对象原型后父对象原型也随即被改,即再new Shape()新建对象时,新对象name为‘Triangl

  

  ②临时构造器——new F()

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);alert(my.getArea());//通过这种方法,我们仍然能保持住原型链my._proto_ === Triangle.prototype;              //truemy._proto_.constructor === Triangle;            //truemy._proto_._proto_ === TwoDshape.prototypr;        //truemy._proto_._proto_._proto_.constructor === Shape;_    //true//并且父对象的属性不会被子对象覆盖:var s = new Shape();s.name;    // shape//calling toString()"I am a" + new TwoDshape();     //I am a 2D shape                            

  

 3)uber—子对象访问父对象的方式

function Shape(){}Shape.prototype.name='shape';Shape.prototype.toString=function(){  var const = this.constructor;  return const.uber     ? this.const.uber.toString() + ',' + this.name     : this.name;}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;Triangle.uber=TwoDShape.prototype;Triangle.prototype.name='triangle';Triangle.prototype.getArea=function(){return this.side*this.height/2};var my=new Triangle(5,10)console.log(my.toString());//shape,2D shape,triangle

  

 4)将继承部分封装成函数

function extend (Child,Parent) {    var F = function () {};    F.prototype = Parent.prototype;    Child.prototype = new F();    Child.prototype.constructor = Child;    Child.uber = Parent.prototype;}extend(TwoDsgape,Shape);extend(Triangle,TwoDshape);

  

5)属性拷贝

/*属性拷贝执行的是对象原型的逐一拷贝,而非简单的原型链查询。  所以需要特别注意的是:    这种方法仅适用于包含基本数据类型的对象,    所有的对象类型(包括函数和数组)都是不可复制的,    因为他们只支持引用传递      */function extend2(Child,Parent){    var p = Parent.prototype;    var c = Child.prototype;    for(var i in p){        c[i] = p[i];    }    c.uber = p ;}

  

6)小心处理引用拷贝

var A=function(){},B=function(){};A.prototype.stuff=[1,2,3];A.prototype.name='a';extend2(B,A);//让B继承A使用方法二B.prototype.name+='b';//ab,A.prototype.name依然为a,因为拷贝的是值B.prototype.stuff.push(4);//此时A和B原型上的stuff同时被修改,因为拷贝的是应用B.prototype.stuff=['a','b','c']//如果完全重写事情就不一样了,A为原来,B为新的

  

7)对象之间的继承(不使用构造器)

function extendCopy (p) {    var c = {};    for (var i in p){        c[i] = p[i];    }    c.uber = p;    return c;}var shape ={    name = 'shape',    toString :function () {        return this.name;    }}var twoDee = extendCopy(shape);twoDee.name = '2D shape';twoDee.toString = function () {    return this.uber.toString() + ',' + this.name;}//下面我们让triangle对象继承一个2D图形对象var triangle = extendCopy(twoDee);triangle.name = 'Triangle'triangle.getArea = function () {    return this.side * this.height / 2;}//使用triangletriangle.side = 5;triangle.height = 10;triangle.getArea();          //25triangle.toString();        // shape,2D shape,Triangle

  

8)深拷贝(当遇到对象类型时,再次调用拷贝)

function deepCopy(p,c){    c = c || {};    for (var i in p){        if(p.hasOwnProperty(i)){            if(typeof p[i] === 'object'){                c[i] = Array.isArray(p[i]?[]:{});                deepCopy(p[i],c[i]);            }else{                c[i] = p[i]            }        }    }    return c;}var parent = {    numbers:[1,2,3],    letters:['a','b','c'],    obj:{        prop : 1    },    bool : true};//我们分别用深拷贝和浅拷贝测试一下,就会发现两者的不同。//在深拷贝中,对对象的numbers属性进行更新不会对原对象产生影响。var mydeep = deepCopy(parent);var myshallow = extendCopy(parent);mydeep.numbers.push(4,5,6);mydeep.numbers     //[1,2,3,4,5,6]parent.numbers     //[1,2,3]myshallow.numbers.push(10);myshallow.numbers   //[1,2,3,10]parent.numbers      //[1,2,3,10]

  

9)object()(用object函数来接受父对象,并返回一个以该对象为原型的新对象)

function object(o){  var n;  function F(){}  F.prototype=o;  n=new F();  n.uber=o;  return n;}//这个函数与extendcopy基本相同

  

10)原型继承与属性拷贝的混合应用

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用于拷贝方法与属性

  

11)多重继承(一个对象中有不至一个父对象的继承)

function multi(){  var n={},stuff,j=0,len=arguments.length;  for(j=0;i<len;j++){    stuff=arguments[j];    for(var i in stuff){n[i]=stuff[i]}  }  return n;}//内层循环用于拷贝属性,外层循环用于遍历多个父对象参数,若有相同属性后面替代之前

  

12) 寄生式继承

13)构造器借用

待续...

 

原创粉丝点击