原型链
前言
最近在恶补 JS 基础,什么闭包、作用域链、词法环境、事件循环 balabala…人都补傻了…
大概这就是半路出家学前端的代价吧 QAQ。
今天先来把最近刚刚啃透的原型链知识梳理一下。
几个概念
这几个概念是理解原型链的基础,非!常!重!要!
万物皆为对象
在 JS 中,除了 null、undefined 之外的所有数据类型都是对象。
没错, NaN 也是对象,NaN 本质上是 number。
普通对象
就是对象(废话)。
普通对象都会拥有 __proto__ 属性。
{}是普通对象。var foo = new Foo(),foo是普通对象。"abc"是普通对象。123是普通对象。NaN也是普通对象。
函数对象
就是函数。
函数对象都会拥有 prototype 属性,函数对象同时也是普通对象,所以也拥有 __proto__ 属性。
function A() {}是一个函数对象。String、Number、Object、Function等都是函数对象。
普通对象是函数对象的实例
下面这几个例子看一下,相信就能理解了
{}是Object的实例,我们平时看到的var obj = {}其实等于var obj = new Object({})foo是function Foo() {}的实例1
2function Foo() {}
var foo = new Foo();"abc"是String的实例123是Number的实例NaN也是Number的实例
prototype
prototype 即是对象的原型
__proto__
__proto__ 串起原型形成了原型链,可以理解 __proto__ 指向该对象继承的父对象
几个准则
总结出来的几个规律,能记住基本上吴迪!
准则一
普通对象的 __proto__ 指向实例化它的函数对象的 prototype。
所以:
__proto__串起原型形成了原型链
例子
1 | function Foo() {} |
准则二
函数对象的原型上的 constructor 指向函数对象本身。
例子
1 | function Foo() {} |
准则三
函数对象都是 Function 类型的实例,包括 Object,也包括 Function 本身。
例子
1 | function Foo() {} |
准则四
除了 Object 以外的函数对象的原型都继承于 Object 的原型
Object 的原型继承于 null,即原型链的顶端为 null
例子
1 | function Foo() {} |
准则五
获取普通对象的属性时,若不能在普通对象本身上找到,则去原型链上获取。
即先从其 __proto__ 上获取,若还是没有,则继续去其 __proto__.__proto__ 上获取,直到原型链顶端或找到为止。
例子
foo 上并未定义 toString 方法,但是能拿到,是因为会在原型链上找。
1 | function Foo() {} |
test 未定义且原型链上也找不到该属性,所以会报错;
若在 Object 的原型上加上该属性的话,即可获取到,也证明了原型链的逻辑。
1 | foo.test; // Uncaught ReferenceError: foo is not defined |
准则六
所有某一对象的实例,共享同一个对象原型,对象原型是一个 Object 的实例;
已经创建的实例的 __proto__ 引用不会改变;
若对象原型设置为了非引用类型,则新的实例的 __proto__ 会直接指向 Object.prototype。
例子
引用相同。
1 | function Foo() {} |
改变引用。
1 | Foo.prototype = { newTest: 1 }; |
设置原型为非引用类型。
1 | Foo.prototype = 'test'; |
总结
我个人就不总结了,直接上一张非常经典的图,这张图比任何总结都来的直观。
如果能利用上面的原理、准则过一遍,基本上就没问题了!






