欢迎访问 生活随笔!

凯发ag旗舰厅登录网址下载

当前位置: 凯发ag旗舰厅登录网址下载 > 前端技术 > javascript >内容正文

javascript

javascript | 继承 -凯发ag旗舰厅登录网址下载

发布时间:2024/10/12 javascript 38 豆豆
凯发ag旗舰厅登录网址下载 收集整理的这篇文章主要介绍了 javascript | 继承 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

—————————————————————————————————————————————————————————

继承 - ecmascript只支持实现继承(依靠原型链),不支持接口继承(函数没有签名)

原型链

  • 利用原型让一个引用类型继承另一个引用类型的属性和方法,
  • 构造函数、原型、实例的关系:每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针。实例包含一个指向原型对象的内部指针,在创建实例之后即指向原型对象
  • 而当a原型对象的指针指向b个原型对象时(此时a原型对象与b实例同级),就形成了一条原型链。
  • 图解:

    原型搜索机制:当读取模式访问一个实例属性时,首先会在实例中搜索该属性,如果没有找到该属性则沿着原型链向上查找

    在例子中,调用instance.getsupervalue(),先搜索实例instance,再搜索subtype.prototype,再搜索supertype.protorype,最后一步才找到该方法。

    默认的原型:所有的引用类型默认都继承了object,所以默认原型的指针都会指向object.prototype,完整的原型链如下:

    instance subtype.prototype supertype.prototype object.prototype

  • p.s.

    必须替换掉实例的原型后才能给实例添加方法

    不能使用对象字面量创建原型方法,这样做会重写原型链,如

  • 缺点:

    包含引用类型值(function object array)的原型属性会被所有实例共享,在通过原型来实现继承时,原型实际上会变成另一个类型的实例,所以原先的实例属性就变成了现在的原型属性了。

    在创建子类型的实例时,不能向超类型的构造函数中传递参数。

// "use strict";// demo - 1 // supertype 拥有一个属性和一个方法 // subtype 拥有一个属性和一个方法,又从supertype那里继承了一个属性一个方法 function supertype(){this.property = "111"; } supertype.prototype.getsupervalue = function(){return this.property; } function subtype(){this.subproperty = "222"; } // p.s.new操作之前,subtype.prototype指向的是function,不允许为function()定义.getsubvalue方法,所以要将添加方法放在修改原型指向之后 // 操作之后subtype.prototype指向supertype subtype.prototype = new supertype(); subtype.prototype.getsubvalue = function(){ // 必须在subtype替换原型之后才能定义return this.subproperty; } var instance = new subtype(); console.log(instance.property); // 111 console.log(instance.getsupervalue()); // 111 console.log(instance.subproperty); // 222 console.log(instance.getsubvalue()); // 222 console.log(instance.constructor); // f supertype(){} 原本subtype中的constructor属性被重写 // 重写supertype.getsupervalue() // 如果要重写这个方法,会屏蔽原来的方法 // 换句话说,当通过subtype的实例调用getsupervalue时调用的就是这个重新定义的方法,但通过supertype的实例调用时还会继续调用原来的方法 var beforerewrite = new supertype(); supertype.prototype.getsupervalue = function(){console.log("rewrite"); } console.log(instance.getsupervalue()); // rewrite,this.property = undefined console.log(supertype.prototype.getsupervalue()); // rewrite,this.property = undefined console.log(beforerewrite.getsupervalue());// demo - 2 // 确认原型和实例的关系 console.log(instance instanceof object); // true console.log(instance instanceof supertype); // true console.log(instance instanceof subtype); // true // 另一种方法 console.log(object.prototype.isprototypeof(instance)); // true console.log(supertype.prototype.isprototypeof(instance)); // true console.log(subtype.prototype.isprototypeof(instance)); // true// demo - 3 function supertype2(){this.property = "1111"; } supertype2.prototype.getsupervalue = function(){return this.property; } function subtype2(){this.subproperty = "2222"; } subtype2.prototype = new supertype2(); subtype2.prototype = {getsubvalue:function(){return this.subproperty;},someothermethod:function(){return false;} } var instance2 = new subtype2(); console.log(instance2 instanceof object); // true console.log(instance2 instanceof supertype2); // false,原型链被切断 console.log(instance2 instanceof subtype2); // true // console.log(instance2.getsupervalue()); // error// demo - 4 function supertype3(){this.colors = ["red","blue","green"]; } function subtype3(){} subtype3.prototype = new supertype3(); var instance3 = new subtype3(); instance3.colors.push("black"); console.log(instance3.colors); // ["red", "blue", "green", "black"] var instance4 = new subtype3(); console.log(instance4.colors); // ["red", "blue", "green", "black"]

 

借用构造函数(伪造对象 / 经典继承)

  • 在子类型构造函数的内部调用超类型构造函数
  • 优点:

    解决了单独使用原型链共享引用类型值属性的问题

    可以在子类型构造函数中向超类型构造函数传递参数

  • 缺点:

    无法避免构造函数模式存在的问题:方法都在构造函数中定义,无法实现函数复用

