对javascript的原型,原型链和继承的个人理解

author author     2022-09-07     587

关键词:

继承是OO语言中一个最为人津津乐道的概念,也是初接触Javascript的初学者难理解的概念=。=继承主要分为两种:一种是接口继承,另一种是实现继承。而在ECMAScript中只支持实现继承,所以我们今天来讨论讨论实现继承。实现继承就是继承实际的方法,主要依靠原型链来实现。讲到这里我们就需要讨论讨论什么是原型链。

1、什么是原型

  要理解原型链我们首先要知道什么是原型。我们知道每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象包含所有实例共享的属性和方法。所以我个人觉得可以这么简单的理解:原型就是prototype属性。

  同时prototype属性有自己的prototype对象,而pototype对象肯定也有自己的constuct属性,construct属性有自己的constuctor对象,神奇的事情要发生了,这最后一个constructor对象就是我们构造出来的function函数本身!

 

2、关于prototype和_proto_

  (1).每个对象都具有一个名为__proto__的属性;

  (2).每个构造函数(构造函数标准为大写开头,如Function(),Object()等等JS中自带的构造函数,以及自己创建的)都具有一个名为prototype的方法(注意:既然是方法,那么就是一个对象(JS中函数同样是对象),所以prototype同样带有__proto__属性);

  (3).每个对象的__proto__属性指向自身构造函数的prototype;

  所以在大多数情况下我们可以这么认为:_proto_===constructor.prototype(某些情况除外,比如:通过Object.create()创建的对象不适用此等式)

3、原型链

  讲到这,到底什么是原型链呢?其实已经很明了了。由于每个对象都有_proto_属性,而在Javascript中万物皆对象,所以最终会形成一条由_proto_连起来的链条,递归访问最终会到头,最终的值为NULL。那么这条链条就是原型链。

  当Javascript引擎查找对象的属性时,先查找对象本身是否存在该属性,如果不存在,那么会在原型链上逐级查找。(但不会查找自身的prototype)

4、继承

  一、原型链式继承

    实现原型链继承有一种基础模式,代码如下:

function SuperType(){
    this.property=ture;
}
SuperType.prototype.getSuperValue=function(){
  return this.prototype;
};
function SubType(){
  this.subproperty=false;
}
SubType.prototype=new SubType();//继承了SuperType
SubType.prototype.getSubValue=function(){
  return this.subproperty;
};
var instance=new SubType();
alert(instance.getSuperValue());//true

 基础原型链继承虽然简单但是它有两个问题:1、在通过原型链继承时,原型实际上会变成另一个类型的实例。于是,原先的实例属性也就顺理成章地变成了现在的原型属性了。2、在创建子类型的实例时,不能向超类型的构造函数中传递函数。

  二、借用构造函数继承

  在子类型构造函数的内部调用超类构造函数,通过使用call()和apply()方法可以在新创建的对象上执行构造函数。

function SuperType() {
this.colors = ["red","blue","green"];
}
function SubType() {
SuperType.call(this);//继承了SuperType
}
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors);//"red","blue","green","black"
var instance2 = new SubType();
console.log(instance2.colors);//"red","blue","green"

  借用构造函数的问题:放大都在构造函数中,因此函数的复用就无从谈起。而且,在超类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式。

  三、组合继承

function Super(){
    // 只在此处声明基本属性和引用属性
    this.val = 1;
    this.arr = [1];
}
//  在此处声明函数
Super.prototype.fun1 = function(){};
Super.prototype.fun2 = function(){};
//Super.prototype.fun3...
function Sub(){
    Super.call(this);   // 核心
    // ...
}
Sub.prototype = new Super();    // 核心
 
var sub1 = new Sub(1);
var sub2 = new Sub(2);
alert(sub1.fun === sub2.fun);   // true

  为了解决借用构造函数继承的问题,组合继承应运而生。

  组合继承把实例函数都放在原型对象上,以实现函数复用。同时还要保留借用构造函数方式的优点,通过Super.call(this);继承父类的基本属性和引用属性并保留能传参的优点;通过Sub.prototype = new Super();继承父类函数,实现函数复用。

  组合继承避免了原型链继承和借用构造函数继承的缺点,融合了他们的优点:不存在引用属性共享问题,可传参,函数可复用。因此成为Javascript中最常见的继承模式。

  缺点:组合集成的最大问题是在无论什么情况下都会调用两次超类型构造函数。

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);//第一次调用SuperType()
    this.age=age
}
SubType.prototype=new SuperType();//第二次调用SuperType()
SubType.prototype.constructor=function(){
    alert(this.age);
};

  

  四、寄生式组合继承

    既然组合继承也有不足之处,那当然就需要弥补,于是就出现了寄生式组合继承。

寄生式组合继承的基本模式如下:

function inheritPrototype(subType,superType){
    var prototype=Object(superType.prototype);//创建对象
    prototypr.constructor=subType;//增强对象  弥补因重写原型失去的默认的constructor属性
  subType.prototype=prototype;//指定对象 将新创建的对象赋值给子类型的原型
}

这个示例中的inheritPrototype()函数实现了组合继承的最简单形式。我们可以调用inheritPrototype()函数区替换前面例子中的子类型原型赋值函数:

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);//第一次调用SuperType()
    this.age=age
}
inheritPrototype(Subtype,Supertype);
SubType.prototype.sayAge=function(){
    alert(this.age);
};

  这个例子的搞笑体现在只调用了一次Supertype构造函数,避免了在SubType.prototype上创建的不必要、多余的属性。与此同时还能保持原型链的不变;因此,还能正常使用instanceof和isPrototypeOf()。所以现在寄生式组合继承是最理想的继承方式。

 

