js(原型与原型链是什么,有什么用)


前言

原型是Javascript中的继承的基础,所有 JavaScript 对象都从原型继承属性和方法,JavaScript的继承就是基于原型的继承。

要了解原型与原型链是什么,有什么用,需要先了解JavaScript对象构造函数等基本知识。


由来:Javascript语言的继承机制一直很难被人理解。它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(prototype chain)模式,来实现继承。Brendan Eich设计javascript之初是为了实现网页与浏览器之间交互的一种简单的脚本语言如果真的是一种简易的脚本语言,其实不需要有"继承"机制。但是,Javascript里面都是对象,必须有一种机制,将所有对象联系起来。所以,Brendan Eich最后还是设计了"继承"。

原型模式

我们创建的每个函数都有一个prototype (原型)属性,这个属性是一个指针, 指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。如果按照字面意思来理解,那么prototype就是通过调用构造函数而创建的那个对象实例的原型对象。使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。换句话说,不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中,如下面的例子所示。

function Personl) {
Person. prototype. name = "Nicholas";
Person. prototype.age = 29;
Person. prototype.job = " Software Engineer" ;
Person. prototype . sayNane = function() {
alert (this .name);
};
var person1 = new Person() ;
per son1. sayName() ;
//"Ni cholas"
var person2 = new Person();
person2 . sayName(); // "Nicholas"
alert person1 . sayName == person2 . sayName) ;
/ /true

在此,我们将sayName ()方法和所有属性直接添加到了Person的prototype属性中,构造函数变成了空函数。即使如此,也仍然可以通过调用构造函数来创建新对象,而且新对象还会具有相同的属性和方法。但与构造函数模式不同的是,新对象的这些属性和方法是由所有实例共享的。换句话说,person1和person2访问的都是同一组属性和同一个sayName()函数。要理解原型模式的工作原理,必须先理解ECMAScript中原型对象的性质。

理解原型对象

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含-一个指向prototype 属性所在函数的指针。就拿前面的例子说,Person.prototype. constructor 指向Person。 而通过这个构造函数,我们还可继续为原型对象添加其他属性和方法。创建了自定义的构造函数之后,其原型对象默认只会取得constructor属性;至于其他方法,则都是从obj ect继承而来的。当调用构造函数创建-一个新实例后,该实例的内部将包含-一个指针 (内部属性),指向构造函数的原型对象。ECMA-262第5版中管这个指针叫[ [Prototypel1。虽然在脚本中没有标准的方式访问[[Prototype]],但Fircfox. Safari 和Chrome 在每个对象上都支持一个属性_proto_ ; 而在其他实现中,这个属性对脚本则是完全不可见的。不过,要明确的真正重要的一点就是,这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。以前面使用Person构造函数和Person . prototype创建实例的代码为例,如下图展示了各个对象之间的关系。
在这里插入图片描述
上图展示了Person 构造函数、Person 的原型属性以及Person 现有的两个实例之间的关系。在此, Person. prototype指向了原型对象,而Person. prototype . constructor又指回了Person。原型对象中除了包含constructor属性之外,还包括后来添加的其他属性。Person 的每个实例-person1和person2都包含-一个内部属性,该属性仅仅指向了Person. prototype;换句话说,它们与构造函数没有直接的关系。此外,要格外注意的是,虽然这两个实例都不包含属性和方法,但我们却

原型对象的问题

原型模式也不是没有缺点。首先,它省略了为构造函数传递初始化参数这一环节, 结果所有实例在默认情况下都将取得相同的属性值。但原型模式的最大问题是由其共享的本性所导致的。原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性倒也说得过去,毕竟通过在实例上添加一个同名属性,可以隐藏原型中的对应属性。然而,对于包含引用类型值的属性来说,问题就比较突出了。

原型链

ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让-个引用类型继承另-一个引用类型的属性和方法。简单回顾- - 下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含-个指向构造函数的指针,而实例都包含-个指向原型对象的内部指针。那么,假如我们让原型对象等于另-一个类型的实例,结果会怎么样呢?显然,此时的原型对象将包含-一个指向另-一个原型的指针,相应地,另-个原型中也包含着-一个指向另一 个构造函数的指针。假如另一个原型又是另-个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。这就是所谓原型链的基本概念。实现原型链有一种基本模式,其代码大致如下:

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

在这里插入图片描述

原型链的问题

原型链虽然很强大,可以用它来实现继承,但它也存在一些问题。其中,最主要的问题来自包含引用类型值的原型。想必大家还记得,我们前面介绍过包含引用类型值的原型属性会被所有实例共享;而这也正是为什么要在构造函数中,而不是在原型对象中定义属性的原因。在通过原型来实现继承时,原型实际上会变成另-一个类型的实例。于是,原先的实例属性也就顺理成章地变成了现在的原型属性了。下列代码可以用来说明这个问题。

function SuperType() {
this.colors = ["red", "blue", "green"];
. 6.3 继承
167
}
function SubType() {
//继承了SuperType
SubType . prototype = new SuperType();
var instance1 = new SubType() ;
instance1. colors . push("black") ;
alert (i nstance1. colors);
1/"red, blue, green, black"
var instance2 = new SubType() ;
alert (instance2.colors) ;
//" red, blue, green, black"

总结

原型模式,使用构造函数的prototype属性来指定那些应该共享的属性和方法。组合使用构造函数模式和原型模式时,使用构造函数定义实例属性,而使用原型定义共享的属性和方法。
JavaScript主要通过原型链实现继承。原型链的构建是通过将- - 个类型的实例赋值给另一个构造函数的原型实现的。这样,子类型就能够访问超类型的所有属性和方法,这一点与基于类的继承很相似。原型链的问题是对象实例共享所有继承的属性和方法,因此不适宜单独使用。解决这个问题的技术是借用构造函数,即在子类型构造函数的内部调用超类型构造函数。这样就可以做到每个实例都具有自己的属性,同时还能保证只使用构造函数模式来定义类型。使用最多的继承模式是组合继承,这种模式使用原型链继承共享的属性和方法,而通过借用构造函数继承实例属性。

原型式继承(继承模式),可以在不必预先定义构造函数的情况下实现继承,其本质是执行对给定对象的浅复制。而复制得到的副本还可以得到进-一步改造。

本文主体参考摘抄自:《JavaScript高级程序设计(第3版)》

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不想想了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值