// "use strict";function supertype(name) {this.name = name;this.colors = ["111", "222", "333"]; }function subtype() {supertype.call(this, "name1");this.age = 20; }var instance = new subtype(); instance.colors.push("444"); console.log(instance.colors); // ["111", "222", "333", "444"] console.log(instance.name); // name1 console.log(instance.age); // 20 var instance2 = new subtype(); console.log(instance2.colors); // ["111", "222", "333"]

 

组合继承(伪经典继承)

  • 将原型链和借用构造函数组合,使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承
  • 对应创建对象 <组合使用构造函数模式和原型模式>
  • 优点:最常用
  • 缺点:需要调用两次超类型构造函数,一次在创建子函数原型时,另一次在子函数构造函数内部。调用子类型构造函数时需要重写属性
// "use strict"; function supertype(name) {this.name = name;this.colors = ["111", "222", "333"]; } supertype.prototype.sayname = function() {console.log(this.name); }function subtype(name, age) {supertype.call(this, name); // 继承属性this.age = age; } subtype.prototype = new supertype(); // 继承方法 subtype.prototype.constructor = subtype; subtype.prototype.sayage = function() {console.log(this.age); } var instance1 = new subtype("hugh", 20); instance1.colors.push("444"); console.log(instance1.colors); // ["111", "222", "333", "444"] instance1.sayname(); // hugh instance1.sayage(); // 20 var instance2 = new subtype("dong", 21); console.log(instance2.colors); // ["111", "222", "333"] instance2.sayname(); // dong instance2.sayage(); // 21

 

原型式继承

  • 对应创建对象 <动态原型模式>
  • 没有使用严格意义上的构造函数,借助已有的对象创建新对象
  • 优点:

    在不想创建构造函数,只想让一个对象与另一个对象保持类似的情况下,原型式继承完全可以胜任

  • 缺点:

    包含引用类型值的属性始终都会共享,就像原型模式一样

// "use strict"; function object(o){function f(){} // 创建临时性构造函数f.prototype = o; // 将传入的对象作为构造函数的原型return new f(); // 返回临时类型的一个新实例 }var person = {name:"hugh",friends:["111",'222','333'] };var anotherperson = object(person); anotherperson.name = "dong"; anotherperson.friends.push("444");var yetanotherperson = object(person); yetanotherperson.name = "hehe"; yetanotherperson.friends.push("555");console.log(person.friends); // ["111", "222", "333", "444", "555"] console.log(person.name); // hugh console.log(anotherperson.friends); // ["111", "222", "333", "444", "555"] console.log(anotherperson.name); // dong console.log(yetanotherperson.friends); // ["111", "222", "333", "444", "555"] console.log(yetanotherperson.name); // hehe// 使用object.create()规范化原型式继承 // 以这种方式指定的任何属性都会覆盖原型对象上的同名属性 var otherperson1 = object.create(person); otherperson1.friends.push("666"); console.log(yetanotherperson.friends); // ["111", "222", "333", "444", "555", "666"] var otherperson2 = object.create(person,{name:{value:"test"} }); console.log(otherperson2.name);

 

寄生式继承

  • 对应创建对象 <寄生构造函数 / 工厂模式>
  • 创建一个仅用于封装继承过程的函数,在内部增强对象,最后返回对象
  • 示范集成模式时使用的object()函数不是必须的,任何能够返回新对象的函数都适用于此模式
  • 使用场景:在主要考虑对象而不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的模式
  • 缺点:无法做到函数复用,类似于构造函数模式
// "use strict"; function object(o) {function f() {} // 创建临时性构造函数f.prototype = o; // 将传入的对象作为构造函数的原型return new f(); // 返回临时类型的一个新实例 }function createanother(original) { // 接收的函数作为新对象基础的对象var clone = object(original);clone.sayhi = function() { // 添加新方法console.log('hi');};return clone; } var person = {name: "hugh",friends: ['111', '222', '333'] }; var person1 = createanother(person); person1.sayhi(); console.log(person1.name); console.log(person1.friends);

 

寄生组合式继承

  • 优点:

    最理想的继承范式

    解决组合继承重写属性的问题,只调用了一次supertype构造函数

    避免了在subtype.prototype上创建不必要的属性

    原型链保持不变

    能够正常使用instanceofisprototypeof()

"use strict"; function object(o) {function f() {}f.prototype = o;return new f(); }// 1.创建超类型原型的一个副本 // 2.为创建的副本添加constructor属性,弥补因重写原型而失去的属性 // 3.将新创建的对象(即副本)赋值给子类型的原型 function inheritprototype(subtype,supertype){var prototype = object(supertype.prototype); // 创建对象prototype.constructor = subtype; // 增强对象subtype.prototype = prototype; // 指定对象 } function supertype(name){this.name = name;this.colors= [1,2,3,4]; } supertype.prototype.sayname = function(){console.log(this.name); } function subtype(name,age){supertype.call(this,name);this.age = age; } inheritprototype(subtype,supertype); subtype.prototype.sayage = function(){console.log(this.age); }

转载于:https://www.cnblogs.com/hughdong/p/7264122.html

总结

以上是凯发ag旗舰厅登录网址下载为你收集整理的javascript | 继承的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得凯发ag旗舰厅登录网址下载网站内容还不错,欢迎将凯发ag旗舰厅登录网址下载推荐给好友。

  • 上一篇:
  • 下一篇:
网站地图