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,试试以下两题: ...
随机推荐
- jQuery方法注意事项
1.关于选择器中含有特殊符号 选择器中含有".","#","(","]"等特殊字符,根据W3C的规定,属性值中是不能含有 ...
- shell-bash学习04读取输入、分隔符、流程控制
读入输出 输入通常是通过stdin或参数传递给命令; 输出出现在stderr或stdout; 管道,过滤器,管道操作符: cmd1 | cmd2 | cmd3; //最后还有输出 ls | cat - ...
- css3 总结01
前缀 chrome: -webkit- safari: -webkit- firefox: -moz- ie: -ms- opera: -o- 书写的时候应该先用有前缀的样式,再用无前缀的样式 颜色 ...
- 一个java集合使用bug
在使用java集合的时候有的时候集合是来自于一些第三方工具提供的从字符串或json 转出集合的对象有时是抽象类,这时的对象部分功能是未实现的,在使用相应操作的时侯 会引发bug. Exception ...
- 2.2 代码块--delphi 写日志模块
//2.2 代码块--写日志 //调用例句如:LogMsg('FTP上传线程终止',False,true); procedure LogMsg(AMsg: string; const blnIsErr ...
- Codeforce - Runtime Error
Bahosain was trying to solve this simple problem, but he got a Runtime Error on one of the test case ...
- 【FZU】1977 Pandora adventure
http://acm.fzu.edu.cn/problem.php?pid=1977 题意:n×m的网格,有3种格子,'O'必须经过.'*'可以选择经过.'X'不能经过.现在要求路径经过所有'O'且是 ...
- ubuntu 装机及装机以后干的事情
一.装系统 下载ubuntu镜像 ubuntu 16.04 镜像下载(linux公社) 安装unetbootin (u盘启动盘制作工具) sudo apt-get install unetbootin ...
- Makefile学习
makefile中常用的函数: http://linux.chinaunix.net/techdoc/develop/2009/07/09/1122854.shtml SRC = $(wildcard ...
- 在Linux中安装Tomcat
带Linux的虚拟机中安装Tomcat 一.从官方网站上下载tomcat软件包.http://tomcat.apache.org/ apache-tomcat-7.0.33.tar.gz 二.下载到本 ...