[Effective JavaScript 笔记]第1八条:不要注重函数对象的toString方法

备忘:

那边供给去探听一下,js解释器的学问。
连锁的链接有:
javascript设计格局之解释器方式详解
javascript设计情势 –
解释器格局(interpreter)

Chrome V8

toString应用

如上边所说,继承自Object的对象都有toString方法,但各类对象完结了个其他toString方法,导致力不从心用toString方法举办项目判断。那里能够动用在此以前讲到过的call或apply方法来调用Object.prototype.toString方法。

function getType(obj){
   var toString=Object.prototype.toString;
   return toString.call(obj);   
}

测试一下各个型会得到如下结果

getType(1);//"[object Number]"
getType(true);//"[object Boolean]"
getType('1');//"[object String]"
getType(undefined);//"[object Undefined]"
getType(function(){});//"[object Function]"
getType(/sf/);//"[object RegExp]"
getType(null);//"[object Null]"
getType(window);//"[object Window]"
getType({});//"[object Object]"
getType([]);//"[object Array]"
getType(Math);//"[object Math]"

装有类型都得以分别出来,是还是不是非常的粗略呀!

ECMAScript,还有个特出的值要求注意NaN.

getType(NaN);//"[object Number]"

NaN是叁个Number类型的相当规值,它是表述是二个不是一个数字的值,这里对这些值也要开始展览拍卖。能够关切此前小说《[Effective
JavaScript笔记]第壹条:当心隐式的劫持转换
》里有关NaN的内容。处理代码如下

function isReallyNaN(x){
   return x!==x;
}

 

js函数有三个非同壹般的风味,即将其源代码再现为字符串的力量。

一个难倒的事例

(function(x){
     return x+1
}).bind(16).toString();//"function () { [native code] }"

假若函数是利用纯js达成的,那么js引擎会试图提供该函数的源代码的真人真事表示。

简易数据类型

//数字
(Undefined).toString();//"error"
(Null).toString();//error
(true).toString();//"true"
(1).toString();//"1"
('111').toString();//"111"

能够见到在那之中除了Undefined和Null类型外,为啥别的几其中央类型能够运维吧。
那在我们以前的小说《[Effective JavaScript 笔记]
第6条:原始类型优于封闭对象
》中讲到,当容易数据类型调用toString方法会首先把原始类型转换来包装对象。
那儿对应的卷入对象为

  • 数字为Number对象

  • 布尔值为Boolean对象

  • 字符串为String对象

这几个指标也都以持续自Object对象的,同等对待写了独家的toString方法。
但Undefined类型和Null类型都唯有二个值undefined,null,并从未相应的包裹对象。
虽说typeof null的值是”object”,但并没用。

引用类型

//Object对象
({a:10,b:20}).toString();//"[object Object]"
//Date对象
(new Date).toString();//"Tue Jun 07 2016 15:37:15 GMT+0800 (中国标准时间)"
//RegExp对象
(/^sss$/g).toString();//"/^sss$/g"
//Function对象
function aa(){return "bb"}
aa.toString();//"function aa(){return "bb"}"
//window对象
window.toString();//"[object Window]"
//Math对象
Math.toString();//"[object Math]"

看到上边的toString方法,Object,window,Math是选拔Object原型方法。别的对象都选取了笔者覆盖的toString方法。

typeof操作符

对以上所有项目应用typeof操作符时会博得以下的结果

typeof 1;//"number"
typeof '1';//"string"
typeof true;//"boolean"
typeof undefined;//"undefined"
typeof (function a(){});//"function"
typeof null;//"object"
typeof {};//"object"
typeof (new Date);//"object"
typeof [];//"object"
typeof window;//"object"
typeof Math;//"object"
typeof (/sdfsf/g);//"object"

能够看到,想行使单单的typeof操作符来对品种进行判定大概是不容许的。

有人也许会说对于再次回到object字符串,能够采纳构造函数来判定项目即instanceOf方法。

