原型的概念
每个函数都有一个prototype属性,因为这个属性是一个对象,所以也称作为原型对象。
function f(){
return "你好"
}
typeof (f.prototype) //object
原型的作用
1.可存放一些属性和方法
function f(){
return "你好"
}
f.prototype.color = "white"
f.prototype.dec = function (){
console.log("你好啊")
}
var A = f.prototype
console.log(A.color) //white
A.dec() //你好啊
2.可以实现继承
在第一点的代码实现中,我们将f函数对应的原型对象赋给了A,那么A就可以使用原型中的属性和方法,这就是一种继承。
当然我们可以用别的定义方式:
var A = new f()
那么这种定义方式我们是不是见过呢?
当我们定义一个数组的时候,是通过以下方法来定义的
const arr = new Array(1,2,3)
定义完成后,我们就可以使用数组的一些方法,比如arr.reverse()和arr.join()等,那么这些方法是从哪里来的呢??
同上,数组的构造函数Array()也有一个原型对象,其中就包括了很多的方法供我们使用。
当我们查看官方文档中的方法时,发现它是这么写的:
这就是为什么我们声明了一个数组就可以使用这些方法的原因,因为这些方法都挂载在了Array()的原型对象中。
那么我们的实例是如何与Array.prototype建立联系的?
这里就要提到一个属性:__proto__,(两个下划线)该属性是每个函数实例都有的一个属性,可以指向上一级的原型对象,我们刚才实例化的arr里的__proto__就指向了Array.prototype从而使我们可以调用它的方法。
原型链
我们已经知道了每个对象都有一个__proto__属性用来指向上一级的原型对象,并且知道每个对象都有该属性,那么上一级的原型对象肯定也有__proto__属性,同时该__proto__属性也指向了一个原型对象。
当我们要调用一个对象的方法,但是该方法并不存在时,此时就会寻找上一级来查看是否有该方法,若还没有则继续往上寻找,直到寻找到所有对象的父类Object时,这时Object.prototype的__proto__属性指向的是null,那么查找过程中这样一层一层的链式结构就叫做原型链。