原型与原型链
# 原型与原型链
# 知识背景
原型在平时工作中用得比较少, 但原型是 JavaScript 中的基础, 是构建大型应用, 框架不可或缺的一环, 是你在写代码时, 不知不觉就应用上了的一个最基础的知识.
# 原型
任何一个函数, 都拥有一个 prototype 属性, 它指向这个函数的原型对象, 如
function Foo() {}
console.log(Foo.prototype); // { constructor: f Foo(), __proto__: Object }
//浏览器显示的是__proto__指向的对象<prototype>: Object { … }
图表如下
上图左边代表
Foo
函数, 它有一个prototype
属性, 指向右侧这个原型对象, 每声明一个函数, 都会有这样的一个原型对象, 原型对象有一个constructor
属性。constructor
指向构造函数Foo
本身。
我们来看Foo
的实例化foo
,任何构造函数的实例化都有__proto__
属性,它指向构造函数的原型。
function Foo() {}
var foo = new Foo();
console.log(foo); //{__proto__:object}
//浏览器显示的是__proto__指向的对象<prototype>: Object { … }
图表如下
foo
默认会有个__proto__
属性, 它也指向构造函数Foo
的原型, 这就是__proto__
的作用, 即指向构造函数的原型。然而
Foo.prototype
也具有__proto__
属性,那么它又指向谁的原型呢?所以让我们回到
Foo.prototype.__proto__
, 来看看他的指向
图表如下
上图的
Foo.prototype.__proto__
指向Object.prototype
, 也就是说, 每个函数的原型, 都是 Object 的实例. 就好像每个函数的原型, 是由new Object()
产生一样以上就是关于原型的阐述, 如果看到这里似懂非懂, 建议反复看几遍, 注意文字与图片对应, 线条的指向, 看懂了再接着往下看.
# 原型链
原型链是 JavaScript 作者为了继承而设计的, 由上边的分析,
const foo = new Foo()
语句, 其实是产生了一个链条的, 如下:
我们在 new 出
foo
对象后, 并没有给foo
对象添加任何方法, 但我们依然能从foo
对象中调用toString()
,hasOwnProperty()
等方法. 这是为什么呢?
console.log(typeof foo.toString); // function
console.log(typeof foo.hasOwnProperty); // function
原因是, JavaScript 在设计之初,
__proto__
就是用来查找属性和方法的, 从上图的链条来看, 我们在foo
这个对象中, 查找 toString 方法, 没找到, 就循着foo.__proto__
查找,foo.__proto__
里也没有找到, 就循着foo.__proto__.__proto__
找, 诶这个时候找到了, 则调用, 如果还找不到, 就再往上找, 即foo.__proto__._proto__._proto__
, 这个时候值为null
, 查找结束.这就是原型链, 我们也可以说,
Foo
继承了Object
, 所以foo
中能访问到 Object 的原型属性.