原型链是整个JS面向对象的基础
在理解原型链之前先来谈谈JS创建对象的几种方式
//字面量方式
var a1 = {name:'a1'}
var a2 = new Object({name:'a2'})
//构造函数方式
var F = function(name) {
this.name = name
}
var a3 = new F('a3')
//Object.create()方式
var o = {name:'a4'}
var a4 = Object.create(o)
console.log(a1,a2,a3,a4)
//{name: "a1"}
//{name: "a2"}
//{name: "a3"}
//{}
可以看到输出了4个对象,a1和a2看起来一样,但是a3和a4就有一些不一样了。
- a1和a2创建的时候原型对象指向Object;
- a3是F构造函数的实例,所以指向的是F构造函数(当任何一个函数被new使用了它就是一个构造函数);
- a4输出看不到name属性,但是可以通过a4.name获取到name值(这里能获取到就是因为如果在对象内找不到name时JS会自动去原型链上一层一层往外找,所以就找到了proto属性里的name,当找到最外层Object的原型对象时没有找到则会结束查找);
在浏览器控制台输出对象时展开会发现有粉色的proto或prototype这两个属性,这就是原型对象。
区别在于对象上只有proto属性,而函数有proto和prototype这两个属性。
注意:prototype只有函数上有,proto只有对象上有,因为JS中函数也算是一种对象,所以在函数上也有proto属性。
原型、构造函数、实例相互关系:
构造函数指F函数,实例指a3
原型.png任何一个实例对象可以通过原型链找到它上层的属性和方法,都是共享的。
注意:函数F是Function的实例
F.__proto__===Function.prototype
//true
instanceof原理:
instanceof用来判断实例是否为某个对象的实例。
其原理就是根据原型链来判断。
流程如下:
比较实例对象的proto和构造函数的prototype是否相同,如果相同则为真。
a3 instanceof F
//等价
a3.__proto__ === F.prototype
//true
//只要是在原型链上的构造函数,都会返回真
a3 instanceof Object
//等价
a3.__proto__.__proto__ === Object.prototype
//true
因为instanceof不够精确,所以可以使用constructor来判断是否为实例。
a3.__proto__.constructor === F
//true
a3.__proto__.constructor === Object
//false
new运算符:
foo为构造函数
- 一个新对象被创建,它继承于foo.prototype。
- 构造函数被执行。执行的时候,相应的参数会被传入,同时上下文(this)会被指定为这个新实例。new foo等同于 new foo(),只能用在不传参的情况。
- 如果构造函数返回了一个对象,那么这个对象会取代整个new出来的结果。如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象。
var new2 = function (func) {
var o = Object.create(func.prototype)
var k = func.call(o)
if (typeof k === 'object') {
return k
} else {
return o
}
}
var a5 = new2(F)
a5 instanceof F
//true
a5.__proto__.constructor === F
//true
网友评论