//一.原型链示例 //第一种方式:可能会对对象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';
javascript 继承
最新推荐文章于 2023-03-06 16:41:59 发布