js继承方法

前因:ECMAScript不支持接口继承,只支持实现继承

一、原型链

概念:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针,让这个原型对象(子的原型)等于要继承的引用类型(父)的实例,由于引用类型(父)的实例包含一个指向(父)原型对象的内部指针,以此类推,层层递进,便构成实例与原型的链条,即原型链。

基本思想:利用原型让(子)引用类型继承(父)引用类型的属性和方法

基本模式的代码(参考红宝书):

/*原型链继承*/
//父的引用类型,拥有一个property属性
function SuperType() {
this.property = true;
} //为(父)引用类型的原型对象添加一个getSuperValue方法
//由于原型对象都包含一个指向构造函数的指针(constructor指向其引用类型的指针),
//故其方法可以取到property属性的值
SuperType.prototype.getSuperValue = function () {
return this.property; //返回property的值
} //子的引用类型,拥有一个subproperty属性
function SubType() {
this.subproperty = false;
} //继承父类型,即SuperType,让子引用类型的原型对象指向父类型的实例
SubType.prototype = new SuperType(); //为(子)引用类型的原型对象添加一个getSubValue方法
SubType.prototype.getSubValue = function () {
return this.subproperty; //返回subproperty的值
} //实例示范
var instance = new SubType(); //该对象同时拥有SubType和SuperType里面的所有方法和属性
alert(instance.getSuperValue); //true
/*原型链继承*/

默认原型:所有函数的默认原型都是Object实例,所以都会继承toString()和valueOf()等默认方法

确定原型和实例的关系方法:

(1)通过使用instanceof()
如:alert(instance instanceOf Object); //true
(2)通过使用isPrototypeOf()

如:alert(Object.prototype.isPrototyOf(instance)); //true

注意点:

(1)给原型添加方法一定要放在替换原型的语句之后
(2)在通过原型链实现继承时,不能使用对象字面量创建原型方法

原型链存在的问题:

(1)子类型的所有实例都可以共享父类型的属性
(2)子类型的实例无法在不影响所有对象的情况下,给父类型的构造函数传递参数

二、借用构造函数继承(伪造对象或经典继承)

基本思想:在子类型构造函数的内部调用超类型构造函数(通过使用apply()和call()方法也可以在(将来)新创建的对象上执行构造函数);

代码(参考红宝书):

/*借助构造函数继承*/
// 父类型
function SuperType(){
this.colors = ["red","blue","green"];
} //子类型
function SubType(){
// 继承SuperType
SuperType.call(this);
} /*每执行new SubType()操作,都会在其实例环境下调用一次SuperType构造函数,
都会执行SuperType()函数中所定义的所有对象初始化代码,
因此,SubType的每个实例都会有自己的colors属性的副本*/
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black" var instance2 = new SubType();
alert(instance1.colors); //"red,blue,green" /*借助构造函数继承*/

存在问题:方法都在构造函数中定义,函数复用变得没有意义

补充:通过call()或者appla()调用父类型时,可以进行传参

三、组合继承(伪经典继承,原型链和借用构造函数技术组合)

基本思想:使用原型链实现对原型属性和方法的继承(主要想继承方法),而通过借用构造函数来实现对实例属性的继承(子类型的实例内部存在同名属性,从而对父类型的同名属性进行屏蔽);最后同时避免了原型链会被继承时会共享同一个父类型属性和借用构造函数的函数复用的缺陷

代码(参考红宝书):

 /*组合继承*/