({}) instanceof Object;//true
(new Date) instanceof Date;//true
([]) instanceof Array;//true
(/sdfsf/g) instanceof RegExp;//true

接下来null类型只要

var a=null;
a===null;//true;

好像能够兑现上边那样的门类判断代码了

function getType(obj){
    if(typeof obj !== 'object'){
        return typeof obj;
    }else{   
        if(obj===null){
            return 'null';
        }
        if(obj===window){
            return 'window'; 
        }
        if(obj===Math){
            return 'Math'
        }      
        if((obj) instanceof Date){
            return 'date';
        }
        if((obj) instanceof Array){
            return 'array';
        }
        if((obj) instanceof RegExp){
            return 'regexp';
        } 
        if((obj) instanceof Object){
            return 'object';
        }

    }
}

上边代码是还是不是能够运作测试一下,并不曾难点

getType(1);//"number"
getType(true);//"boolean"
getType('1');//"string"
getType(undefined);//"undefined"
getType(function(){});//"function"
getType(/sf/);//"regexp"
getType(null);//"null"
getType(window);//"window"
getType({});//"object"
getType([]);//"array"

但此间要留心的1个标题正是,那么些代码里的对于object类型的检查评定一定要放置最前边。
正如所示,全部指标都是继承自Object,所以instanceof检查实验全数指标是否为Object类型的实例再次来到都以true

([]) instanceof Array;//true
([]) instanceof Object;//true

看来以上代码是还是不是认为太复杂麻烦了,有未有一种更简便的格局来对项目实行判断呢?答案自然是有,下边来看toString方法的接纳。

波折原因:

采用了由宿主环境的内置库提供的函数。

  • 是因为广大宿主环境中,bind函数是由其余编制程序语言实现的(平常是c++)。宿主环境提供的是叁个编写翻译后的函数,在此环境下该函数未有js的源代码供显示。

  • 是因为专业允许浏览器引擎改变toString方法的出口,很简单使编写的主次贰个js系统中正确运营,在其余js系统中却不或然正确运维。程序对函数的源代码字符串的切切实实细节很灵巧,尽管js的完成有有个别分寸的转移都可能破坏程序。

  • 由toString方法生成的源代码并不显得闭包中保留的与其间变量引用相关的值

(function(x){
   return function(y){
      return x+y;
   }
})(42).toString();//"function (y){      return x+y;   }"

留意:固然函数实际上是二个绑定x为4二的闭包,但结果字符串照旧蕴藏1个引用x的变量。

从某种意义上说,js的toString方法的那一个局限使其用来领取函数源代码并不是专门有效和值得依赖。平常应该幸免采用它。对领取函数源代码13分复杂的接纳相应选拔精心制作的js解释器和处理库。将js函数看作是二个不应当违背的肤浅是最稳妥的。

附录一:toString方法

不等数据类型调用toString方法的结果。
toString方法是Object原型对象中的3个格局,所以持续自那个类的对象都会继续这么些主意,并能够对toString方法开始展览覆盖。
js标准库中的5种简易数据类型:Undefined,Null,Boolean,Number和String。还有一种复杂的数据类型Object,Object的面目是1组严节的名值对构成。

提示

  • 当调用函数的toString方法时,并不曾须求js引擎能够规范地收获到函数的源代码

  • 出于在差别的内燃机下调用toString方法的结果只怕两样,所以并非要信赖函数源代码的详细细节

  • toString方法的履行结果并不会揭穿存款和储蓄在闭包中的局地变量

  • 平凡意况下,应该幸免选用函数对象的toString方法

反射获取函数源代码的法力很有力,使用函数对象的toString方法有生死攸关的局限性。
toString方法的局限性
ECMAScript标准对函数对象的toString方法的归来结果(即该字符串)并不曾任何必要。那意味着分歧的js引擎将产生不相同的字符串,甚至产生的字符串与该函数并不相干。

(function(x){
   return x+1
}).toString();//"function (x){   return x+1}"