PS:关于原型式继承和寄生式继承在这里就不多做解释了。大家可以自己去查相关的资料,不太推荐使用(个人观点)。

javascript中的原型链和继承

理解原型链在JavaScript的世界中,函数是一等公民。上面这句话在很多地方都看到过。用我自己的话来理解就是:函数既当爹又当妈。“当爹”是因为我们用函数去处理各种“粗活累活”(各种工具函数、页面交互、业务逻辑等... 查看详情

javascript常见继承方式

与传统的面向对象语言不同,JavaScript的继承主要是通过原型链和借用构造函数的方式实现。今天我们就来学习下在JavaScript中常见的四种继承实现方式,分别是:原型链继承、借用构造函数继承、组合继承以及Class类继承。原型... 查看详情

js继承之组合继承

...造函数的缺陷,融合了他们的优点,So,组合继承成为了JavaScript中最常用的继承模式。 查看详情

js原型链和继承的理解

...向Object并且会切断之前原型对象的联系,破坏原型链。3.JavaScript主要通过原型链实现继承。原型链的构建是通过将一个类型的实例赋值给另一个构造函数的原型实现的例子:xxx实例.p 查看详情

原型原型链和对象是怎么实现继承的

什么是原型?  声明函数时js会自动在你声明的函数对象(js一切皆对象)上挂载一些方法和属性 其中prototype属性就是  原型(也称为原型对象)如下图:这个原型对象里面保存着constructor自己的函数体(也就是Pro.prot... 查看详情

javascript中的经典继承与原型继承

】javascript中的经典继承与原型继承【英文标题】:classicalinheritancevsprototypalinheritanceinjavascript【发布时间】:2013-11-0703:56:34【问题描述】:我在Google上搜索了这么多链接,但对经典继承和原型继承之间的区别不太了解?我从中学... 查看详情

原型链和继承(代码片段)

1.原型链2.__proto__vsprototype2.1__proto__字面量构造法构造函数构造法Object.create构造法隐式原型2.2prototype显式原型2.3prototype和__proto__关系2.4constructor2.5画个图吧3.继承3.1构造函数继承3.2原型链继承3.3组合式继承3.4原型式继承3.5寄生式继... 查看详情

组合继承

组合继承,有时候也叫伪经典继承,指的是将原型链和借用构造函数的技术组合到一起,从而发挥两者之长的一种继承模式。组合继承的思路是使用原型链的方式实现对原型属性和方法的继承,而通过借用构造函数来实现对实例... 查看详情

组合继承介绍

组合继承有时候也叫伪经典继承,指的是将原型链和借用构造函数技术组合到一块,从而发挥二者之长的一种继承模式,其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。... 查看详情

javascript继承笔记

//原型(prototype):原型是一个对象,其他对象可以通过它实现属性继承 /*笔记: *1.类式继承:通过原型链继承的方式 *2.原型式继承:对类式继承的封装 *3.寄生式继承:对原型继承的二次封装,并且在第二次封装过程中对继... 查看详情

javascript中的原型与原型链

  一直对JavaScript的原型与继承不了解,参考《JavaScript权威指南(第六版)》和《JavaScript高级程序设计(第三版)》对这个点的知识做个整理,方便自己记忆。以下内容大部分摘录自这两本书每一个JavaScript对象都有与之相关的原型... 查看详情

javascript原型链污染学习记录(代码片段)

NodeJS原型机制,比较官方的定义:我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。1.JS原型和继承机制0>原型及... 查看详情

原型链和继承(代码片段)

1.构造函数与实例对象首先我做了如下测试varA=function(a)this.a=a;varb=‘b‘;varfn=function()alert(a);this.fn1=fn;;vara=newA(‘a‘);得到的结果是:a.a=“a”a.b.undefineda.fnundefineda.fn1ƒ() alert(‘b‘);  查看详情

javascript原型继承原型链(代码片段)

...形成三、例-求以下代码的输出总结前言部分理论参考《JavaScript权威指南》每一个对象都有与之相关的原型(prototype),原型是在实例创建之初就设定好的,作用是继承属性.使用new调用构造函数会自动创建一个新对象,因此构造函数本... 查看详情

浅话javascript的继承

javascript的继承和java或C#的继承是不一样的,后者是基于类的继承,而javascript是通过原型来继承的。所以,先得理一理原型是个什么鬼。 当一个函数对象被创建时,Function构造器产生的函数对象会运行类似这样一些代码:this.... 查看详情

javascript之继承(原型链)

JavaScript之继承(原型链)  我们知道继承是oo语言中不可缺少的一部分,对于JavaScript也是如此。一般的继承有两种方式:其一,接口继承,只继承方法的签名;其二,实现继承,继承实际的方法。JavaScript不支持签名,因此只... 查看详情

js继承《转》

...icle/55540.htmhttp://www.cnblogs.com/OceanHeaven/p/4965947.html深入理解javascript原型链和继承在上一篇文章中,介绍了原型的概念,了解到在javascript中构造函数、原型对象、实例三个好基友之间的关系:每一个构造函数都有一个“守护神&rd... 查看详情

javascript之继承(原型链)

  我们知道继承是oo语言中不可缺少的一部分,对于JavaScript也是如此。一般的继承有两种方式:其一,接口继承,只继承方法的签名;其二,实现继承,继承实际的方法。JavaScript不支持签名,因此只有实现继承。其中实现继... 查看详情