// 父类型
function SuperType(name){
this.name = name;
this.colors = ["red","blue","green"];
} //设置父类型的sayName方法
SuperType.prototype.sayName = function () {
alert(this.name);
} // 子类型
function SubType(name,age) {
// 借用构造函数的方法继承"属性",该代码会在新建的实例里面添加和父类型相同的属性
SuperType.call(this,name);
this.age = age;
} // 通过原型链继承方法
SubType.prototype = new SuperType();
SubType.prototype.costructor = SubType; //原型对象指向构造函数的指针(constructor)
SubType.prototype.sayAge = function () {
alert(this.age);
} // 实例
var instance1 = new SubType("Jack",29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Jack"
instance1.sayAge(); // var instance2 = new SubType("Greg",27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg"
instance2.sayAge(); //
/*组合继承*/

缺点:两次调用父类构造函数:(第一次是在创建子类原型的时候,第二次是在子类构造函数内部) ;从而造成子类继承父类的属性,一组在子类实例上,一组在子类原型上(即在子类原型上创建不必要的多余的属性)

四、原型式继承

基本思想:借助原型可以基于已有的的对象创建新对象,即如在一个函数Object内部,先创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型(实际上执行了浅复制),最后返回这个临时类型的新实例。

代码(参考红宝书):

/*原型式继承*/
function object(o){
function F(){}; //创建临时性的构造函数(对象)
F.prototype = o; //浅复制(只将地址地址进行赋值)
return new F();
} // 例子如下:
var person = {
name:"Nicholas",
friends:["Shelby","Court","Van"]
} //新建一个anothorPerson对象(空的),原型指向person
var anothorPerson = object(person);
anothorPerson.name = "Greg"; //直接在anothorPerson里面创建name(基本类型),再进行赋值
/*在anothorPerson查找friends(引用类型),
没有找到则顺着原型向上(即继承的父类型)找,直到找到,否则报undefind*/
anothorPerson.friends.push("Rob"); var yetAnothorPerson = object(person);
yetAnothorPerson.name = "Linda";
yetAnothorPerson.friends.push("Barbie");
// anothorPerson和yetAnothorPerson共享person的friends
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
/*原型式继承*/

补充:ES5新增的Object.create()方法拥有和object()方法同样的效果,但是Object.create()方法接受两个参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性(会覆盖作新对象原型的对象上的同名属性)的对象

举例子如下:

// Object.create()
var person = {
name: "Nicholas",
friends:["Shelby","Court","Van"]
}; var anothorPerson = Object.create(person,{
name:{
value:"Greg"
}
}); alert(anothorPerson.name); //"Greg"
五、寄生式继承

基本思想:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象

代码(参考红宝书):

/*寄生式继承*/
function object(o){
function F(){}; //创建临时性的构造函数(对象)
F.prototype = o; //浅复制(只将地址地址进行赋值)
return new F();
} function createAnother(original){
var clone = object(original); //通过调用函数创建一个新对象
clone.sayHi = function () { //以某种方式来增强这个对象
alert("Hi");
};
return clone; //返回这个对象
} var person = {
name: "Nicholas",
friends:["Shelby","Court","Van"]
}; var anothorPerson = createAnother(person);
anothorPerson.sayHi(); //"Hi"
/*寄生式继承*/

缺点:不能做到函数复用导致降低效率

六、寄生组合式继承

概念:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

基本思想:没有必要为了指定子类型的原型而调用超类型的构造函数(函数复用),我们需要的是超类型原型的副本。本质:使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

代码(参考红宝书):

/*寄生组合式继承*/
function object(o){
function F(){}; //创建临时性的构造函数(对象)
F.prototype = o; //浅复制(只将地址地址进行赋值)
return new F();
} function inheritPrototype(subType,superType){
//创建对象,使用寄生式继承来继承超类型的原型
var prototype = object(superType.prototype);
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象,将结果指定给子类型的原型
} function SuperType(name){
this.name = name;
this.colors = ["red","blue","green"];
} SuperType.prototype.sayName = function () {
alert(this.name);
}; function SubType(name,age){
SuperType.call(this.name); //借用构造函数来继承属性
this.age = age;
} inheritPrototype(SubType,SuperType); //使用寄生式继承来继承方法 SubType.prototype.sayAge = function(t) {
alert(this.age);
};
/*寄生组合式继承*/

