js中的对象分为两种:普通对象object和函数对象function。html
function fn1(){}; var fn2 = function(){}; var fn3 = new Function(); var fn4 = Function(); var obj1 = new fn1(); var obj2 = {}; var obj3 = new Object(); var obj4 = Object(); console.log(typeof fn1);//function console.log(typeof fn2);//function console.log(typeof fn3);//function console.log(typeof fn4);//function console.log(typeof obj1);//object console.log(typeof obj2);//object console.log(typeof obj3);//object console.log(typeof obj4);//object
还有就是全部的构建函数好比Function、Object、Number等等都是函数对象,这个共知的。chrome
//全部的构建函数都是function类型的 console.log(typeof Object);//function console.log(typeof Function);//function console.log(typeof Number);//function
全部的这类构建函数使用new或者直接调用方式都能构建出一个新的数据类型。可是构建出来的数据有区别的函数
var o = new Object(), o1 = Object(); console.log(o == o1);//false console.log(o === o1);//false var f = new Function(), f1 = Function(); console.log(f == f1);//false console.log(f === f1);//false var a = new Array(), a1 = Array(); console.log(a == a1);//false console.log(a === a1);//false var n = new Number(), n1 = Number(); console.log(n == n1);//true console.log(n === n1);//false var s = new String(), s1 = String(); console.log(s == s1);//true console.log(s === s1);//false var b = new Boolean(), b1 = Boolean(); console.log(b == b1);//true console.log(b === b1);//false //数据类型null/undefined是没有构造函数的
上面的例子中Object/Function/Array的对比结果都好说,由于他们构建出来的都是新的对象,对象比较是要比较根源(数据是不是同一个)。不管是使用new仍是直接调用生成一个新的对象是要开辟新的空间存储的,不会和任何一个对象相等。spa
可是对于数值类型,比较符“==”只是比较值相等,比较符"==="除了比较值之外还要比较数据类型。prototype
那么构建数值类型比较为何呈现上面的样子?指针
咱们以Number为例。实际上new Number()构建出来的变量n是一个特殊的对象,chrome上的展现以下code
只不过这个对象和数值类型比较的时候被当作数值类型来比较。当使用“===”的时候比较数值相等时再比较数据类型的时候是有别于其余数值类型的。htm
上面提到了和数值类型比较的时候才成立,若是这个对象和其余对象比较则使用对象比较的规则。对象
好比下面的例子blog
var num = new Number(0); var str = new String(0); var str1 = String(0); console.log(num == str);//false console.log(num == str1);//true console.log(num === str1);//false
num和str都是比较特殊的对象,str1为数值类型。num和str比较实用对象比较的规则来,num和str1比较实用数值比较的规则来。
上面分析了那么多,如今进入正题。
普通对象是没有prototype属性的,只有隐藏属性__proto__(IE上也有该隐藏属性,可是使用obj.__proto__不能输出东西,因此建议不要使用__proto__属性)。而函数对象则二者兼有。prototype属性指向的是函数对象的原型对象,对象的__proto__属性是建立实例对象的时候对应的函数对象的原型对象。
这里咱们须要理解原型对象的值是怎么来的。原型对象的值实际上就是在函数建立的时候,建立了一个它的实例对象并赋值给它的prototype。过程以下(以Function为例)
var temp = new Function(); Function.prototype = temp;
因此咱们看一下熟知的函数的原型对象吧
//chrome下的显示效果 Function.prototype;//function() {} Object.prototype;//Object {} Number.prototype;//Number {[[PrimitiveValue]]: 0} Boolean.prototype;//Boolean {[[PrimitiveValue]]: false} Array.prototype;//[] String.prototype;//String {length: 0, [[PrimitiveValue]]: ""}
说道这里,必须提的是全部函数对象的原型对象都继承制原始对象,即fn.prototype.__proto__为原始对象(原始对象在继承属性__proto__中有定义)。这其中比较特别的是Object函数,他的原型对象就是原始对象,即Object.prototype。
var f1 = new Function(); var f2 = Function(); var fn3 = function(){} console.log(f1.prototype.__proto__ === Object.prototype);//true console.log(f2.prototype.__proto__ === Object.prototype);//true console.log(f2.prototype.__proto__ === Object.prototype);//true console.log(Number.prototype.__proto__ === Object.prototype);//true console.log(Boolean.prototype.__proto__ === Object.prototype);//true
实际上js没有继承这个东东,可是__proto__却起到了相似继承的做用。咱们所知的全部的对象起源都是一个空对象,咱们把这个空对象叫作原始对象。全部的对象经过__proto__回溯最终都会指向(所谓的指向相似C中的指针,这个原始对象是惟一的,整个内存中只会存在一个原始对象)这个原始对象。用下面的例子佐证
var o = new Object(); o.__proto__;//Object {} o.prototype;//undefined Object.prototype;//Object {} Object.__proto__;//function(){} Object.__proto__.__proto__;//Object {} var f = new Function(); f.__proto__;//function(){} f.prototype;//Object {} Function.prototype;//function(){} Function.__proto__;//function(){} Function.__proto__.__proto__;//Object {}
原始对象的__proto__属性为null,而且没有原型对象。
全部的对象都继承自原始对象;Object比较特殊,他的原型对象也就是原始对象;因此咱们每每用Object.prototype表示原始对象。
//全部的对象都继承自原始对象 //Object比较特殊,他的原型对象也就是原始对象 //因此咱们每每用Object.prototype表示原始对象 Object.prototype === o.__proto__;//true Object.prototype === Object.__proto__.__proto__;//true Object.prototype === Function.__proto__.__proto__;//true
f.prototype的的值貌似也是原始对象?其实不是,咱们在函数对象的原型对象这一段中不是说过吗函数对象f的原型对象其实是函数对象的一个实例。每个实例都是一个新的单独的对象。
new f();//Object {}
全部的函数对象都继承制原始函数对象;Function比较特殊,他的原型对象也就是原始函数对象;因此咱们每每用Function.prototype表示原始函数对象;而原始函数对象又继承自原始对象。
//全部的函数对象都继承制原始函数对象, //Function比较特殊,他的原型对象也就是原始函数对象 Function.prototype === f.__proto__ Function.prototype === Object.__proto__ ;//true Function.prototype === Function.__proto__;//true //因此咱们每每用Function.prototype表示原始函数对象 //而原始函数对象又继承自原始对象 Function.prototype.__proto__ === Object.prototype;
因此对象之间的继承和原型对象结构以下图(引用的别人的js object猜测图)
看了上面的图咱们还知道函数对象的原型对象的构造函数就是函数对象自己。不难理解函数对象的原型对象就是函数对象的实例了吧。
在使用New方法初始化函数的时候(详细点击查看new的深度理解)获得的新对象的__proto__属性会指向函数对象的原型对象,而函数对象的原型对象又继承至原始对象。因此呈现如下结构
function fn(){}; var test = new fn();
把这个有__proto__串起来的直到Object.prototype.__proto__为null的链叫作原型链。原型链实际上就是js中数据继承的继承链。
若是以为本文不错,请点击右下方【推荐】!