理解JavaScript的原型链和继承
Table of Contents
instanceof 引发的问题
instanceof 运算符可以用来判断某个构造函数的prototype属性是否存在另外一个要检测对象的原型链上1。
什么意思呢?
来个题
Function instanceof Object;
用高中数学的话就是把x,y代入公式得:
instanceof 运算符可以用来判断Object的 prototype属性 是否存在Function的 原型链 上。
等等,斜体字的这俩到底是什么鬼意思?
prototype属性是原型链吗?
JS是基于原型链面向对象语言,也就是说所有对象都是以对象为模板创建实例的。如果是其他oo语言的背景比如Java或Ruby,都习惯于创建一个class模板,class创建object实例。比如ruby:
class A def initialize name @name = name end def to_s @name end end puts A.new('hehe') # => hehe
这里的类A就是所有 A.new
创建出来的实例的模板而已。而对于原型链语言JS来说,同意的事情要这样做
function A(name){ this.name = name } A.prototype.toString = function(){ return this.name } var a = new A('hehe') console.log('object name is:' + new A ('hehe')) // => object name is: hehe
- 这里的怪怪的函数其实就是constructor,相当于ruby例子里的initialize
- 而prototype上的方法toString也就是类似class模板上的方法。
为什么要把方法绑到prototype上?直接
A.toString
…= 不行吗?
在解释prototype之前,先解释一下 new A
到底发生了什么2:
1: // var a = new A('hehe') => 2: var a = new Object(); 3: a.__proto__ = A.prototype; (proto) 4: A.call(a, 'hehe');
其中 A.call
的意思是先把A的this设置为a,然后执行A的body也就是this.name=name
但是 __proto__
又是什么
__proto__
才是原型链
__proto__
是内部 [ [Prototype ]] (说了半天原型链这就是牛逼闪闪的 原型链, 指向对象或者null)的getter和setter方法(已加入ES6规范3,但是还是建议只使用Object.getPrototypeOf())
JS对象能使用它原型链对象的所有方法,比如所有的对象的原型链(的原型链的原型链的原型链…)都最终会指向Object(或null)。因此,所有的对象都能使用Object.prototype上的方法,比如我之前覆盖掉的 toString
本身就是Object.prototype上的方法,如果没有覆盖,它是可以拿到所有Object上的方法的:
a.toString === A.prototype.toString // true a.toLocalString === Object.prototype.toLocalString // true a.__proto__ === A.prototype // true
所以,现在是否可以理解这句话了呢
instanceof 运算符可以用来判断Object的 prototype属性 是否存在Function的 原型链 上。
所以instanceof其实就是
Function.__proto__ === Object.prototype // false
擦,假设失败了呢,让我们来看看为什么不对,Function.__proto__到底指哪去了
Function.__proto__ === Function.prototype //true
原来指向自己的prototype了呢,那就意味着…
Function instanceof Function //true
yes,然而 Function instanceof Object似乎也能解释了
Function.__proto__ === Function.prototype Function.__proto__.__proto__ === Object.prototype
所以如果我们让
Function.__proto__.__proto__ = null Function instanceof Object //false
这回知道为什么不要用 __proto__
了吧,一不小心重写了会导致所有继承自它的对象都受影响。
为了养成良好的习惯,实际项目最好使用
getPrototypeOf
取原型链,这里只是为了方便我采用__proto__
下面来看第二个题
Object instanceof Function
难道可以互相链吗?这意味着
Object.__proto__ === Function.prototype // true // 但是Firefox取不到Object.__proto__, 看来做了保护,必须要用 // Object.getPrototypeOf(Object) === Function.prototype
要晕了, 忍不住要画个图
多简单呢,一共就分别有两类:
- 原型链指向Function.prototype的函数们
- 原型链指向Object.propotype的对象们
而原型链顶端的Object.prototype就再没有原型链了,所以是空
现在再回头看题目是不是so easy了。
也没什么卵用得 contructor
如果你好奇的在FireFox Console中看一下 a
除了刚才那些玩意,还有一个奇怪的东西
话说 A
里面这个constructor是个什么鬼,我们来玩它一下
a.constructor === A.prototype.constructor A.prototype.constructor === A A.prototype.constructor = null a.constructor // => null a instanceof A // true
这只是函数都有的一个玩意而已, 由于js的函数可以作为构造器,也就是可以 new
,所以所有的 函数的prototype.constructor都指向自己,因此所有的 new 出来的对象也都有一个reference能找到自己的构造器。
然而除了这个功能也并没有什么卵用嘛。
真的是这样吗?
.
..
…
….
…..
……
…….
恩,真的!
Bonus 继承
下面这个是babel 从es6 class
class A{ constructor(name) { this.name= name } toString() { return this.name } } class B extends A { toString(){ return this.name + 'b' } }
编译出来的ES5继承
function _inherits(subClass, superClass) { // 密 } var A = (function () { function A(name) { this.name = name; } A.prototype.toString = function toString() { return this.name; }; return A; })(); var B = (function (_A) { function B() { if (_A != null) { _A.apply(this, arguments); } } _inherits(B, _A); B.prototype.toString = function toString() { return this.name + 'b'; }; return B; })(A);
其他地方都不用看了,inherits 函数用到了之前学到的所有玩意,要求实现要满足下列所有的cases,就当是课后练习了:
var a= new A('A'); var b= new B('B'); a.constructor === A && b.constructor === B && a instanceof A && b instanceof A && b instanceof B
相关推荐
JavaScript原型链是JavaScript语言中的一个核心特性,它关乎对象之间的继承关系。在JavaScript中,一切皆为对象,而原型链则是实现对象间属性和方法共享的一种机制。理解原型链对于深入学习JavaScript至关重要。 ...
深入理解javascript原型和闭包(01)——一切都是对象 深入理解javascript原型和闭包(02)——函数和对象的关系
JavaScript原型和闭包是这门语言中两个比较难以理解且与其他面向对象语言区别较大的概念。理解这两个概念,不仅能让我们更深层次地理解JavaScript,而且有助于我们了解编程语言的设计思路,拓宽我们的视野。 首先,...
"基于Javascript原型的Zepto框架设计" 本文主要讨论了基于Javascript原型的Zepto框架设计。随着互联网的普及,前端技术也得到了迅速发展。为了深入了解前端开发中的框架设计原理,以Zepto前端框架为例,利用...
本文将深入探讨JavaScript原型链的工作原理及其可能导致的安全问题——原型链污染。 首先,JavaScript 中的对象继承并不像传统面向对象语言那样基于类,而是通过原型链机制。每个对象都有一个内部属性`[[Prototype]...
JavaSciptDOM基本操作,JavaScipt函数基础,JavaScipt流程语句,JavaScript变量,JavaScript数据类型,JavaScript数组,JavaScript正则表达式,JavaScript字符串函数,Window对象等图解。JS高手进阶的工具图谱
### 理解Javascript原型继承原理 #### 一、引言 在JavaScript中,原型继承是一种非常核心且独特的机制,它使得对象能够继承其他对象的属性和方法。本文旨在深入探讨这一机制,并通过具体的示例代码帮助读者更好地...
### 浅析JavaScript原型继承机制 #### 一、引言 JavaScript作为一种动态语言,其对象模型与传统的面向对象编程语言有所不同。在JavaScript中,并没有直接提供类的概念,而是通过原型来实现继承。本文将深入探讨...
### JavaScript原型继承工作原理及实例详解 #### 一、引言 JavaScript作为一种广泛使用的脚本语言,在Web开发中扮演着重要角色。其独特的面向对象机制是通过原型继承来实现的,这种机制使得JavaScript能够灵活地...
本篇文章将深入探讨JavaScript原型数据共享和方法共享的实现。 首先,我们需要理解JavaScript中的原型对象。每个函数在创建时都会自动获得一个`prototype`属性,这个属性是一个对象,它的作用是为该函数的所有实例...
Javascript原型继承是一个被说烂掉了的话题,但是自己对于这个问题一直没有彻底理解,今天花了点时间又看了一遍《Javascript模式》中关于原型实现继承的几种方法,下面来一一说明下,在最后我根据自己的理解提出了一...
javascript原型继承,prototype的使用,可以像java一样继承
JavaScript原型继承是面向对象编程在JavaScript中的实现方式之一,它基于原型(Prototype)和对象的特性,使得一个对象可以继承另一个对象的属性和方法。在JavaScript中,每个对象都有一个特殊的内部属性`[...
javascript原型继承机制参考.pdf
javascript原型继承机制借鉴.pdf
javascript原型继承机制归类.pdf
javascript原型继承机制[整理].pdf
通过`Prototype-In-Javascript-Basic.pdf`和`Prototype-In-JavaScript-Examples.zip`中的资料,你可以深入学习并实践JavaScript原型的各种用法,包括如何创建和使用原型,如何实现继承,以及如何处理与原型相关的...
Javascript 原型 这个包包含一个脚本,其中包含用于获取选项和运行某些东西的主要功能。 它是一部分,以学习如何编写标准代码和TDD的常用用法。 使用逐步此代码的开发。 安装 该包是自洽的,但如果你想自己测试,你...