什么是原型

在 JavaScript 中继承是基于原型继承的。例如创建一个对象

1
2
3
4
const obj = { name: 'xiaokang' }

console.log(obj.name) // xiaokang
console.log(obj.toString()) // [object Object]

那么问题来了,既然我没有给obj定义toString()方法,那么为什么可以正常输出呢?原因就是因为继承了原型对象中的方法。

那么什么是原型对象呢?

对于实例对象来说,每一个实例对象"身上"都有一个__proto__属性,这是每个对象都有的隐式原型属性,该属性指向该对象构造函数的原型对象。

image-20221129201841348

当我们点开__proto__.constructor属性时,会发现存在一个与__proto__一模一样的数据prototype

1
obj.__proto__ == obj.__proto__.constructor.prototype // true

image-20221129202536393

因此对象的原型对象即该对象构造函数所创建的对象。没错,原型也是对象。

什么是原型链

原型链其实更多的描述的是一种关系,例如上面介绍原型时调用的toString()方法,在我声明的对象中并未声明该对象,但又可以调用。这边是通过原型链找到了该对象的原型上的方法。

因此原型链就是多个对象通过 __proto__ 的方式连接了起来,从而进行了在一条链路上寻找所调用的属性或方法。

函数的原型还有一个特殊的属性prototype,这个属性只有函数拥有,他是一个显示原型。(除let fun = Function.prototype.bind()之外)

1
2
3
4
5
6
function Foo() {}
Foo.prototype.sayHi = function () {
console.log('hi')
}
const foo = new Foo()
foo.sayHi() // hi

image-20221129204255868

1.对象有属性proto,指向该对象的构造函数的原型对象。

2.方法除了有属性proto,还有属性 prototype,prototype 指向该方法的原型对象。

指向

  • Object 是所有对象的爸爸,所有对象都可以通过 __proto__ 找到它
  • Function 是所有函数的爸爸,所有函数都可以通过 __proto__ 找到它
  • Function.prototypeObject.prototype 是两个特殊的对象,他们由引擎来创建
  • 除了以上两个特殊对象,其他对象都是通过构造器 new 出来的
  • 函数的 prototype 是一个对象,也就是原型
  • 对象的 __proto__ 指向原型, __proto__ 将对象和原型连接起来组成了原型链