原型里最核心的三句话
1.每个函数都有一个prototype
(原型)属性,该属性值为一个对象(分配堆内存)
2.每个prototype
指向的堆内存中,有一个constructor
属性,该属性的值指向函数本身
3.每个对象都有一个__proto__
属性,该属性指向当前实例所属类的prototype
属性(如果不能确定是谁的实例,则都为Object的实例)
下面将以画图的方式解释这三句话
都知道有数组Array
这样一个类 ,它有一个prototype
属性,指向一个堆内存,堆内存有一个consturctor
属性
Array.prototype.constructor === Array //true
//现在创造一个这个类的实例
let a = new Array(1,2,3) //其实等同于let a = [1,2,3]
a里面有个__proto__
属性,指向Array
的prootptype
因为Array.prototype
是一个对象,且不能确定Array.prototype
属于谁的实例 (注意!它是Array的属性),所以它属于Object
的实例,且他的__proto__
属性指向Object
的prototype
这样看来,最后因为Object.prototype
也有__proto__
属性,但他总不能自己指向自己吧,所以最后Object.prototype.__proto__
指向null 。
原型链
这是一种基于__proto__
向上查找的机制
当我们操作实例的属性或方法时,先找自己空间中私有的属性或方法,找到就返回。
找不到就继续往上找类的prototype
里是否存在该属性或方法,如果还是没找到,就一直往上找,直到最后一层Object.prototype
里都没有,则报错找不到该方法。
下面代码用于检测是否清楚
function fn (){
let n = 5;
this.say = function () {console.log("my");}
}
fn.prototype.say= function (){console.log("all");}
let fn1 = new fn();
fn1.say() // "my"
fn1.say===fn.prototype.say // false
fn1.__proto__.say===fn.prototype.say // true
fn1.hasOwnProperty===fn.hasOwnProperty // true
fn1.name // -->设置私有属性
fn1.__proto__.name //-->设置共有属性