一,回顾原型链的知识
1,Object也是个函数,而任何函数都是Function的实例对象。
2,Function可以看作Function自身的实例,所以它的显示原型和隐式原型都指向Function.prototype。
3,任何对象都是Object的instance,因为原型链的顶端都指向Object.prototype。
二,Object.prototype.toString方法的理解
在Object.prototype上有一个toString方法,返回的是值类型。也就是说它可以精准地判断输入值的数据类型。
function f1(){
var a=1
}
console.log(Object.prototype.toString.call(f1)) //[object Function]
console.log(Object.prototype.toString.call([])) //[object Array]
console.log(Object.prototype.toString.call({})) //[object Object]
console.log(Object.prototype.toString.call(null)) //[object Null]
console.log(Object.prototype.toString.call(undefined)) //[object Undefined]
console.log(Object.prototype.toString.call(1)) //[object Number]
这里利用call,就是改变this指向,让()里面的来调用Object.prototype.toString方法
至于第一点,为啥讲原型链的知识,那是因为,既然Object的原型对象上有toString方法,JavaScript中,所有类都是Object的实例对象,因此toString()方法应该也被继承了,那为啥又要调用Object.prototype.toString方法,而不直接使用toString方法,让它自己顺着原型链找到这个.toString方法然后调用呢????
实际上,所有类在继承Object的时候,改写了toString()方法。
而只有Object原型上的方法是可以输出数据类型的。因此我们想判断数据类型时,也只能使用原始方法。继而有了此方法:Object.prototype.toString.call(obj)
三,那它们把tostring改写成啥样了?
1,先来看看这个tostring被改写了定义在原型链的什么位置上:
var arr=[1,2,3]
console.log(Array.prototype.hasOwnProperty('toString')) //true
console.log(Array.hasOwnProperty('toString')) //false
console.log(arr.hasOwnProperty('toString')) //false
这说明,每一种类型都把toString方法改写在了自己的对应的原型对象上(除了Object未改写),于是在构建对应的数据时,才会有:“所有对象都有自己的toString方法” 的说法,也就是说,正常的实例对象(除了obj),顺着它的原型链上查找,都能找到两个toString方法:
一个是定义在Object.prototype上的:用来精准判断数据类型的(只有Object.prototype上有)
另一个是定义在各类别构造函数的原型对象上的:它的作用,下一点讲。
经过验证:只有Function、Array、Boolean、String、Number的prototype上有转化字符的toString()
2,定义在各类别构造函数的原型对象上的toString方法的作用
toString:由名字可以看出此方法是将传入的数据类型转换成字符串输出(null和undefined除外)
var num = 123
num.toString() // '123'
var str = 'hello'
str.toString() // 'hello'
var bool = false
bool.toString() // 'false'
var arr = [1, 2, 3]
arr.toString() // '1,2,3'
var obj = {lang:'zh'}
obj.toString() // '[object Object]'
var fn = function(){}
fn.toString() // 'function(){}'
null.toString() // Cannot read property 'toString' of null
undefined.toString() // Cannot read property 'toString' of undefined
console.log(Object.toString()) //function Object() { [native code] }
console.log(Array.toString()) //function Array() { [native code] }
console.log(Function.toString()) //function Function() { [native code] }
这里可以有两点说的,
1,obj.toString() // '[object Object]'
//这个就印证了刚刚的结论,obj的toString方法未被改写,所以它的原型链上只有这一个tostring方法,也就是判断数据类型的方法,也就是所有Object的实例对象的原型链上,只有这么一个判断数据类型的tostring方法
2,
console.log(Object.toString()) //function Object() { [native code] }
console.log(Array.toString()) //function Array() { [native code] }
console.log(Function.toString()) //function Function() { [native code] }
//这几个就可以印证那句话:这些类包括Function自身都是Function的实例对象。所以它们直接使用toString,其实就是使用了改写定义在Function.prototype上面的toString方法!(可参照本文最前面的红线链条理解),而这个tostrings是改写后的,于是打印字符串,因为都是function创建的构造函数,所以都是这个函数