浅谈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 原型链的更多相关文章

  1. JavaScript学习总结(十七)——Javascript原型链的原理

    一.JavaScript原型链 ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法.其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法.在JavaScript中, ...

  2. javascript原型链中 this 的指向

    为了弄清楚Javascript原型链中的this指向问题,我写了个代码来测试: var d = { d: 40 }; var a = { x: 10, calculate: function (z) ...

  3. 明白JavaScript原型链和JavaScrip继承

    原型链是JavaScript的基础性内容之一.其本质是JavaScript内部的设计逻辑. 首先看一组代码: <script type="text/javascript"&g ...

  4. Javascript 原型链资料收集

    Javascript 原型链资料收集 先收集,后理解. 理解JavaScript的原型链和继承 https://blog.oyanglul.us/javascript/understand-proto ...

  5. 资料--JavaScript原型链

    JavaScript原型链 原文出处:https://www.cnblogs.com/chengzp/p/prototype.html 目录 创建对象有几种方法 原型.构造函数.实例.原型链 inst ...

  6. JavaScript原型链:prototype与__proto__

    title: 'JavaScript原型链:prototype与__proto__' toc: false date: 2018-09-04 11:16:54 主要看了这一篇,讲解的很清晰,最主要的一 ...

  7. JavaScript原型链及其污染

    JavaScript原型链及其污染 一.什么是原型链? 1.JavaScript中,我们如果要define一个类,需要以define"构造函数"的方式来define: functi ...

  8. 图解Javascript原型链

    本文尝试阐述Js中原型(prototype).原型链(prototype chain)等概念及其作用机制.上一篇文章(图解Javascript上下文与作用域)介绍了Js中变量作用域的相关概念,实际上关 ...

  9. 画一画javascript原型链

    在javascript中,几种数据类型String,Number,Boolean,Object,Function都是函数,可称之为函数对象. 可以说拥有prototype属性的都是函数. 所有对象都拥 ...

  10. JavaScript原型链和instanceof运算符的暧昧关系

    时间回到两个月前,简单地理了理原型链.prototype以及__proto__之间的乱七八糟的关系,同时也简单了解了下typeof和instanceof两个运算符,但是,anyway,试试以下两题: ...

随机推荐

  1. ASP.Net MVC开发基础学习笔记(4):校验、AJAX与过滤器

    一.校验 — 表单不是你想提想提就能提 1.1 DataAnnotations(数据注解) 位于 System.ComponentModel.DataAnnotations 命名空间中的特性指定对数据 ...

  2. SpringMVC解析1-使用示例

    Spring MVC分离了控制器.模型对象.分派器以及处理程序对象的角色,这种分离让它们更容易进行定制.Spring的MVC是基于servlet功能实现的,通过实现Servlet接口的Dispatch ...

  3. PHP学习笔记(一)

    by Alina.Xia, dated on 2016.11.27 一.MyAql数据库PHP在开发web站点或管理一些系统时,需要对大量的数据进行保存.XML文件和文本文件虽然可以作为数据的整体,但 ...

  4. Javascript参考手册

    ---------------------------------------------------------------------------------------------------- ...

  5. nginx实现ssl反向代理实战

    登录认证account.free4lab.com需要提供ssl登录接口,ssl的原理看这篇博文,因为前面有反向代理nginx,所以这个需求就放在nginx实现了,否则可以放在web容器(jetty,t ...

  6. LA6886 Golf Bot(FFT)

    题目 Source https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page= ...

  7. Codeforces 620E New Year Tree(DFS序 + 线段树)

    题目大概说给一棵树,树上结点都有颜色(1到60),进行下面两个操作:把某结点为根的子树染成某一颜色.询问某结点为根的子树有多少种颜色. 子树,显然DFS序,把子树结点映射到连续的区间.而注意到颜色60 ...

  8. Hadoop建立IPC连接和数据读写

    建立IPC连接 IPC Client通过调用getConnection获取IPC连接,具体流程图如下: 服务器端的IPC连接代码分散在Listener和Server.Connection中. List ...

  9. 常用JS正则表达式

    常用JS正则表达式 收集一些常用的JavaScript正则表达式匹配规则,比如匹配电话号码.Email.中文字符.身份证号.邮编.QQ号.过滤空白行.匹配特定数字等.觉得这玩意是很有用的,只不过自己水 ...

  10. 洛谷 P1029 最大公约数和最小公倍数问题 Label:Water&&非学习区警告

    题目描述 输入二个正整数x0,y0(2<=x0<100000,2<=y0<=1000000),求出满足下列条件的P,Q的个数 条件: 1.P,Q是正整数 2.要求P,Q以x0为 ...