原型与原型链理解 1. 什么是原型
JavaScript是一种简易的脚本语言,其是由对象构成。每一个JavaScript对象(除null外)都和另一个对象相关联,“另一个”对象就是原型。也就是说,任何一个对象都有原型这个属性。
隐式原型(_proto_):上面说的这个原型是JavaScript中的内置属性[[prototype]],此属性继承自object对象,在脚本中没有标准的方式访问[[prototype]],但Firefox、Safari和Chrome在每个对象上都支持一个属性_proto_。隐式原型的作用是用来构成原型链,实现基于原型的继承
显示原型(prototype):每一个函数在创建之后,便会拥有一个prototype属性,这个属性指向函数的原型对象。显示原型的作用是用来实现基于原型的继承与属性的共享
2. 那原型是用来做什么的?其可以解决什么问题?
构造函数的缺陷:
构造函数是通过new运算符创建并初始化一个新的对象,关键字new后跟随一个函数调用,这个函数称为构造函数,构造函数用来初始化一个新创建的对象。
现在有一个Person的构造函数,表示人对象的原型
function Person(name) { this.name = name this.address = "上海" // 设置一个实例对象的共有属性address } //生成人对象实例 var person1 = new Person("Tom") var person2 = new Person("Jack")
这两个对象的address属性是独立的,修改其中一个,不会影响到另一个
person1.address = "北京" console.log(person2.address) // 上海,不受person1的影响
每一个实例对象都有自己的属性和方法的副本,由于无法做到数据共享,导致资源的浪费。所以,为了解决数据无法共享的问题,引入了prototype属性,prototype属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法,也就是说prototype是通过调用构造函数而创建的那个对象实例的原型对象。因此我们可以将实例对象需要共享的属性和方法都放在这个对象中。
现在对上面的Person方法进行重写,假设我们需要address这个属性是共享的,但是name是独有的。
function Person(name) { this.name = name } Person.prototype = { address: "上海" } //生成人对象实例 var person1 = new Person("Tom") var person2 = new Person("Jack") //修改共享的属性address Person.prototype.address = "北京" console.log(person1.prototype) // 北京 console.log(person2.prototype) // 北京
address属性放在了Person的prototype对象中,创建实例后,两个实例也将address属性放在了原型对象中,这两个实例对象共享这个属性,只要修改Person中的prototype对象,就会同时影响两个实例对象
继承机制
我们都知道JavaScript里面都是对象,如果想要让所有的对象联系起来,就需要有一种继承机制来实现。上面的例子中说了实例中原型的作用,就是实现共享属性和方法,但是如果想要让其他引用类型也共享这个引用类型的属性和方法呢?假如我们让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,且关系依然成立,如此层层递进,就构成了实例与原型的链条。
实现原型链的基本模式
//原型链 function SuperType() { this.property = true } SuperType.prototype.getSuperValue = function(){ return this.property } function SubType () { this.subproperty = false } //继承了SubType SubType.prototype = new SuperType() SubType.prototype.getSubValue = function () { return this.subproperty } var instance = new SubType() console.log(instance.getSuperValue())
首先先定义了两个类型:SuperType和SubType,每个类型分别有一个属性和方法,通过创建SuperType实例让SubType继承SuperType,并且将SuperType实例赋值给SubType.prototype。这样就将原来存放在SuperType的实例中的所有属性和方法共享到SubType.prototype中。
然后再给SubType.prototype添加一个方法,这样就在继承了SuperType的属性和方法的基础上又添加了一个新方法。
最终结果如图上所示,instance指向SubType的原型,SubType的原型又指向SuperType的原型。getSuperValue()方法仍然还在SuperType.prototype中,但peoperty则位于SubType.prototype中。这是因为property是一个实例属性,而getSuperValue()这是一个原型方法。对于原型链的继承是如何进行的呢?
这就需要介绍一些原型搜索机制,原型搜索机制是当使用读取模式访问一个属性时,首先会在实例中搜索该属性,如果没有找到该属性,接着就会继续搜索实例的原型。 在通过原型链实现继承的情况下,搜索过程就得以沿着原型链继续向上。就拿上面的例子来说,调用instance.getSuperValue()会经历三个搜索步骤:
1). 搜索实例 2). 搜索SubTyp.prototype 3). 搜索SuperType.prototype,最后一步才会找到该方法
在找不到属性或方法的时的情况下,搜索过程总是要一环一环地前行到原型链的末端才会停下来。
总结JavaScript的原型是为了实现对象间的联系,解决构造函数无法数据共享而引入的一个属性。而原型链是一个实现对象间联系即继承的主要方法。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/107477.html
摘要:探索是如何判断的表达式如果函数的显式原型对象在对象的隐式原型链上,返回,否则返回是通过自己产生的实例案例案例重要注意的显示原型和隐式原型是一样的。面试题测试题测试题报错对照下图理解 原型与原型链深入理解(图解) 原型(prototype) 函数的 prototype 属性(图) 每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象) 原型对象中有...
摘要:构造函数的属性指向原型对象原型对象的属性指向构造函数实例对象的指向原型对象所有引用类型默认都继承了,而这个继承也是通过原型链实现的。第一种方式是使用操作符,只要用这个操作符来测试实例与原型链中出现过的构造函数,结果就会返回。 理解对象 首先对象的定义是:无序属性的集合,其属性可以包含基本值、对象或者函数。严格来讲,这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名...
摘要:原型对象是由创建的,因此原型对象的构造函数是构造函数也可以是称为对象,原型对象也就继承了其生父构造函数中的数据,也同时继承了原型对象的数据。当然这条原型链中的数据,会被还是还是这类构造函数继承,但是不会被这些继承,他们不处于同一个链条上。 js中,Function的本质是什么?Object的本质又是什么?js中有几条原型链? showImg(https://segmentfault.c...
摘要:相当于在用原型继承编写复杂代码前理解原型继承模型十分重要。同时,还要清楚代码中原型链的长度,并在必要时结束原型链,以避免可能存在的性能问题。 js是一门动态语言,js没有类的概念,ES6 新增了class 关键字,但只是语法糖,JavaScript 仍旧是基于原型。 至于继承,js的继承与java这种传统的继承不一样.js是基于原型链的继承. 在javascript里面,每个对象都有一...
摘要:原型链与继承当谈到继承时,只有一种结构对象。如果对该图不怎么理解,不要着急,继续往下看基于原型链的继承对象是动态的属性包指其自己的属性。当使用操作符来作用这个函数时,它就可以被称为构造方法构造函数。 原型链与继承 当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象(object )都有一个私有属性(称之为proto)指向它的原型对象(prototype)。该原型对象也...
阅读 1685·2021-11-18 10:02
阅读 2184·2021-11-15 11:38
阅读 2651·2019-08-30 15:52
阅读 2158·2019-08-29 14:04
阅读 3208·2019-08-29 12:29
阅读 2065·2019-08-26 11:44
阅读 958·2019-08-26 10:28
阅读 802·2019-08-23 18:37