JavaScript原型继承和原型链原理详解

这篇文章主要介绍了JavaScript原型继承和原型链原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

在讨论原型继承之前,先回顾一下关于创建自定义类型的方式,这里推荐将构造函数和原型模式组合使用,通过构造函数来定义实例自己的属性,再通过原型来定义公共的方法和属性。

这样一来,每个实例都有自己的实例属性副本,又能共享同一个方法,这样的好处就是可以极大的节省内存空间。同时还可以向构造函数传递参数,十分的方便。

这里还要再讲一下两种特色的构造函数模式:

1.寄生构造函数

从形式上来看,这种模式和工厂模式并无区别:

function Person(name, age, job) {
  var o = new Object();
  o.name = name;
  o.age = age;
  o.job = job;
  o.sayName = function() {
    alert(this.name);
  };
  return o;
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName(); //"Nicholas"

都是在内部创建一个Object对象实例,再赋予属性和方法,最后返回,这种构造模式的好处是,对于原生的引用类型创建的实例,例如Array,想为实例创建新的方法或者属性时,因为不建议直接修改原生的Array引用类型的构造函数,所以可以利用寄生构造函数:

function SpecialArray() {
  //创建数组
  var values = new Array();
  //添加值
  values.push.apply(values, arguments);
  //添加方法
  values.toPipedString = function() {
    return this.join("|");
  };
  //返回数组
  return values;
}
var colors = new SpecialArray("red", "blue", "green");
alert(colors.toPipedString()); //"red|blue|green"

通过在内部创建一个Array实例,并添加新的方法,最后将这个实例返回,既没有修改原生的Array构造函数,又成功添加了自定义的方法和属性。

缺点:使用寄生构造函数有一个缺点,那就是返回的实例与构造函数或构造函数原型属性之间没有关系,与在构造函数外创建实例没有区别,也无法通过instanceof来确定对象类型,因此有其他更好选择的时候,不推荐使用该方法。

2.稳妥构造函数

稳妥构造函数与寄生构造函数类似,但是并不使用new和this(某些环境下禁止使用),前面的函数可以改写成这样:

function Person(name, age, job) {
  //创建要返回的对象
  var o = new Object();

  //可以在这里定义私有变量和函数
  //添加方法
  o.sayName = function() {
    alert(name);
  };
  //返回对象
  return o;
}

说完这些,现在来谈谈原型继承和原型链,所谓继承,基本思想是利用原型让一个引用类型继承另一个引用类型的方法和属性。每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。所有引用类型默认都继承了Object,而这个继承也是通过原型链实现的。大家要记住,所有函数的默认原型都是Object 的实例,因此默认原型都会包含一个内部指针,指向Object.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;
}
//继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
  alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29
var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27

SuperType 构造函数定义了两个属性:name 和colors。SuperType 的原型定义了一个方法sayName()。SubType 构造函数在调用SuperType 构造函数时传入了name 参数,紧接着又定义了它自己的属性age。然后,将SuperType 的实例赋值给SubType 的原型,然后又在该新原型上定义了方法sayAge()。这样一来,就可以让两个不同的SubType 实例既分别拥有自己属性——包括colors 属性,又可以使用相同的方法了。

原型式继承(借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型)

