javascript 原型链
浅谈JS原型链
原型链
ECMAScript中描述了原型链的概念。我们知道ECMAScript并不像C++,Java那样使用类,但是对象仍然可以通过多种方式创建,其中就有构造函数方式。每个构造函数都有一个原型对象,同时都有一个prototype属性, prototype属性指向构造函数的原型对象,它被用来实现基于原型的继承和共享。而原型对象又都默认会取得一个constructor属性,这个属性包含一个指向构造函数(prototype属性所在函数)的指针。每个通过调用构造函数创建的实例对象都拥有一个指向原型对象的指针,ECMA-262第5版中叫这个指针为[[prototype]],虽然在脚本上没有标准的方式访问[[prototype]],但Chrome、Firefox和Safari在每个对象上都支持一个属性_proto_,而在其他实现中,这个属性对脚本是完全不可见的。假如原型对象等于另一个类型的实例,那么它就拥有指向创建该实例的构造函数的原型对象的指针,依此类推,就形成了一条指针链,这就是原型链的概念。通过下面的图形我们可以更清晰地了解原型链的概念。
ECMA5中可以使用Object.getPrototypeOf()来获取实例的构造函数的prototype

事实上,上图所展示的原型链还少一环。我们知道,所有引用类型默认都继承了Object,而这个继承也是通过原型链实现的。函数是可调用的对象,所有函数的默认原型对象都是Object的实例,所以函数的原型对象都会包含一个指向Object构造函数的原型对象的指针,也即指向Object.prototype的指针[[prototype]]。这样就解释了为什么所有自定义对象类型都会继承toLocaleString()、toString()等Object原型对象的默认方法了。还是来上图吧。

