关于javascript原型链的个人理解
首先js是一种面对对象的语言,虽然大多数时候是以面对过程的形式展现出来。先来看一段代码:
function Base() {
this.name = 'tarol';
}
function Sub() {
this.age = 18;
}
var b = new Base;
Sub.prototype = b;
var s = new Sub;
console.log(s.name); //'tarol'
结果相信都知道,但是实现的原理却不明,于是逐行解析:
Sub.prototype = b;
prototype是函数对象(函数也是对象)的特有属性,普通对象是不存在这个属性的,该属性默认为{}。这个属性的作用就是,将这个属性赋予给、使用此函数作为构造函数进行实例化的对象、作为该对象[[Propertype]]的内部属性。所谓内部属性就是通过js不能访问的属性,庆幸的是现代浏览器开放了这个属性的访问,一般属性名为__proto__。所以:
var s = new Sub;
这一段(也可以说每个new操作)可以展开:
var s = {};
s.__proto__ = Sub.prototype;
Sub.call(s);
可见,对象实例化后,与构造函数的耦合在于前者的__proto__属性和后者的prototype属性为同一个对象的引用。
然后__proto__这个内部属性是用来做什么的呢,是用来实现js中的“继承”的。这个“继承”之所以打引号是用来区别c++和java中的类式继承的思想,这种方式称之为原型继承。
原型继承的原理是:每个对象都保有一个指向其他对象的引用(也就是__proto__即原型),这条引用最终指向null(null也是对象),当访问这个对象的任一属性时,如果在本对象中没有找到,则向其__proto__指向的对象中寻找,直到原型链的尽头null。需要注意的是:原型链中的所有元素都是实例化的对象。
现在回到上面的代码,当访问对象s的属性name时,在s中没有找到,于是跑到s的__proto__指向的Base的实例对象中寻找,找到了name为'tarol'。
但如果访问s的属性gender时,在s和s.__proto__中都没有找到,于是继续向s.__proto__.__proto__中寻找。由s.__proto__ === new Base,可知s.__proto__.__proto__ === Base.prototype(即(new Constructor()).__proto__ === Constructor.prototype)。上面说到,prototype默认是{},于是继续在Base.prototype.__proto__中找,即(new Object()).__proto__ === Object.prototype。如果没有添加一些自定义的属性,Object.prototype同样是{},这样看来,似乎要陷入无限的循环当中,但其实到这里原型链就走向了尽头,因为浏览器会定义Object.prototype.__proto__ = null。用下面的流程梳理下,-->代表原型链上的传递,===代表对象不同引用间的替换。
s.gender --> s.__proto__.gender === Sub.prototype.gender === b.gender --> b.__proto__.gender === Base.prototype.gender === (new Object()).gender --> (new Object()).__proto__.gender === Object.prototype.gender --> Object.prototype.__proto__ === null
Object.prototype.__proto__也是所有对象原型链的尽头,包括Function(函数的构造函数本身也是对象)、Date(普通对象)、Math(单体内置对象),因为Function.prototype是默认的{},即进入上面流程中(new Object()).gender这一阶段。
最后举个栗子:
function Class(){}
var a = new Class;
Class.prototype = new Class;
var b = new Class;
console.log(b.__proto__.__proto__ === a.__proto__);
其中最让人困惑的估计是
Class.prototype = new Class;
如果用类式继承来理解,会误以为这句代码会陷入死循环调用当中,但注意上面红字标明那句话:原型链中的所有元素都是实例化的对象。也就是,这里只是将一个对象插入Class对象的原型链最前端(除对象本身外),至于这个对象是new Class还是new Glass(见第一段红字,这句代码修改了构造函数的引用,使__proto__和prototype之间的耦合解除了,可以说这个对象和构造函数“分家”了),都不影响调用的过程。所以,这句代码的目的是修改了Class构造函数,让其实例化的对象的原型链长度+1。
写的有些凌乱,如果过段时间我看不懂了再回来改一改。
参考:
《理解JavaScript面向对象的思路》By 温神
《关于__proto__和prototype的一些理解》By TonyCoolZhu
《JavaScript高级程序设计》By Nicholas C.Zakas
关于javascript原型链的个人理解的更多相关文章
- javascript原型链简单的理解
在JavaScript中,一共有两种类型的值,原始值和对象值.每个对象都有一个内部属性[prototype],我们通常称之为原型.原型的值可以是一个对象,也可以是null.当然也可能是一个值,如果它的 ...
- Javascript 原型链资料收集
Javascript 原型链资料收集 先收集,后理解. 理解JavaScript的原型链和继承 https://blog.oyanglul.us/javascript/understand-proto ...
- 资料--JavaScript原型链
JavaScript原型链 原文出处:https://www.cnblogs.com/chengzp/p/prototype.html 目录 创建对象有几种方法 原型.构造函数.实例.原型链 inst ...
- JavaScript原型链及其污染
JavaScript原型链及其污染 一.什么是原型链? 1.JavaScript中,我们如果要define一个类,需要以define"构造函数"的方式来define: functi ...
- 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原型链:prototype与__proto__
title: 'JavaScript原型链:prototype与__proto__' toc: false date: 2018-09-04 11:16:54 主要看了这一篇,讲解的很清晰,最主要的一 ...
- 再次理解JavaScript原型链和匿名函数
<!--------------------------------------------- 1.演示匿名加载 2.js单进程执行流 3.原型链理解 a.__proto__:属性每个对象都有 ...
随机推荐
- Protocol Buffers与FlatBuffers效率对比
Protocol Buffers是Google跨语言.跨平台的通用序列化库.FlatBuffers同样出自Google,而且也跨语言跨平台,但更强调效率,专门为游戏开发打造.在游戏界混了几年,各种各样 ...
- 使用 Git 同步时出现ssl错误
错误提示 fatal: unable to access 'https://android.googlesource.com/platform/prebuilts/qemu-kernel/': gnu ...
- jsp的验证码实现
package com.xunfang.demo; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; imp ...
- Presto0.157版本单节点部署教程
因为Presto版本的更新速度较快,所以最好按照对应版本的教程进行部署,博主之前看错了版本号,拿0.100版本的教程来部署0.157版本,结果导致部署失败. 官网:https://prestodb.i ...
- angular学习(六)-- Filter
2.6 过滤器:Filter 内置过滤器 currency number date json uppercase lowercase orderBy limitTo filter 自定义过滤器
- 关于Spring总结
关于Spring总结 Spring引入 传统的基于mvc的项目框架结构:Entity / dao / service / action 简单用户访问流程:/user.action ----> T ...
- brk(), sbrk() 用法详解
brk() , sbrk() 的声明如下: #include <unistd.h> int brk(void *addr); void *sbrk(intptr_t increment); ...
- C++11 中值得关注的几大变化(网摘)
C++11 中值得关注的几大变化(详解) 原文出处:[陈皓 coolshell] 源文章来自前C++标准委员会的 Danny Kalev 的 The Biggest Changes in C++11 ...
- MJExtension框架源码分析
iOS开发中经常会用到数据和模型的互相转换,大致有两种转换方式:1.手动写转换的代码,2.利用开源库进行转换.常用的开源库有:JSONModel.Mantle.MJExtension.YYModel等 ...
- 家中路由添加静态IP映射(二)
家中的路由器普遍通过DHCP向连接到此路由器的客户主机提供IP配置方式,但是一般都是动态IP: 假设需要静态IP配置到个人电脑,就要在路由器上进行配置IP和MAC地址映射关系.如上篇截图.路由器端配置 ...