js继承的方式及其优缺点的更多相关文章

  1. js继承的方式

    深入理解继承的实现方式不仅仅有利于自己去造轮子,封装插件,更有利于我们去阅读一些框架的源码, 以下记录几种常见的继承方式 1. 原型链实现继承 function Father(){ this.name ...

  2. JS继承 实现方式

    JS中继承方式的实现有多种方法,下面是比较推荐的方法,其它继承方式可做了解: function object(o) { function F() {} F.prototype = o; return ...

  3. js 继承的方式

    //定义object的继承方法 Object.extend = function(destination, source) { for(property in source) { destinatio ...

  4. js面向对象编程(第2版)——js继承多种方式

    附带书籍地址: js面向对象编程(第2版)

  5. 【编程题与分析题】Javascript 之继承的多种实现方式和优缺点总结

    [!NOTE] 能熟练掌握每种继承方式的手写实现,并知道该继承实现方式的优缺点. 原型链继承 function Parent() { this.name = 'zhangsan'; this.chil ...

  6. JS继承的原理、方式和应用

    概要: 一.继承的原理 二.继承的几种方式 三.继承的应用场景 什么是继承? 继承:子类可以使用父类的所有功能,并且对这些功能进行扩展.继承的过程,就是从一般到特殊的过程.要了解JS继承必须首先要了解 ...

  7. js各种继承方式和优缺点的介绍

    js各种继承方式和优缺点的介绍 作者: default 参考网址2 写在前面 本文讲解JavaScript各种继承方式和优缺点. 注意: 跟<JavaScript深入之创建对象>一样,更像 ...

  8. JS实现继承的几种方式以及优缺点(转载)

    前言 JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一.那么如何在JS中实现继承呢?让我们拭目以待. JS继承的实现方式 既然要实现继承,那么首先我们得有一个父类,代码如下: // 定义一个 ...

  9. 三张图搞懂JavaScript的原型对象与原型链 / js继承,各种继承的优缺点(原型链继承,组合继承,寄生组合继承)

    摘自:https://www.cnblogs.com/shuiyi/p/5305435.html 对于新人来说,JavaScript的原型是一个很让人头疼的事情,一来prototype容易与__pro ...

随机推荐

  1. (考试大整理~)Xxy 的车厢调度

    这一题我以前研究过哈哈哈~ (train.cpp/c/pas) Description 有 一 个 火 车 站 , 铁 路 如 图 所 示 ,每辆火车从 A 驶入,再从 B 方向驶出,同时它的车厢可以 ...

  2. numpy中np.max() 和 np.maximum() 的区别

    np.max(a, axis=None, out=None, keepdims=False) # 接收一个参数a # 取a 在 axis方向上的最大值 np.maximum(x, y) # 接收两个参 ...

  3. jsPDF – 基于 HTML5 的强大 PDF 生成工具

    jsPDF 是一个基于 HTML5 的客户端解决方案,用于生成各种用途的 PDF 文档. 使用方法很简单,只要引入 jsPDF 库,然后调用内置的方法就可以了. 米扑科技项目用到了HHTML5生成PD ...

  4. JavaWeb_(Struts2框架)使用Struts框架实现用户的登陆

    JavaWeb_(Struts2框架)使用Servlet实现用户的登陆 传送门 JavaWeb_(Struts2框架)Servlet与Struts区别 传送门 MySQL数据库中存在Gary用户,密码 ...

  5. 【CSS】三栏/两栏宽高自适应布局大全

    页面布局 注意方案多样性.各自原理.各自优缺点.如果不定高呢.兼容性如何 三栏自适应布局,左右两侧300px,中间宽度自适应 (1) 给出5种方案 方案一: float (左右浮动,中间不用给宽,设置 ...

  6. shell编程-定时删除(30天)文件

    1.创建shell touch /opt/auto-del-30-days-ago.sh chmod +x auto-del-30-days-ago.sh 2.编辑shell脚本: vi auto-d ...

  7. python3笔记十六:python匿名函数和高阶函数

    一:学习内容 lambda函数 map函数与reduce函数 filter函数 sorted函数 二:匿名函数-lambda 1.概念:不使用def这样的语句去定义函数,使用lambda来创建匿名函数 ...

  8. c# 调用CMD命令并获取输出结果

    private static string CMDPath = Environment.GetFolderPath(Environment.SpecialFolder.System) + " ...

  9. char能不能存储一个汉字

    答案是肯定的 请参见博客:https://www.cnblogs.com/1017hlbyr/p/6419016.html

  10. 2018年第一记:EDM策略分享-EDM营销的策略分析

    很久没有上博客园来更新下文章了,一则因为工作繁忙,二则对技术方面的研究时间花的少了,目前主要侧重于EDM营销方面的策略制定.很多人跟我说,做EDM营销都茫然无头绪,那么做EDM到底有什么策略呢?下面博 ...