相信js开发者都知道原型,原型链,可是不少人晕晕乎乎对此不知甚解。下面分享一下个人我的心得。数组
废话不说先上图app
不须要管网上乱七八糟的各类原型链指向图,记住这个就好了。
除了各类指向之外,图中还包含这些信息:函数
__proto__
才是实例的。固然,这个属性不建议使用。能够用Object.setPrototypeOf
和Object.getPrototypeOf
天真的我曾经觉得原型是prototype
,那原型链就是跟着prototype
找...,实在是too young too simple啊。
这里必定要记住,原型链是沿着__proto__
链找。学习
其实这个问题也能够是:当咱们构建对象时,发生了什么。
举个简单例子:this
function father(){ this.name = "爸爸" } father.prototype.family = "爱的家" var dad = new father();
这里进行了以下操做:spa
Object.create()
;用代码模拟就是:prototype
function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ param1) { // 将 arguments 对象转为数组 var args = [].slice.call(arguments); // 取出构造函数 var constructor = args.shift(); // 建立一个空对象,继承构造函数的 prototype 属性 var context = Object.create(constructor.prototype); // 执行构造函数 var result = constructor.apply(context, args); // 若是返回结果是对象,就直接返回,则返回 context 对象 return (typeof result === 'object' && result != null) ? result : context; } // 实例 var actor = _new(Person, '张三', 28);
记住一点,实例化对象之后,构造函数就没什么事了。原型链只看构造函数的原型对象和实例化出来的对象。
这里在说一点,关于,继承。现实中的继承就是你的东西给我了,我拿过来了。我可使用,能够转让。可是js中真是这样吗?
一个很简单的问题,若是原型继承真是把原型中的属性拷过来那我每次自身找不到属性还要沿着原型链查找干吗。
很显然,js中原型可不是二百五,他所谓的继承,只是给你使用权,不会给你转让权。
上面第二步中:将father的[[prototype]]属性委托给father的原型
。我写的是委托。这样描述可能更准确。由于这里只是至关于给实例化对象一个指针,指向了原型对象。这其实也是下一个问题的答案。指针
答案揭晓:
只有经过new调用构造函数才会走第二步,也就是原型的委托操做。
那么怎么判断是否同new调用呢?code
ES6函数内部可使用new.target属性。若是当前函数是new命令调用,new.target指向当前函数,不然为undefined。
ES5对象
if(this instanceof Father){...}
ES6
//在函数外使用new.target是一个错误 typeof new.target !== 'undefined'
这里再多扯一下typeof和instance。反正我之前是每次看了记住了,好久不用又忘了。。。。,看了这么多原型链的内容,再看看这个应该会映象深入吧:
用来判断值类型。如string/number/boolean,但若是判断引用类型,返回值就只有 object/function。因此没法进一步判断是object对象,仍是数组,仍是new Number等等。
注意:
undefined返回undefined。
// 错误的写法 if (v) { // ... } // ReferenceError: v is not defined // 正确的写法 if (typeof v === "undefined") { // ... }
根据原型链判断引用类型。A instanceof B
,判断原则是沿着 A 的__proto__这条线来找,同时沿着 B 的 prototype 这条线来找,若是两条线能找到同一个引用,即同一个对象,那么就返回 true。若是找到终点还未重合,则返回 false。