当前位置: 主页 > 前端开发 > nodejs >

Javascript 原型中的哲学思想

时间: 2016-12-06 04:21 来源: 未知 作者: admin 点击:
Javascript 原型中的哲学思想

 

记得当年初试前端的时候学习JavaScript过程中原型问题一直让我疑惑许久那时候捧着那本著名的红皮书看到有关原型的讲解时总是心存疑虑
当在JavaScript世界中走过不少旅程之后再次萌发起研究这部分知识的欲望翻阅了不少书籍和资料才搞懂__proto__prototype的概念
故以作此笔记日后忘了可以回来看看
如果你看的过程中觉得理解有些困难把例子在代码中跑一跑亲手试一试也许能解决不少疑惑

一切皆为对象

殊不知JavaScript的世界中的对象追根溯源来自于一个 null

一切皆为对象这句着实是一手好营销易记易上口印象深刻
万物初生时一个null对象凭空而生接着ObjectFunction学着null的模样塑造了自己并且它们彼此之间喜结连理提供了prototypeconstructor一个给子孙提供了基因一个则制造万千子子孙孙
JavaScriptnull也是作为一个对象存在基于它继承的子子孙孙当属对象
乍一看null像是上帝,ObjectFunction犹如JavaScript世界中的亚当夏娃

原型指针 __proto__

JavaScript每个对象都拥有一个原型对象而指向该原型对象的内部指针则是__proto__,通过它可以从中继承原型对象的属性原型是JavaScript中的基因链接有了这个才能知道这个对象的祖祖辈辈从对象中的__proto__可以访问到他所继承的原型对象


							
1
2

							
var a = new Array();
a.__proto__ === Array.prototype // true

上面代码中创建了一个Array的实例a该实例的原型指向了Array.prototype Array.prototype本身也是一个对象也有继承的原型:


							
1
2

							
a.__proto__.__proto__ === Object.prototype // true
// 等同于 Array.prototype.__proto__ === Object.prototype

这就说了明了Array本身也是继承自Object那么Object的原型指向的是谁呢


							
1
2

							
a.__proto__.__proto__.__proto__ === null // true
// 等同于 Object.prototype.__proto__ === null

prototype.png

所以说JavaScript中的对象追根溯源都是来自一个null对象佛曰万物皆空善哉善哉

除了使用.__proto__方式访问对象的原型还可以通过Object.getPrototypeOf方法来获取对象的原型以及通过Object.setPrototypeOf方法来重写对象的原型 值得注意的是按照语言标准__proto__属性只有浏览器才需要部署其他环境可以没有这个属性而且前后的两根下划线表示它本质是一个内部属性不应该对使用者暴露因此应该尽量少用这个属性而是用Object.getPrototypeofObject.setPrototypeOf进行原型对象的读写操作 这里用__proto__属性来描述对象中的原型是因为这样来得更加形象且容易理解

原型对象 prototype

函数作为JavaScript中的一等公民它既是函数又是对象函数的原型指向的是Function.prototype


							
1
2

							
var Foo = function() {}
Foo.__proto__ === Function.prototype // true

函数实例除了拥有__proto__属性之外还拥有prototype属性 通过该函数构造的新的实例对象其原型指针__proto__会指向该函数的prototype属性


							
1
2

							
var a = new Foo();
a.__proto__ === Foo.prototype; // true

而函数的prototype属性本身是一个由Object构造的实例对象


							
1

							
Foo.prototype.__proto__ === Object.prototype; // true

prototype属性很特殊它还有一个隐式的constructor指向了构造函数本身


							
1
2
3

							
Foo.prototype.constructor === Foo; // true
a.constructor === Foo; // true
a.constructor === Foo.prototype.constructor; // true

prototype2.png

原型链

概念

原型链作为实现继承的主要方法其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法 每个构造函数都有一个原型对象(prototype)原型对象都包含一个指向构造函数的指针(constructor)而实例都包含一个指向原型对象的内部指针(__proto__) 那么假如我们让原型对象等于另一个类型的实例此时的原型对象将包含一个指向另一个原型的指针相应地另一个原型中也包含着一个指向另一个构造函数的指针假如另一个原型又是另一个类型的实例那么上述关系依然成立 如此层层递进就构造了实例与原型的链条这就是原型链的基本概念

意义

“原型链”的作用在于当读取对象的某个属性时JavaScript引擎先寻找对象本身的属性如果找不到就到它的原型去找如果还是找不到就到原型的原型去找以此类推如果直到最顶层的Object.prototype还是找不到则返回undefine

亲子鉴定

JavaScript也存在鉴定亲子之间DNA关系的方法

  1. instanceof 运算符返回一个布尔值表示一个对象是否由某个构造函数创建
  2. Object.isPrototypeOf() 只要某个对象处在原型链上isProtypeOf都返回true

							
1
2
3
4
5

							
var Bar = function() {}
var b = new Bar();
b instanceof Bar // true
Bar.prototype.isPrototypeOf(b) // true
Object.prototype.isPrototypeOf(Bar) // true

要注意实例b的原型是Bar.prototype而不是Bar

一张历史悠久的图

jsobj_full.jpg

这是一张描述了ObjectFunction以及一个函数实例Foo他们之间原型之间联系如果理解了上面的概念这张图是不难读懂

从上图中能看到一个有趣的地方 Function.prototype.__proto__ 指向了 Object.prototype这说明Function.prototype 是一个 Object实例那么应当是先有的Object再有Function 但是Object.prototype.constructor.__proto__ 又指向了 Function.prototype这样看来没有FunctionObject也不能创建实例 这就产生了一种类先有鸡还是先有蛋的经典问题到底是先有的Object还是先有的Function 这么哲学向的问题留给你思考了 我只是感慨 越往JavaScript的深处探索越发觉得这一门语言很哲学

(责任编辑:admin)
------分隔线----------------------------