js中的类型有:后端
number,string,boolean,object,undefined,function
因此对象能够这么分类:函数
因此函数对象能够大声唱咱们不同,既然不同确定得有一点不同的烟火,函数对象的不同在什么地方呢? 每个函数对象都有一个prototype属性(Function.prototype除外)this
做为一个傻傻的后端的我一直觉得每个对象都有一个prototype属性。每个对象都有的是一个叫作__proto__的隐藏属性,它指向的就是对象所对应的函数对象的prototype(也就是传说中的原型对象)prototype
后面咱们再举例子来讲明原型对象,咱们先看一下那些是函数对象,方便理解。code
function FN() {} var FA = function() {} var FF = new Function('arg1', 'arg2', 'console.log(arg1 + arg2)'); FF('a','b'); console.log('typeof Object:' + typeof Object); //function console.log('typeof Object.prototype:' + typeof Object.prototype); //object console.log('typeof Function:' + typeof Function); //function console.log('typeof Function.prototype:' + typeof Function.prototype); //function console.log('typeof FN:' + typeof FN); //function console.log('typeof FA:' + typeof FA); //function console.log('typeof FF:' + typeof FF); //function
不那么精确的总结一下就是:对象
这里说一下Function.prototype,由于它又是一个不同的烟火。由于通常的函数对象的prototype都是普通对象,可是Function.prototype是一个函数对象,而且这个函数对象没有prototype属性。原型链
全部的函数对象的__proto__都指向的是Function.prototypeget
可使用:原型
console.log(Object.getOwnPropertyNames(Function.prototype))
打印一下Function.prototype的属性,会发现都是一下公共函数。string
咱们把问题简化来处理,看一个最多见的简化的原型链:
function Person(name, age) { this.name = name; this.age = age; this.hobby = function() { return '实例对象hobby'; } } Person.hobby = function() { return '函数对象hobby'; } Person.prototype.hobby = function(){ return 'prototype hobby'; } var p1 = new Person("tim",20); var p2 = new Person("alice",20); console.log(p1.hobby === p2.hobby);//false console.log(p1.__proto__ == Person.prototype);//true console.log(p2.__proto__ == Person.prototype);//true console.log(p1.__proto__ == p2.__proto__);//true console.log(p1.__proto__.hobby == p2.__proto__.hobby);//true console.log(p1.hobby());//实例对象hobby console.log(Person.hobby());//函数对象hobby
从前面介绍的咱们知道Person是一个函数对象,既然是一个函数对象,那么Person是有prototype属性的,因此给Person的prototype的属性添加一个hobby属性也是合理的事情了。
Person是一个函数对象,那么说Person是一个对象也是合理的了,给Person添加一个hobby属性也是合理的了。
下面就要看一下关键的new关键字的行为了,咱们知道Person是一个函数对象,new一个函数对象,基本上执行的就是属性拷贝,而后把new出来的对象的__proto__指向函数对象的prototype的属性。
因此上面的p1.hobby === p2.hobby是false是由于他们是2个对象中不一样的属性,是2个不一样的引用。
而p1.proto.hobby == p2.proto.hobby是true是由于这2个都是Person.prototype对象上的属性hobby是同一个引用。
js原型链查找方式就是在当前对象中查找这个属性,若是没有就在__proto__指向的对象中去查找,依次查找到Object.prototype结束,由于Object.prototype.proto == null
下面思考一个问题:若是把上面的:
Person.hobby = function() { return '函数对象hobby'; }
去掉会有问题吗?
答案是会有问题,这个问题有点绕,可是记住咱们前面总结的,全部的函数对象的__proto__指向的都是Function.prototype
全部若是没有上面的代码Person.hobby()这个调用在Person函数对象中找不到hobby属性,就会在Funtion.prototype对象中找,依次找到Object.prototype,显然是找不到的。
注意原型链,不是在Person.prototype中查找,那不在Person对象的原型链。