咱们先回顾一下前两天讨论的内容javascript
在 ECMAScript 核心所定义的所有属性中,最回味无穷的就要数 prototype 属性了。对于 ECMAScript 中的引用类型而言,prototype 是保存着它们全部实例方法的真正所在。换句话所说,诸如 toString()和 valuseOf() 等方法实际上都保存在 prototype 名下,只不过是经过各自对象的实例访问罢了。----《JavaScript 高级程序设计》
function Foo(name) { this.name = name; } var foo = new Foo('陌上寒'); console.log(Foo.prototype.constructor===Foo)//true console.log(foo.constructor===Foo);//true
原型对象有一个constructor属性,指向该原型对象对应的构造函数
foo 为何有 constructor 属性?那是由于 foo 是 Foo 的实例。
那 Foo.prototype 为何有 constructor 属性??同理, Foo.prototype Foo 的实例。
也就是在 Foo 建立的时候,建立了一个它的实例对象并赋值给它的 prototypejava
在Firefox、Safari 和 Chrome 的每一个对象上都有这个__proto__,属性 ,而在其余浏览器中是彻底不可见的为了确保浏览器兼容性问题,不要直接使用 proto 属性)segmentfault
// 普通对象的\__proto\__指向当前函数对象的原型, console.log('陌上寒'.__proto__===String.prototype);//true //原型对象(也属于普通对象)的__proto__指向当前函数对象的原型 console.log(String.prototype.__proto__===Object.prototype);//true //内置函数对象的\__proto\__指向的都是ƒ () { [native code] } console.log(Object.__proto__);//ƒ () { [native code] } //Object的原型对象的\__proto\__为null console.log(Object.prototype.__proto__)//null
好好消化上面的知识点,有助于我么讨论新的内容==>原型链数组
经过三者之间的联系,造成了原型链
继续看一下我门昨天讨论过的代码浏览器
console.log('陌上寒'.__proto__===String.prototype);//true console.log(String.prototype.__proto__===Object.prototype);//true //等量代换,得出如下结论 console.log('陌上寒'.__proto__.__proto__===Object.prototype);//true
咱们刚才说过,普通对象的__proto__指向当前函数对象的原型
咱们刚才还说过,普通对象都是经过函数建立的
根据以上两个结论咱们分析一下上面的代码
‘陌上寒’是字符串类型,’陌上寒’的构造函数是String(), 因此’陌上寒’的__proto__指向String的原型
String是js的内置构造函数,内置构造函数继承自Object
String的原型对象String.prototype也是一个普通对象,它的__proto__指向Object的原型,即Object.prototype
因此函数
console.log('陌上寒'.__proto__.__proto__===Object.prototype);//true
这就是原型链
咱们继续品读如下代码this
//咱们建立一个构造函数Foo(要记得,构造函数命名,首字母要大写) function Foo() {} //经过咱们自定义的构造函数。经过new操做符,咱们实例化出来一个对象foo const foo = new Foo() //对象的__proto__指向当前函数对象(foo是同构Foo实例化出来的,因此foo的函数对象是Foo)的原型 console.log(foo.__proto__===Foo.prototype); //原型对象也存在__proto__,指向该原型对象(Foo.prototype)所对应的函数对象(Object)的原型(好像有点绕,看代码就没那么绕了) console.log(Foo.prototype.__proto__===Object.prototype);//true //上面的若是懂了,这行代码就简单了,一个数学的等量代换,就得出告终论 console.log(foo.__proto__.__proto__===Object.prototype);//true console.log('---我是分割线----'); //咱们经过字面量建立了一个对象,等同于 const obj = new Object() const obj = {} //obj 是经过内置构造函数Object建立的,因此,obj的__proto__指向它的函数对象(Object)的原型(prototype)即:Object.prototype console.log(obj.__proto__===Object.prototype);//true console.log('---我是分割线----');//true //建立一个对象b const b = {} //咱们以前说过建立对象有三种方式,咱们使用第三种方式建立一个对象b1,对象b1继承自对象b,也就是说,对象b是对象b1的__proto__ const b1 = Object.create(b) //对象b是对象b1的__proto__ console.log(b1.__proto__===b);//true //前面已经证明过,b.__proto__==Object.prototype,再也不赘述 console.log(b.__proto__==Object.prototype);//true //等量代换就得出如下结论 console.log(b1.__proto__.__proto__===b.__proto__);//true console.log(b1.__proto__.__proto__==Object.prototype);//true
//自定义构造函数A(构造函数命名首字母大写)建立方式等同于var A = new Function() var A = function(){}//等同于var A = new Function() //经过构造函数A,使用new操做符实例化一个对象a(A是a的构造函数,a是A建立出来的) var a = new A() //对象的的__proto__指向它所对象函数对象(A)的原型(A.prototype) console.log(a.__proto__===A.prototype)//true //A是经过js内置构造函数Function建立出来的,然而 console.log(A.prototype.__proto__===Function.prototype);//false console.log(A.prototype.__proto__==Object.prototype);//true console.log(Function.prototype)//ƒ () { [native code] }
咱们从新修改一下上面的代码.net
var A = new Function() var a = new A()
A.prototype是个函数对象,理论上他的__proto__应该指向 Function.prototype,就是他本身,本身指向本身,没有意义。
js一直强调万物皆对象,函数对象也是对象,给他认个祖宗,指向Object.prototype。Object.prototype._proto_ === null,保证原型链可以正常结束。
事实验证了这样一个道理prototype
console.log(a.__proto__===A.prototype)//true console.log(A.prototype.__proto__===Function.prototype);//false console.log(A.prototype.__proto__==Object.prototype);//true console.log(a.__proto__.__proto__==Object.prototype);//true
A的原型对象的__proto__指向的是Object的原型
再看一张图
图片来源
再看一张图,细细品味
图片地址
今天先讨论到这里,咱们一块儿对今天的内容作一个总结
全部函数对象的 _proto_ 都指向 Function.prototype,它是一个空函数(Empty function)ƒ () { [native code] }
var obj = {name: '陌上寒'} var arr = [1,2,3] var reg = /hello/g var date = new Date var err = new Error('exception') console.log(obj.__proto__ === Object.prototype) // true console.log(arr.__proto__ === Array.prototype) // true console.log(reg.__proto__ === RegExp.prototype) // true console.log(date.__proto__ === Date.prototype) // true console.log(err.__proto__ === Error.prototype) // true
全部对象的 _proto_ 都指向其构造器的 prototype
原型链
原型链是实现继承的主要方法。
本身是由本身建立的,好像不符合逻辑,但仔细想一想,现实世界也有些相似,你是怎么来的,你妈生的,你妈怎么来的,你姥姥生的,……类人猿进化来的,那类人猿从哪来,一直追溯下去……,就是无,(NULL生万物)
正如《道德经》里所说“无,名天地之始”。
function Person(){} var person1 = new Person(); console.log(person1.__proto__ === Person.prototype); // true console.log(Person.prototype.__proto__ === Object.prototype) //true console.log(Object.prototype.__proto__) //null Person.__proto__ === Function.prototype; //true console.log(Function.prototype)// function(){} (空函数) var num = new Array() console.log(num.__proto__ === Array.prototype) // true console.log( Array.prototype.__proto__ === Object.prototype) // true console.log(Array.prototype) // [] (空数组) console.log(Object.prototype.__proto__) //null console.log(Array.__proto__ === Function.prototype)// true
咱们一块儿连续讨论了那么多,相信你必定对js原型和原型链有了些认识,可是光有认识仍是不够的,原型和原型链在实际场景中是怎么发挥做用的呢?咱们如何将原型链的相关技能投入到开发中呢?咱们明天继续讨论javascript的原型和原型链,不见不散
相关文章
关于javascript的原型和原型链,看我就够了(一)
关于javascript的原型和原型链,看我就够了(二)
关于javascript的Object. hasOwnProperty,看我就够了
参考连接
JavaScript之原型与原型链
图解prototype、proto和constructor的三角关系
Function.__proto__===Function.prototype怎么解释?
最详尽的 JS 原型与原型链终极详解,没有「多是」。(一)