Description
原型链解决的主要是继承问题。
定义
prototype(显式原型)
每一个函数在创建之后都会拥有一个名为prototype
的属性,这个属性指向函数的原型对象。
proto(隐式原型)
隐式原型指向创建这个对象的函数的prototype
作用
- 显式原型的作用:用来实现基于原型的继承与属性的共享。
- 隐式原型的作用:构成原型链,同样用于实现基于原型的继承。举个例子,当我们访问obj这个对象中的x属性时,如果在obj中找不到,那么就会沿着
__proto__
依次查找。
__proto__的指向
__proto__
的指向到底如何判断呢?关键的点在于找到创建这个对象的构造函数,接下来就来看一下JS中对象被创建的方式,一眼看过去似乎有三种方式:
(1)对象字面量的方式
(2)new 的方式
(3)ES5中的Object.create()
但是本质上只有一种方式,也就是通过new来创建。为什么这么说呢,首先字面量的方式是一种为了开发人员更方便创建对象的一个语法糖,本质就是var o = new Object(); o.xx = xx;o.yy=yy;
再来看看Object.create()
,这是ES5中新增的方法,在这之前这被称为原型式继承
function object(o){
function F(){}
F.prototype = o;
return new F()
}
这种方法并没有使用严格意义上的构造函数。它是借助原型可以基于已有的对象创建新对象,同时还不用创建自定义类型
所以从实现代码return new F()
中我们可以看到,这依然是通过new
来创建的。不同之处在于由 Object.create()
创建出来的对象没有构造函数 (没有constructor
,打印constructor
输出的是Object
),看到这里你是不是要问,没有构造函数我怎么知道它的__proto__
指向哪里呢,其实这里说它没有构造函数是指在Object.create()
函数外部我们不能访问到它的构造函数,然而在函数内部实现中是有的,它短暂地存在了那么一会儿。假设我们现在就在函数内部,可以看到对象的构造函数是F
, 现在
//以下是用于验证的伪代码
var f = new F();
//于是有
f.__proto__ === F.prototype //true
//又因为
F.prototype === o;//true
//所以
f.__proto__ === o;
因此由Object.create(o)
创建出来的对象它的隐式原型指向o
。好了,对象的创建方式分析完了,现在你应该能够判断一个对象的__proto__
指向谁了。
例子巩固
内建对象
内建对象(built-in object):比如Array()
,Array.prototype.__proto__
指向什么?Array.prototype
也是一个对象,对象就是由 Object()
这个构造函数创建的,因此Array.prototype.__proto__ === Object.prototype //true
,或者也可以这么理解,所有的内建对象都是由Object()
创建而来。
自定义对象
默认情况下
function Foo(){}
var foo = new Foo()
Foo.prototype.__proto__ === Object.prototype //true 理由同上
其他情况
(1)
function Bar(){}
//这时我们想让Foo继承Bar
Foo.prototype = new Bar()
Foo.prototype.__proto__ === Bar.prototype //true
(2)
//我们不想让Foo继承谁,但是我们要自己重新定义Foo.prototype
Foo.prototype = {
a:10,
b:-10
}
//这种方式就是用了对象字面量的方式来创建一个对象,根据前文所述
Foo.prototype.__proto__ === Object.prototype
注: 以上两种情况都等于完全重写了Foo.prototype,所以Foo.prototype.constructor也跟着改变了。
instanceof
instanceof
操作符的内部实现机制和隐式原型、显式原型有直接的关系。instanceof
的左值一般是一个对象,右值一般是一个构造函数,用来判断左值是否是右值的实例。它的内部实现原理是这样的:
//设 L instanceof R
//通过判断
L.__proto__.__proto__ ..... === R.prototype ?
//最终返回true or false
也就是沿着L的__proto__一直寻找到原型链末端,直到等于R.prototype为止。
Function instanceof Object // true
Object instanceof Function // true
Object.__proto__ === Function.prototype //true
Function instanceof Function //true
Object instanceof Object // true
Number instanceof Number //false
function Person() {}
let p = new Person();
console.log(p instanceof Person); // true
console.log(Person instanceof Person); // false