__proto__(先后都是两条杠)
prototype
constructor
普通对象
函数对象
构造器(构造函数)
实例(实例是个普通对象)
原型
原型对象
ps:第一次认真梳理知识点,有点浅显,但愿读完你所收获。若有错误,也望及时指出,感激涕零!
复制代码
每一个对象都有__proto__ ,而prototype只有函数对象才有
复制代码
答:__proto__
上图中: obj.__proto__ === Object.prototype
复制代码
首先 Object.prototype叫作obj的原型对象,这个对象里包含了全部对外共享的属性和方法。面试
举个例子:数组
var function Person(name){
this.name = name;
}
var p1 = new Person('林蛋大');
console.log(p1.__proto__); //Person.prototype
console.log(p1.__proto__ === Person.prototype); //true
复制代码
其次,咱们在控制台看到了很眼熟很扎眼的 constructor,它是什么鬼?
复制代码
如下写法同 Person.prototype.constructor 直观地用数学思惟理解:等号两边写谁都同样bash
console.log(p1.__proto__.constructor ); //Person
复制代码
也就是说,原型对象里有一个叫constructor的属性,它指向本身的构造器(构造函数) 因此,通常用constructor属性来获取当前对象的构造函数app
以下:函数
p1.constructor === p1.__proto__.constructor
p1.constructor === Person.prototype.constructor
用数学思惟左右置换,互求,是能够的
复制代码
p1这个对象是Person的一个实例,由于它是Person new 出来,Person是它的构造器,因此它的constructor指向了Person;ui
另外,Person.prototype是一个对象,它的constructor也指向了Person,是否是能够理解为:Person.prototype 也是Person的一个实例?this
经过__proto__能够获取原型,一直往一层层获取,一直__proto__直到结果为null就是尽头了。走完这个流程就是走完了你当前对象的原型链。(这一块后面细讲)编码
经过constructor能够获取当前对象的构造函数spa
通俗的理解----prototype
function Person(name) {
this.name = name
}
// 修改原型
Person.prototype.getName = function() {}
var p = new Person('林蛋大')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true
// 重写原型
Person.prototype = {
getName: function() {}
}
var p = new Person('楚中天')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // false
why false????
复制代码
这是由于给Person.prototype赋值的是一个对象直接量{getName: function(){}},使用对象直接量方式定义的对象,它的构造器(constructor)指向的是根构造器Object
因此这个时候p.constructor === Object为true,它如今的构造器是个叫作Object的构造器(构造函数),而已经不是叫作Person的构造器了,你让他们怎么相等?这种继承注定会失败
那么怎么办?这个时候要改很简单,只要把constructor给指回来就行了,这是写原型继承的时候最最最重要的坑!
Person.prototype = {
getName: function() {}
}
var p = new Person('jack')
p.constructor = Person; //就是这一行,核心重点
!
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true
复制代码
上节说到__proto__能够获取原型对象,一直往上获取就能拿到整条链子,怎么个获取法?口说不清咱们直接看代码:
var function Person(name){
this.name = name;
}
var p1 = new Person('林蛋大');
//不打印的话,你知道如下会输出什么吗?
1. p1.__proto__ ?
2. Person.__proto__ ?
复制代码
你先把这图放脑子里等着,咱们先来分析第2题,:
p1.__proto__ ? Person.prototype
p1.__proto__.__proto__?
复制代码
综上所述,第2题要求的是p1的构造器的原型对象。 答案以下:
Person.prototype.__proto__ ?Object.prototype
骚问法:
p1.__proto__.__proto__ ?Object.prototype
变态问法:
p1.constructor.__proto__ ? Object.prototype
p1.__proto__.constructor.prototype.__proto__ ? Object.prototype
Person.prototype.constructor.prototype.__proto__ ? Object.prototype
晕了?请翻到上面两个constructor的等式,左右置换一下:
p1.__proto__.constructor 就是Person
Person.prototype.constructor 就是Person
懂了吧?嘿嘿~
复制代码
第2题分析完了,咱们来看看链子怎么求。
咱们往上追溯原型链的目的,无非就是找些方法或者属性来知足当前的coding须要,因此---
由 p1.__proto__ 获得 Person.prototype,发现构造器Person的集合里没有咱们想要的
复制代码
由 Person.__proto__ 获得 Function.prototype,发现构造器Function的集合里仍是没有
复制代码
由 Function.__proto__ 获得 Object.prototype,发现构造器Object的集合里仍是没有
复制代码
由 Object.__proto__ 获得 null,纳尼????
复制代码
祖宗十八代找遍,都找到类人猿了,仍是没有找到咱们要用的方法或者属性,只有一个解释:你要找的家伙还没有出世(不存在)。
打个比方就是p1的家族世代修炼,每一代都修炼出本身的独门绝学,而后传给后代,最后面的p1就继承到了以上全部祖宗的绝学(属性和方法)
console.log(p1.arguments) // arguments 从哪里来的?
console.log(Person.call(window)) // call 方法从哪里来的?
复制代码
console.log(Function.prototype) // function() {} (一个空的函数)
console.log(Object.getOwnPropertyNames(Function.prototype));
/* 输出
["length", "name", "arguments", "caller", "constructor", "bind", "toString", "call", "apply"]
*/
复制代码
顺利被咱们找出arguments和call,getOwnPropertyNames是顶级公民Object.prototype里的属性和方法,全部的对象都能继承到它的属性和方法,它的角色至关于老祖宗(初代)你们自行打印一下,它的方法和属性很是多。
可是!Function.prototype竟然是个空函数,为何?请看下一节
先无论它是空函数什么的,来看看下列JS世界中各种构造器的原型,你会很惊讶他们都是同一个:
Number.__proto__ === Function.prototype // true
Number.constructor == Function //true
Boolean.__proto__ === Function.prototype // true
Boolean.constructor == Function //true
String.__proto__ === Function.prototype // true
String.constructor == Function //true
// 全部的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身
Object.__proto__ === Function.prototype // true
Object.constructor == Function // true
// 全部的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身
Function.__proto__ === Function.prototype // true
Function.constructor == Function //true
Array.__proto__ === Function.prototype // true
Array.constructor == Function //true
RegExp.__proto__ === Function.prototype // true
RegExp.constructor == Function //true
Error.__proto__ === Function.prototype // true
Error.constructor == Function //true
Date.__proto__ === Function.prototype // true
Date.constructor == Function //true
复制代码
以下
Math.__proto__ === Object.prototype // true
Math.construrctor == Object // true
JSON.__proto__ === Object.prototype // true
JSON.construrctor == Object //true
复制代码
上面说的函数对象固然包括自定义的。以下
// 函数声明
function Person() {}
// 函数表达式
var Perosn = function() {}
console.log(Person.__proto__ === Function.prototype) // true
console.log(Man.__proto__ === Function.prototype) // true
复制代码
这些打印结果说明:全部的构造器(构造函数)都来自于 Function.prototype,甚至包括根构造器Object及Function自身。因此全部构造器都继承了Function.prototype的属性及方法。 故,函数是惟一一个typeof 结果是function 的类型。
那么上一节的问题,说Function.prototype怎么是个空函数啊?不止是它,若是你求Array构造器的原型,也是一个空数组:
console.log(Function.prototype) // function() {} (一个空的函数)
console.log(Array.prototype) // [ ] (一个空的数组)
复制代码
怎么办?故技重施啊!它本身没有,它的原型确定有鸭!
//首先 Function.prototype/Array.prototype是个对象
console.log(Function.prototype.__proto__ === Object.prototype ) //true
console.log(Array.prototype.__proto__ === Object.prototype ) //true
//Object.prototype的原型呢?null,到世界的尽头了
console.log(Object.prototype.__proto__ === null )//true
复制代码
若是 Object.prototype.__proto__ === Function.prototype 为true,
那么继续往上找 Function.prototype.__proto__ === Object.prototype
再继续往上 Object.prototype.__proto__ === Function.prototype
再再继续往上 Function.prototype.__proto__ === Object.prototype
.........
复制代码
function Person(name) {
this.name = name
}
var p2 = new Person('king');
核心点:__proto__是求原型对象的,也就是求构造器的prototype属性 ===>原型对象是构造器的一个属性,自己是个对象
constructor 是求构造器的 ====> 构造器的prototype属性的对象集合里也有constructor,这个prototype里的constructor指向构造器本身
console.log(p2.__proto__)//Person.prototype
console.log(p2.__proto__.__proto__)//结合上题,也就是Person.prototype的__proto__,Person.prototype自己是个对象,因此这里输出:Object.prototype
console.log(p2.__proto__.__proto__.__proto__)//同理,这里是求Object.prototype的__proto__,这里输出:null
console.log(p2.__proto__.__proto__.__proto__.__proto__)//null后面没有了,报错
console.log(p2.__proto__.__proto__.__proto__.__proto__.__proto__)//null后面没有了,报错
console.log(p2.constructor)//Person
console.log(p2.prototype)//undefined p2是实例对象,不是函数对象,是没有prototype属性滴
console.log(Person.constructor)//Function 一个空函数
console.log(Person.prototype)//打印出Person.prototype这个对象里全部的方法和属性
console.log(Person.prototype.constructor)//Person
console.log(Person.prototype.__proto__)//Person.prototype是对象,因此输出:Object.prototype
console.log(Person.__proto__)//Function.prototype
console.log(Function.prototype.__proto__)//Object.prototype
console.log(Function.__proto__)//Function.prototype
console.log(Object.__proto__)//Function.prototype
console.log(Object.prototype.__proto__)//null
复制代码