JavaScript范例:关于范例,有哪些你不知道的细节?

undefined和null

  Undefined范例示意未定义,它的范例只要一个值为undefined。任何变量在赋值前都是undefined范例,值为undefined。然则JS中undefined是一个变量,并非是一个关键字,为了防止无意中的改动,运用void 0来猎取undefined值。

  undefined和null有肯定的表意差异,null示意“定义了然则为空”,它只一个值为null,并且是JS关键字,能够放心运用。

Number

  非整数的Number范例没法运用 == 或 === 来比较,有一段有名的代码

console.log(0.1 + 0.2 == 0.3);

  输出结果是false,申明双方不等,这是浮点运算的特性,浮点数运算的精度题目致使等式摆布并非严厉相称,而是相差了个细小的值。

  正确的比较要领是运用JS供应的最小精度值:

console.log(Math.abs(0.1 + 0.2 -0.3) <= Number.EPSILON);

  搜检等式摆布双方差的绝对值是不是小于最小精度值,才是正确的比较浮点数的要领。

范例转换

  由于 JS 是弱范例言语,所以范例转换发作异常频仍,大部分我们熟习的运算都邑先举行范例转换。大部分范例转换相符人类的直觉,然则假如我们不去明白范例转换的严厉定义,很轻易形成一些代码中的推断失误。个中最为臭名远扬的是 JS 中的“ == ”运算,由于试图完成跨范例的比较,它的划定规矩太甚庞杂。许多实践中引荐制止运用“ ==”,而请求程序员举行显式地范例转换后,用 === 比较。

  parseInt 和 parseFloat 是很经常使用的范例转换的要领。在不传入第二个参数的情况下,parseInt 只支撑 16 进制前缀“0x”,而且会疏忽非数字字符,也不支撑科学计数法。在一些陈旧的浏览器环境中,parseInt 还支撑 0 开首的数字作为 8 进制前缀,这是许多毛病的泉源。所以在任何环境下,都发起传入 parseInt 的第二个参数,而 parseFloat 则直接把原字符串作为十进制来剖析,它不会引入任何的其他进制。

  多半情况下,Number 是比 parseInt 和 parseFloat 更好的挑选。

装箱转换

  每一种基础范例 Number、String、Boolean、Symbol 在对象中都有对应的类,所谓装箱转换,恰是把基础范例转换为对应的对象,它是范例转换中一种相称主要的品种。全局的 Symbol 函数没法运用 new 来挪用,但我们仍能够应用装箱机制来取得一个 Symbol 对象,我们能够应用一个函数的 call 要领来强制发生装箱。我们定义一个函数,函数内里只要 return this,然后我们挪用函数的 call 要领到一个 Symbol 范例的值上,如许就会发生一个 symbolObject。

  我们能够用 console.log 看一下这个东西的 type of,它的值是 object,我们运用 symbolObject instanceof 能够看到,它是 Symbol 这个类的实例,我们找它的 constructor 也是即是 Symbol 的,所以我们不管哪一个角度看,它都是 Symbol 装箱过的对象:

    
var symbolObject = (function(){ 
    return this; 
}).call(Symbol("a"));

console.log(typeof symbolObject);         //object
console.log(symbolObject instanceof Symbol);     //true
console.log(symbolObject.constructor == Symbol);    //true

  装箱机制会频仍发生暂时对象,在一些对机能请求较高的场景下,我们应当只管防止对基础范例做装箱转换。

  运用内置的Object函数,能够在JS代码中显式的挪用装箱才能。

var symbolObject = Object((Symbol("a"));

console.log(typeof symbolObject);         //object
console.log(symbolObject instanceof Symbol);     //true
console.log(symbolObject.constructor == Symbol);     //true

  每一类装箱对象皆有私有的Class属性,这些属机能够用Object.protoype.toString猎取:

var symbolObject = Object((Symbol("a"));
console.log(Object.prototype.toString.call(symbolObject)); //[object Symbol]

  JS中,没有要领能够变动私有的Class属性,因而Object.prototype.toString是能够正确辨认对象对应的基础范例的要领,它比instanceof越发正确。

  但须要注重的是,call 自身会发生装箱操纵,所以须要合营typeof来辨别基础范例照样对象范例。

拆箱转换

  JS规范中,划定了ToPrimitive函数,它是对象范例到基础范例的转换。(即拆线转换)

  对象到String和Number的转换都遵照“先拆箱再转换”的划定规矩。经由过程拆箱转换,把对象编程基础范例,再从从基础范例转换成对应的String或许Number。

  拆箱转换会尝试挪用valueOf和toString来取得拆箱后的基础范例。假如valueOf和toString都不存在。或许没有返回基础范例,则会发生范例毛病的提醒TypeError。

var o = {
    valueOf : () => {console.log("valueOf"); return {}},
    toString : () => {console.log("toString"); return {}}
}
    
o * 2
// valueOf
// toString
// TypeError

  我们定义了一个对象 o,o 有 valueOf 和 toString 两个要领,这两个要领都返回一个对象,然后我们举行 o * 2 这个运算的时刻,你会看见先执行了 valueOf,接下来是 toString,末了抛出了一个 TypeError,这就申清楚明了这个拆箱转换失利了。

  到 String 的拆箱转换会优先挪用 toString。我们把适才的运算从 o*2 换成 o + “”,那末你会看到挪用递次就变了。

var o = {
    valueOf : () => {console.log("valueOf"); return {}},
    toString : () => {console.log("toString"); return {}}
}
 o + ""
// toString
// valueOf
// TypeError
    原文作者:bertZuo
    原文地址: https://segmentfault.com/a/1190000018394626
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