原型链是为了实现继承,也就是说 js 的继承是基于原型链的。
原型-prototype,是一个对象,用于存放共享的属性和方法的。
原型主要有这么几个概念:
__proto__
、prototype
、constructor
__proto__
?js 会为每个 对象
添加一个属性,这个属性指向另外一个对象的prototype
,js 可以通过 Object.getPrototypeOf(obj)获取
,chrome 浏览器实现为__proto__
。
prototype
?js 会为每个 函数
添加一个prototype
属性,表示自己的原型对象。
prototype
是个对象。
constructor
?是 js 创建和初始化对象的方法,如果没有自己指定constructor
,则会默认有个空的constructor
。
原型对象的constructor
指向自己的创造者,每个原型对象都有constructor
。所有对象都会从它的原型上继承 constructor
属性。
Tips:
__proto__
属性。Object.prototype.__proto__ === null
。Object
函数的 prototype.__proto__
都是 Object.prototype
。Object
函数的 __proto__
永远指向 prototype
。⚠️ 注意:这里有个特殊的函数:
Function
,任何函数都是Function
的实例,包括Object
。所以Function
可以说是根构造函数。所以
Object.__proto__
就是Function.prototype
所以
Function.__proto__
也是Function.prototype
以上就是主要知识点,为了理解咱们举个 🌰:
创建一个普普通通的函数 A
function A() {}
此时 A
里面有prototype
,__proto__
两个属性。
A
同时继承了 A.prototype.constructor
A.prototype
A.prototype
就是它的原型对象,里面有什么?
有constructor
和__proto__
,为什么会有__proto__
?
因为 prototype
也是个对象。
A.prototype.constructor
指向了谁?
当然是 A
,prototype
里面的constructor
指向它的函数。
A.prototype.__proto__
指向了谁?
当然是 Object.prototype
,因为 默认情况下,任何函数的原型属性__proto__
都是 Object.prototype
。
A.__proto__
A.__proto__
是什么?
应该知道它指向一个 prototype
,那么是谁的 prototype
?
当然是 Function
的。因为它也是由 Function
创建的。__proto__
是由浏览器实现的,不是标准写法,Object
提供了获取原型的方法:
getPrototypeOf
Object.getPrototypeOf(A)
A.constructor
A.constructor
,实际是 A.prototype.constructor
,指向自己的创造者:Function
创建一个 A
的实例:
a = new A();
根据上面讲述,a 会有 __proto__
和constructor
两个属性,并且 a.__proto__ === A.prototype
:
a.constructor
为 a.__proto__.constructor
。
如果这个时候 A.prototype
中如果有属性,或者方法,a
都是可以调用的。
两个对象通过 __proto__
连接,就组成了原型链。
可以给对象指定原型(不建议这么做),这里举例仅是为了理解原型链。将 A
的实例赋值给 B
的原型,这样可以理解为 B
继承了 A
,B
创建的实例 b
也可以调用 A
原型中的方法了:
整体结构图如下:
从上面例子可以看出 js 创建一个对象(使用 new 操作符)大致过程:
constructor
加工创建一个对象:
<!-- new 一个 A 对象 -->
function newA(...args) {
var self = Object.create(A.prototype)
var res = A.prototype.constructor.call(self, ...args)
if (typeof res === 'object' && res !== null) {
return res
}
return self
}
像 Array
中的 forEach
,find
,filter
等都是在 Array.prototype
上,这样的内置对象还有很多。
es6 实现了 class
语法糖,实际还是应用原型链。
// function A(name) {
// this.name = name;
// }
// A.prototype.run = function() {
// console.log(`${this.name} running...`);
// };
class A {
constructor(name) {
this.name = name;
}
run() {
console.log(`${this.name} running...`);
}
}
但是不建议修改内置对象的原型,会产生一些副作用,比如:
觉得有帮助的话,不妨考虑购买付费文章来支持我们 🙂 :
付费文章