当然,还有很重要的一点是我们需要注意的:对象实例中的指针[[prototype]]只指向原型对象,并不指向构造函数。
原型语法
通常,我们可以用一个包含所有属性和方法的对象字面量来重写整个原型对象。例如
1 |
function Person(){} |
2 |
Person.prototype = { |
3 |
name: "bella", |
4 |
age: 21, |
5 |
sayHello: function(){ |
6 |
alert(this.name); |
7 |
} |
8 |
} |
不过,我们需要注意的是,重写之后,构造函数Person的原型对象的constructor属性不再指向Person了,因为该语法的本质是完全重写了默认的原型对象,所以constructor属性也就变成了新对象的constructor属性,指向Object构造函数,我们此时就不能通过constuctor来确定对象的类型了。
可以通过Person.prototype.constructor = Person恢复constructor的指针。
原型的动态性
原型在查找值的过程中是一次搜索,当我们想引用一个对象的某个属性时,所引用到的是原型链中包含该属性名的第一个对象所对应的属性值。换句话说,直接引用这个属性的对象会首先被查询是否包含该属性名,如果包含,该属性值就是我们想获取的,查询停止,如果不包含,会接着查询该对象的原型是否包含该属性,依此类推。
我们可以随时动态地为原型添加属性和方法,而且,基于这种搜索过程,我们对原型对象所做的任何修改都能立即从对象实例上看到,即使该修改是在创建实例之后。但如果是用上面提到的语法重写整个原型对象就另当别论了。因为重写原型对象会切断现有原型对象与原来已经存在的任何对象实例之间的联系,它们包含的指针[[prototype]]仍然指向原来的原型对象,我们可以看看下面的小例子。
01 |
function Person(){} |
02 |
var person1 = new Person(); |
03 |
Person.prototype = { |
04 |
name: "bella", |
05 |
age: 21, |
06 |
sayHello: function(){ |
07 |
alert(this.name); |
08 |
} |
09 |
} |
10 |
person1.sayHello(); //error |
上面的例子中,我们先创建了Person的一个实例对象person1,然后重写了Person的原型对象,之后再调用person1.sayHello()就会发生错误。因为person1中包含的指针[[prototype]]仍然指向原来的原型对象,并不包含新的原型对象中定义的sayHello属性。
原型的问题
原型模式使得所有对象实例在默认情况下取得相同的属性值,对于属性值为函数的情况,这正是我们希望看到的,所有对象实例共享这一函数而不需要重复定义,但是对于属性值为基本值的情况,我们通常希望不同的对象实例拥有不同的基本值,不过,我们可以通过在对象实例上添加同名属性来隐藏原型对象中的属性。但是,如果包含引用类型值的属性,问题就显现出来了。
01 |
function Person(){} |
02 |
Person.prototype = { |
03 |
name: "bella", |
04 |
age: 21, |
05 |
classmates: ["Lucy", "Lily"], |
06 |
sayHello: function(){ |
07 |
alert(this.name); |
08 |
} |
09 |
} |
10 |
var person1 = new Person(); |
11 |
var person2 = new Person(); |
12 |
person1.classmates.push("Mark"); |
13 |
alert(person1.classmates === person2.classmates); //true |
这里,我们为Person.prototype对象添加了classmates属性,值为一个字符串数组,然后创建了两个对象实例person1, person2。由于person1, person2所拥有的classmates属性其实是共享原型对象Person.prototype的classmates属性得到的,也就是数组只存在于Person.prototype对象中,person1和person2引用的是同一个数组,对person1中classmates的修改也会从person2.classmates中反映出来,这样会导致所有对象实例共享一个数组,这往往不是我们想要的。
以上,我只是简单地分析了原型链的概念和原型对象的基本特性,希望能对大家有小小的帮助,想要更深刻地认识它,当然还是得靠大家在实际项目中去学习
原文地址:
http://cube.qq.com/?p=163
javascript 原型链的更多相关文章
- JavaScript学习总结(十七)——Javascript原型链的原理
一.JavaScript原型链 ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法.其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法.在JavaScript中, ...
- javascript原型链中 this 的指向
为了弄清楚Javascript原型链中的this指向问题,我写了个代码来测试: var d = { d: 40 }; var a = { x: 10, calculate: function (z) ...
- 明白JavaScript原型链和JavaScrip继承
原型链是JavaScript的基础性内容之一.其本质是JavaScript内部的设计逻辑. 首先看一组代码: <script type="text/javascript"&g ...
- Javascript 原型链资料收集
Javascript 原型链资料收集 先收集,后理解. 理解JavaScript的原型链和继承 https://blog.oyanglul.us/javascript/understand-proto ...
- 资料--JavaScript原型链
JavaScript原型链 原文出处:https://www.cnblogs.com/chengzp/p/prototype.html 目录 创建对象有几种方法 原型.构造函数.实例.原型链 inst ...
- JavaScript原型链:prototype与__proto__
title: 'JavaScript原型链:prototype与__proto__' toc: false date: 2018-09-04 11:16:54 主要看了这一篇,讲解的很清晰,最主要的一 ...
- JavaScript原型链及其污染
JavaScript原型链及其污染 一.什么是原型链? 1.JavaScript中,我们如果要define一个类,需要以define"构造函数"的方式来define: functi ...
- 图解Javascript原型链
本文尝试阐述Js中原型(prototype).原型链(prototype chain)等概念及其作用机制.上一篇文章(图解Javascript上下文与作用域)介绍了Js中变量作用域的相关概念,实际上关 ...
- 画一画javascript原型链
在javascript中,几种数据类型String,Number,Boolean,Object,Function都是函数,可称之为函数对象. 可以说拥有prototype属性的都是函数. 所有对象都拥 ...
- JavaScript原型链和instanceof运算符的暧昧关系
时间回到两个月前,简单地理了理原型链.prototype以及__proto__之间的乱七八糟的关系,同时也简单了解了下typeof和instanceof两个运算符,但是,anyway,试试以下两题: ...
随机推荐
- UpdatePanel的使用方法
UpdatePanel控件也是Ajax里用得最多的控件之一,UpdatePanel控件是用来局部更新网页上的内容,网页上要局部更新的内容必须放在UpdatePanel控件里,他必须和上一次说的Scri ...
- asp.net项目中通过Web.config配置文件及文件夹的访问权限!
描述:在开发中我们通常会碰到这样的问题,例如:在项目的根目录下面有一个文件或者文件夹需要用户登陆后才能访问.如果用户在没有登录的情况下访问该文件或者该文件夹下面的文件时,直接拦截重定向到对应的登陆页面 ...
- java发送短信--httpclient方式
最近头让我写个发送短信的java程序检测BI系统,检查数据库是否有异常发送,有则发送短信到头的手机里.这里我直说httpclient方式的get请求方式,并且已经有方式的短信的接口了,所以只要再加上参 ...
- 主窗体里面打开子窗体&&打印饼图《Delphi 6数据库开发典型实例》--图表的绘制
\Delphi 6数据库开发典型实例\图表的绘制 1.在主窗体里面打开子窗体:ShowForm(Tfrm_Print); procedure Tfrm_Main.ShowForm(AFormClass ...
- Shell 编程基础之 For 练习
一.语法 for var in con1 con2 con3 ... do # 执行内容 done for var in {min..max} do # 执行内容 done for (( 初始值; 限 ...
- ural 2066. Simple Expression
2066. Simple Expression Time limit: 1.0 secondMemory limit: 64 MB You probably know that Alex is a v ...
- HDU5735 : Born Slippy
考虑DP,设$f[x]$表示最后一个是$x$时的最优解,则$f[x]=\max(f[y]+w[x]\ opt\ w[y])$,其中$y$是$x$的祖先. 注意到$w[i]<2^{16}$,那么将 ...
- java 程序访问hdfs错误 hadoop2.2.0
很奇怪的问题,程序在eclipse上跑没问题: 这就代码:FileSystem fs = FileSystem.get(URI.create(hdfs_file), conf , "use ...
- 《隆重介绍 思源黑体:一款Pan-CJK 开源字体》
关于思源黑体 思源黑体是谷歌与 Adobe 联合开发,支持简体中文.繁体中文.日文.韩文以及英文:支持 ExtraLight.Light.Normal.Regular.Medium.Bold 和 He ...
- 20145308刘昊阳 《Java程序设计》第7周学习总结
20145308刘昊阳 <Java程序设计>第7周学习总结 教材学习内容总结 第13章 时间与日期 13.1 认识时间与日期 13.1.1 时间的度量 格林威治时间(GMT) 世界时(UT ...