本文已参与「新人创作礼」活动,一起开启掘金创作之路。
什么是原型
原型对象
- 在JS中,构造函数有一个prototype属性,该属性指向另一个对象;这个对象的所有属性和方法,都会被构造函数拥有;
- prototype属性里面的所有属性和方法都是公共的,都会被构造函数所生成的所有实例继承;这就意味着,我们可以把公共的属性和方法,直接定义在prototype属性上面;
function Person(){}
Person.prototype.sayHi = function() {}
// 实例化对象
let d1 = new Person()
d1.sayHi()
let d2 = new Person()
d2.sayHi()
- 将公用的方法定义在原型对象上面,实例化对象时不会开辟新的空间,有利于性能的提升;
- 可以通过原型对象,对原来的内置对象进行自定义的扩展:
Array.prototype.sum = function(){ // code }
对象原型
- 通过构造函数实例化的对象上面默认有一个__proto__属性,指向构造函数的原型对象;
- d1.proto === Person.prototype;
- 正是有对象原型的存在,当在对象自身找不到对应的属性和方法时,会到原型对象prototype上面去找;
constructor属性
- 原型对象和对象原型上都有constructor属性,该属性指向构造函数本身;
- constructor属性主要是记录该对象引用自哪个构造函数,它可以让原型对象重新指回原来的构造函数,有如下的情形:
function Star () {
this.name = 'demo'
}
console.log(Star.prototype.constructor === Star) // true
Star.prototype = {
name: 'john'
}
console.log(Star.prototype.constructor === Object) // true
// 这里prototype被Object构造函数的实例覆盖,所以constructor属性指向Object构造函数
function Moon () {
this.name = 'David'
}
let currentMoon = new Moon()
Star.prototype = currentMoon
console.log(Star.prototype.constructor === Moon) // true
// 这里currentMoon 是Moon构造函数的实例,当prototype直接被该对象覆盖,constructor属性指向了Moon构造函数
- 为了解决这样的问题,我们将constructor属性指向原来的构造函数即可:
Star.prototype.constructor = Star
console.log(Star.prototype.constructor === Moon) // false
构造函数,实例,原型对象之间的关系
- 为了更加清晰地展示它们之间的关系,画图无疑是更直接的方式(以Star构造函数为例);
原型链
-
有了上面对原型的了解,顺势就能引出原型链的存在方式,我们还是以Star构造函数为例:
- 首先Star构造函数实例对象的__proto__指向Star的prototype属性;
- prototype属性也是一个实例对象,它是由Object构造函数实例而来,所以它的__proto__属性指向Object.prototype;
- 最后Object.prototype.proto 指向null,此时也标志这原型链的结束;
- 当然图解的方式还是最清晰的:
-
正是因为原型链的存在,当我们想要查找属性和方法时,在当前对象找不到时,就沿着原型链寻找,如果找到,那么就直接返回;否则就一直找下去,直到到原型链的末尾null才会结束;
-
在实际的开发中,我们不会直接用到对象原型__proto__,它存在的意义就是将原型对象进行链接,进而形成一个链条,或者说形成一条路线;
-
有了原型链的存在,我们可以做些什么?
- 我们可以将公用的属性和方法定义在原型对象上,由于原型链的存在,实例对象都可以使用这些属性和方法;
- 利用原型链可以实现子类继承父类的属性和方法;(原型链继承)
具体分析Function和Object之间的关系
- js中一切皆是对象,函数也是对象的一种,函数对象;
- 函数对象都是由Function构造函数生成的实例:
function fn() {}
console.log(fn.**proto** === Function.prototype) // true
- Object构造函数也是函数,也是由Function生成的实例:
console.log(Object.**proto** === Function.prototype) // true
- Function本身也是函数,也是由Function生成的实例:
console.log(Function.**proto** === Function.prototype) // true
- 所有对象都是Object的实例,包括Function.prototype也是一个普通的对象:
console.log(Function.prototype.**proto** === Object.prototype) // true
-
下面做一个简单的总结:
- 所有的对象都是继承自Object对象,Object对象直接继承根对象null;
- 一切函数对象,包括构造器函数,都是继承自Function对象;
本文可作为学习笔记,如果觉得有帮助,请多多点赞加评论!