var person = {
  name: "Nicholas",
  friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

在没有必要兴师动众地创建构造函数,而只想让一个对象与另一个对象保持类似的情况下,原型式
继承是完全可以胜任的。不过别忘了,包含引用类型值的属性始终都会共享相应的值,就像使用原型模
式一样。

寄生式继承(寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象)

function createAnother(original) {
  var clone = object(original); //通过调用函数创建一个新对象
  clone.sayHi = function() { //以某种方式来增强这个对象
    alert("hi");
  };
  return clone; //返回这个对象
}

寄生组合式继承

通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • JS学习笔记之原型链和利用原型实现继承详解

    本文实例讲述了JS学习笔记之原型链和利用原型实现继承.分享给大家供大家参考,具体如下: 原型链 原型链是一种关系,实例对象和原型对象之间的关系,关系是通过原型(__proto__)来联系的 实例对象中有__proto__,是对象,叫原型,不是标准的属性,浏览器使用,并且有的游览器不支持 构造函数中有prototype属性,也是对象,叫原型 注意 原型中的方法是可以互相访问的 实例代码 function Animal(name,age){ this.name=name; thia.age=age;

  • [js高手之路]从原型链开始图解继承到组合继承的产生详解

    于javascript原型链的层层递进查找规则,以及原型对象(prototype)的共享特性,实现继承是非常简单的事情 一.把父类的实例对象赋给子类的原型对象(prototype),可以实现继承 function Person(){ this.userName = 'ghostwu'; } Person.prototype.showUserName = function(){ return this.userName; } function Teacher (){} Teacher.protot

  • javascript 原型链维护和继承详解

    一.两个原型 很多人都知道javascript是原型继承,每个构造函数都有一个prototype成员,通过它就可以把javascript的继承演义的美轮美奂了. 其实啊,光靠这一个属性是无法完成javascript的继承. 我们在代码中使用的prototype完成继承在这里就不多说了.大家可以查一下资料. 另外一个看不见的prototype成员. 每一个实例都有有一条指向原型的prototype属性,这个属性是无法被访问到的,当然也就无法被修改了,因为这是维护javascript继承的基础. 复

  • 深入理解JS继承和原型链的问题

    对于那些熟悉基于类的面向对象语言(Java 或者 C++)的开发者来说,JavaScript 的语法是比较怪异的,这是由于 JavaScript 是一门动态语言,而且它没有类的概念( ES6 新增了class 关键字,但只是语法糖,JavaScript 仍旧是基于原型). 涉及到继承这一块,Javascript 只有一种结构,那就是:对象.在 javaScript 中,每个对象都有一个指向它的原型(prototype)对象的内部链接.这个原型对象又有自己的原型,直到某个对象的原型为null 为止

  • JavaScript继承基础讲解(原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承)

    说好的讲解JavaScript继承,可是迟迟到现在讲解.废话不多说,直接进入正题. 既然你想了解继承,证明你对JavaScript面向对象已经有一定的了解,如还有什么不理解的可以参考<面向对象JS基础讲解,工厂模式.构造函数模式.原型模式.混合模式.动态原型模式>,接下来讲一般通过那些方法完成JavaScript的继承. 原型链 JavaScript中实现继承最简单的方式就是使用原型链,将子类型的原型指向父类型的实例即可,即"子类型.prototype = new 父类型();&qu

  • 深入理解javascript原型链和继承

    在上一篇文章中,介绍了原型的概念,了解到在javascript中构造函数.原型对象.实例三个好基友之间的关系:每一个构造函数都有一个"守护神"--原型对象,原型对象心里面也存着一个构造函数的"位置",两情相悦,而实例呢却又"暗恋"着原型对象,她也在心里留存了一个原型对象的位置. javascript本身不是面向对象的语言,而是基于对象的语言,对于习惯了其他OO语言的人来说,起初有些不适应,因为在这里没有"类"的概念,或者说&q

  • JavaScript使用原型和原型链实现对象继承的方法详解

    本文实例讲述了JavaScript使用原型和原型链实现对象继承的方法.分享给大家供大家参考,具体如下: 实际上JavaScript并不是一门面向对象的语言,不过JavaScript基于原型链的继承方式.函数式语法,使得编程相当灵活,所以可以利用原型链来实现面向对象的编程. 之前对JavaScript一直都是一知半解,这两天看了一下原型链这一块知识,综合练习了一下JavaScript的对象继承方式. 以下就是原型链和原型的关系,引用网上的一张图 在Javascript中,每个函数都有一个原型属性p

  • js对象继承之原型链继承实例

    本文实例讲述了js对象继承之原型链继承的用法.分享给大家供大家参考.具体分析如下: 复制代码 代码如下: <script type="text/javascript"> //定义猫的对象 var kitty  = {color:'yellow',bark:function(){alert('喵喵');},climb:function(){alert('我会爬树')}}; //老虎对象的构造函数 function tiger(){  this.color = "ye

  • JavaScript原型继承和原型链原理详解

    这篇文章主要介绍了JavaScript原型继承和原型链原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在讨论原型继承之前,先回顾一下关于创建自定义类型的方式,这里推荐将构造函数和原型模式组合使用,通过构造函数来定义实例自己的属性,再通过原型来定义公共的方法和属性. 这样一来,每个实例都有自己的实例属性副本,又能共享同一个方法,这样的好处就是可以极大的节省内存空间.同时还可以向构造函数传递参数,十分的方便. 这里还要再讲一下两种特色的构造

  • JavaScript对象原型链原理详解

    这篇文章主要介绍了JavaScript对象原型链原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一个js对象,除了自己设置的属性外,还会自动生成proto.class.extensible属性,其中,proto属性指向对象的原型. 对象的属性也有writable.enumerable.configurable.value和get/set的配置方法. 对象的创建方式有三种: 一.使用字面量直接创建. 二.基于原型链创建. 分析上图,要点如

  • JavaScript滚动轮播图制作原理详解

    本文实例为大家分享了JavaScript滚动轮播图制作原理,供大家参考,具体内容如下 滚动轮播图 滚动轮播图布局关键:是所有图片并排在一起,所以unit的宽要足够宽.克隆第一张图片追加到最后一张右按钮拉动策略:先拉动,再瞬移左按钮拉动策略:先瞬移,再拉动与呼吸轮播图一样,需要做防流氓策略 复制代码:将我代码中的图片更换为你的图片,注意图片路径,还需要引入js库,我引入的是jquery-1.12.3.min.js的版本,引入的时候注意路径 举例: <!DOCTYPE html> <html

  • JavaScript设计模式之策略模式实现原理详解

    俗话说,条条大路通罗马.在现实生活中,我们可以采用很多方法实现同一个目标.比如我们先定个小目标,先挣它一个亿.我们可以根据具体的实际情况来完成这个目标. 策略模式的定义 定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换. 举个例子:表单校验 在一个Web项目中,注册.登录等功能的实现都离不开表单提交.表单校验也是前端常常需要做的事.假设我们正在编写一个注册的页面,在点击提交按钮之前,有如下几条校验逻辑: 用户名不可为空,不允许以空白字符命名,用户名长度不能小于2位. 密码长度不能小

  • Javascript数组及类数组相关原理详解

    数组创建方式有两种 1. var arr = [] 2. var arr = new Array() 如果只有一个参数会指定数组的长度,当一个参数时只能是整形,如下例子 var arr = new Array(10) var arr = new Array(10.2) //会报错 var arr = new Array(1, 2, 3) //arr = [1, 2, 3] 数组常用方法 改变原数组 push pop shift unshift sort reverse splice 不改变原数组

  • JavaScript原型及原型链终极详解

    JavaScript原型及原型链终极详解 一. 普通对象与函数对象 JavaScript 中,万物皆对象!但对象也是有区别的.分为普通对象和函数对象,Object,Function 是JS自带的函数对象.下面举例说明 function f1(){}; var f2 = function(){}; var f3 = new Function('str','console.log(str)'); var o3 = new f1(); var o1 = {}; var o2 =new Object()

  • Javascript 原型与原型链深入详解

    目录 前言 对象 原型 原型链 javascript中的类 new的实现 instanceof的实现 javascript的继承 总结 前言 在前端这块领域,原型与原型链是每一个前端 er 必须掌握的概念.多次在面试或者一些技术博客里面看见这个概念.由此可见,这个玩意对于前端来说有多重要.其实它本身理解起来不难,但是很多刚入行前端的同学,看到prototype.__proto__理解起来还是有点吃力,然后脑子里面就乱成一锅粥,就像我一样. 但是这是很正常的事情,没什么大不了的,就像我们想要学会跑

  • Go设计模式原型模式考查点及使用详解

    目录 前言 什么是原型模式 使用原型模式的目的 使用场景 利用原型模式实现文档树 总结 前言 如果一个类的有非常多的属性,层级还很深.每次构造起来,不管是直接构造还是用建造者模式,都要对太多属性进行复制,那么有没有一种好的方式让我们创建太的时候使用体验更好一点呢? 今天的文章里就给大家介绍一种设计模式,来解决这个问题. 这篇内容要说的是创造型设计模式里的原型模式,如果写过点 JS 代码的话,大家可能听说过原型链这么个东西,原型模式在 JavaScript 实现里确实广泛应用,它那个面向对象跟 J

  • JavaScript设计模式之职责链模式详解

    目录 职责链模式 1. 现实中的职责链模式 2. 实际开发中的职责链模式 3. 用职责链模式重构代码 4. 灵活可拆分的职责链节点 5. 异步的职责链 6. 职责链模式的优缺点 7. 用 AOP 实现职责链 8. 小结 职责链模式 职责链模式的定义是:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 职责链模式的名字非常形象,一系列可能会处理请求的对象被连接成一条链,请求在这些对象之间依次传递,直到遇

  • JS作用域作用链及this使用原理详解

    目录 变量提升的原理:JavaScript的执行顺序 第一部分:变量提升部分的代码 第二部分:代码执行部分 代码执行阶段 调用栈:栈溢出的原理 如何利用调用栈 1.使用浏览器查看调用栈的信息 2.小心栈溢出 块级作用域:var.let以及const 作用域 小结 作用域链和闭包 块级作用域中的变量查找 闭包 闭包怎么回收 小练 this:从执行上下文分析this 全局执行上下文的this 函数执行上下文的this 1.通过call 2.通过对象调用 3.通过构造函数设置 this的缺陷以及应对方

随机推荐