JavaScript类型、值和原生函数大揭秘, 前端开发者必看!

195 阅读6分钟

前言

系列首发于公众号『前端进阶圈』 ,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。

JavaScript类型、值和原生函数大揭秘, 前端开发者必看!

类型

  • ECMAScript 一共有七种语言类型:Undefined、Null、Boolean、String、Number、Object、Symbol

    内置类型

  • 函数不仅是对象,还拥有属性。在函数中的 length 属性是参数的个数
  • 如下代码:

    function a(b,c){
    // do something
    }
    
    
    a.length; // 2

    a.length; // 2

  • typeof [...] 为什么等于 object?

    • 数组也是对象,但确切来说,它是 object 的一个 "子类型"
  • 如下代码:

    typeof [1,2,3] === 'object'; // true

值和类型

  • typeof 运算符总是会返回一个字符串
  • 如下代码:

    typeof typeof 42; // string
    
    
    
    
    // typeof 42 首先会返回 number, 然后 typeof number 返回 string

    // typeof 42 首先会返回 number, 然后 typeof number 返回 string

    小结

  • 变量没有类型,他们所拥有的值才有类型。
  • typeof [...] 为什么等于 object?

    • 数组也是对象,但确切来说,它是 object 的一个 "子类型"

数组

  • 使用 delete 操作符不会影响数组长度

    let a = ['a', 'b', 'c', 'd'];
    delete a[2];
    console.log('a ------>', a); // [ 'a', 'b', <1 empty item>, 'd' ]
    console.log('a ------>', a.length); // 4
  • 数组索引既可以通过数字索引,也可以通过字符串索引,可以通过像访问对象的建制属性一样访问数组元素。除了通过使用数字索引的方式,其他都不计算进数组长度内

    let a2 = [];
    a2[0] = 1;
    a2['foo'] = 2;
    
    
    
    
    console.log('a2.length ------>', a2.length);  // 1
    console.log("a2['foo'] ------>", a2['foo']); // 2
    console.log('a2.foo ------>', a2.foo); // 2

    console.log('a2.length ------>', a2.length); // 1 console.log("a2['foo'] ------>", a2['foo']); // 2 console.log('a2.foo ------>', a2.foo); // 2

  • 如果字符串值被强制转换为十进制数字,数组会被当做数字索引来处理

    var a = [];
    a['13'] = 42;
    a.length; // 14
  • 将类数组转为数组, 还有其他方法: indexOf()、concat()、map().....

    var arr = Array.from(arguments);
    Array.prototype.slice.call();

    数字

  • 数字语法:数字前面的 0 可省略

    var a = 0.42;
    var b = .42;
  • 由于数字值使用 Number 对象封装,因此数字值可调用 Number.prototype 中的方法。

    • toPrecision(..) 方法用来指定有效数位的显示位数:

      var a = 42.59;
      
      
      
      
      a.toPrecision( 1 ); // "4e+1"
      a.toPrecision( 2 ); // "43"
      a.toPrecision( 3 ); // "42.6"
      a.toPrecision( 4 ); // "42.59"
      a.toPrecision( 5 ); // "42.590"
      a.toPrecision( 6 ); // "42.5900"

      a.toPrecision( 1 ); // "4e+1" a.toPrecision( 2 ); // "43" a.toPrecision( 3 ); // "42.6" a.toPrecision( 4 ); // "42.59" a.toPrecision( 5 ); // "42.590" a.toPrecision( 6 ); // "42.5900"

  • 注意,对于 . 操作符来说,因为他们是一个有效的数字字符,会被优先识别为数字常量的一部分,然后才是对象属性访问运算符。

    // 无效语法:
    42.toFixed( 3 );    // SyntaxError
    
    
    
    
    // 下面的语法都有效:
    (42).toFixed( 3 );  // "42.000"
    0.42.toFixed( 3 );  // "0.420"
    42..toFixed( 3 );   // "42.000"
    

    // 下面的语法都有效: (42).toFixed( 3 ); // "42.000" 0.42.toFixed( 3 ); // "0.420" 42..toFixed( 3 ); // "42.000"

  • .toFixed(3); // "42.000"

  • 42.tofixed(3) 是无效语法,因为 . 被视为常量 42. 的一部分(如前所述),所以没有 . 属性访问运算符来调用 tofixed 方法。
  • 42..tofixed(3) 则没有问题,因为第一个 . 被视为 number 的一部分,第二个 . 是属性访问运算符。只是这样看着奇怪,实际情况中也很少见。在基本类型值上直接调用的方法并不多见,不过这并不代表不好或不对。

    数值检测方法
  • 能够被"安全"呈现的最大整数是 2^53 - 1,即 9007199254740991,在 ES6 中被定义为 Number.MAX_SAFE_INTEGER。最小整数是 -9007199254740991,在 ES6 中被定义为 Number.MIN_SAFE_INTEGER
  • 要检测一个值是否是整数,可以使用 ES6 中的 Number.isInteger(..) 方法:

    Number.isInteger( 42 );     // true
    Number.isInteger( 42.000 ); // true
    Number.isInteger( 42.3 );   // false
  • 也可以为 ES6 之前的版本 polyfill Number.isInteger(..) 方法:

    if (!Number.isInteger) {
    Number.isInteger = function(num) {
    return typeof num == "number" && num % 1 == 0;
    };
    }
  • 要检测一个值是否是安全的整数,可以使用 ES6 中的 Number.isSafeInteger(..) 方法:

    Number.isSafeInteger( Number.MAX_SAFE_INTEGER );    // true
    Number.isSafeInteger( Math.pow( 2, 53 ) );          // false
    Number.isSafeInteger( Math.pow( 2, 53 ) - 1 );      // true
  • 可以为 ES6 之前的版本 polyfill Number.isSafeInteger(..) 方法:

    if (!Number.isSafeInteger) {
    Number.isSafeInteger = function(num) {
    return Number.isInteger( num ) &&
    Math.abs( num ) <= Number.MAX_SAFE_INTEGER;
    };
    }

特殊数值

  • null 和 undefined。nul 是一个特殊关键字,不是标识符,不能将其当做变量来使用和赋值。但 undefined 确实一个标识符,可被当做变量来使用和赋值。

    null: 指空值
    undefined:指没有值
  • NaN:NaN 是一个特殊值,它和自身并不相等,是唯一一个非自反(即 x === x 不成立的值),而 NaN != NaN 为 true。
  • 那如何判断 NaN 呢?

    var a = 2 / 'foo';
    isNaN(a); // true
  • ES6 开始我们可使用工具函数 Number.isNaN()

    var a = 2 / "foo";
    var b = "foo";
    
    
    
                Number.isNaN( a ); // true
                Number.isNaN( b ); // false——好!</code></pre></li><li><p>还有一个简单方法,利用 NaN 不等于自身这个特点。</p><pre><code class="js">if (!Number.isNaN) {
                Number.isNaN = function(n) {
                    return n !== n;
                    };
                    }</code></pre><h4>小结</h4></li><li>使用 <code>delete</code> 操作符不会影响数组长度</li><li>除了通过使用数字索引的方式,其他都不计算进数组长度内</li><li>数值语法中数字前面的 0 可省略</li><li>注意,<code>对于 </code>.<code> 操作符来说,因为他们是一个有效的数字字符,会被优先识别为数字常量的一部分,然后才是对象属性访问运算符。</code></li><li>要检测一个值是否是整数,可以使用 ES6 中的 <code>Number.isInteger(..)</code> 方法</li><li>最大整数是 <code>9007199254740991</code>,在 ES6 中被定义为 <code>Number.MAX_SAFE_INTEGER</code>。最小整数是 <code>-9007199254740991</code>,在 ES6 中被定义为 <code>Number.MIN_SAFE_INTEGER</code></li><li>NaN:NaN 是一个特殊值,它和自身并不相等,是唯一一个非自反(即 x === x 不成立的值),而 NaN != NaN 为 true。</li><li><p>如何判断一个数是否是 NaN?</p><pre><code class="js">var a = 2 / "foo";
                    var b = "foo";
                    
                    Number.isNaN( a ); // true
                    Number.isNaN( b ); // false ——好!</code></pre></li></ul><h3 id="item-0-5">原生函数</h3><ul><li><p>常见原生函数:</p><pre><code class="js">• String()
                    • Number()
                    • Boolean()
                    • Array()
                    • Object()
                    • Function()
                    • RegExp()
                    • Date()
                    • Error()
                    • Symbol() ——ES6 中新加入的!</code></pre></li><li><p>原生函数可当构造函数使用,但构造出来的对象会我们设想的有所出入。</p><pre><code class="js">var a = new String( "abc" );
                    
                    typeof a;                            // 是"object",不是"String"
                    
                    a instanceof String;                 // true
                    
                    Object.prototype.toString.call( a ); // "[object String]"</code></pre></li><li><code>使用构造函数创建出来的是封装了基本类型值的封装对象。</code></li><li>注意:<code>typeof 在此返回的是对象类型的子类型。</code></li></ul><h4>内部属性 <code>[[Class]]</code></h4><pre><code class="js">Object.prototype.toString.call( [1,2,3] );
                    // "[object Array]"
                    
                    Object.prototype.toString.call( /regex-literal/i );
                    // "[object RegExp]"
                    
                    Object.prototype.toString.call( null );
                    // "[object Null]"
                    
                    Object.prototype.toString.call( undefined );
                    // "[object Undefined]"
                    
                    Object.prototype.toString.call( "abc" );
                    // "[object String]"
                    
                    Object.prototype.toString.call( 42 );
                    // "[object Number]"
                    
                    Object.prototype.toString.call( true );
                    // "[object Boolean]"</code></pre><ul><li>上例中,数组的内部 [[Class]] 属性值是 "Array",正则表达式的值是 "RegExp"......</li></ul><h4>封装对象包装</h4><pre><code class="js">var a = new Boolean( false );
                    console.log('a ------&gt;', a); // [Boolean: false]
                    console.log(Boolean(a)); // true
                    if (!a) {
                        console.log( "Oops" ); // 执行不到这里
                        }</code></pre><ul><li><p>若想要自定义基本类型值,可使用 <code>Object()</code> 函数(不带 new 关键字)</p><pre><code class="js">var a = "abc";
                        var b = new String( a );
                        var c = Object( a );
                        
                        typeof a; // "string"
                        typeof b; // "object"
                        typeof c; // "object"
                        
                        b instanceof String; // true
                        c instanceof String; // true
                        
                        Object.prototype.toString.call( b ); // "[object String]"
                        Object.prototype.toString.call( c ); // "[object String]"</code></pre></li></ul><h4>小结</h4><ol><li>使用原生函数构造出来的函数对象时封装了基本类型值的封装对象。</li><li><p>若想要自定义基本类型值,可使用 <code>Object()</code> 函数(不带 new 关键字)</p><pre><code class="js">var b = new String( a );
                        var c = Object( a );
                        
                        Object.prototype.toString.call( b ); // "[object String]"
                        Object.prototype.toString.call( c ); // "[object String]"</code></pre></li></ol><h2 id="item-0-6">特殊字符描述:</h2><ol><li>问题标注 <code>Q:(question)</code></li><li>答案标注 <code>R:(result)</code></li><li>注意事项标准:<code>A:(attention matters)</code></li><li>详情描述标注:<code>D:(detail info)</code></li><li>总结标注:<code>S:(summary)</code></li><li>分析标注:<code>Ana:(analysis)</code></li><li><p>提示标注:<code>T:(tips)</code></p><h2 id="item-0-7">往期推荐:</h2></li><li><a href="https://link.segmentfault.com/?enc=GtkD1w59kBCKoimRGjMoqA%3D%3D.q0eFMfKXTf3xg2pdySjcM3QDTLHwJ0%2FkHIgUi%2BWdumLIxACjngOruPLr92qapi%2FAbkHuUcxtn3hDNKgOARMv5Q%3D%3D" rel="nofollow" target="_blank">前端面试实录HTML篇</a></li><li><a href="https://link.segmentfault.com/?enc=QlkOqYazADsbomnYLd%2Bgog%3D%3D.UqBCPZNHAm7iqZA8%2F134FJCfdQcOg7CVoyCN%2Bjq2Pqrv0xKzIUwTeTNZ%2BgPwEkTBN80YM1lQUzPqScr2lz3fZQ%3D%3D" rel="nofollow" target="_blank">前端面试实录CSS篇</a></li><li><a href="https://link.segmentfault.com/?enc=dtZ56ODH32OkIUEPIh9T9A%3D%3D.l7EvLHNuW1new7Ni3iZqT5ifx5GiRJ0%2BjeLjhmUvTsFJ69Df0JUOVcf%2FBpP0BpxIquuEM%2F4ONFEVv7hFVEaLlQ%3D%3D" rel="nofollow" target="_blank">JS 如何判断一个元素是否在可视区域内?</a></li><li><a href="https://link.segmentfault.com/?enc=J6T9eQys1otvH8%2FDypERBQ%3D%3D.ddhDDtptzpnBeUc%2FSRF5kletyoo5UffId88sUqq4QQD%2BGWNfNRiSq3qW6skr6ZaQPSL9vHSt2icIpy60Th8LBQ%3D%3D" rel="nofollow" target="_blank">Vue2、3 生命周期及作用?</a></li><li><a href="https://link.segmentfault.com/?enc=0y%2F4RYBbHZ3jzYm3zs9YDQ%3D%3D.SFeFYYxwid9oymNG2JQro49Whba0iPsyhlIrRmLAe4xCWU0Emjy3yAnNqpxK0qCzX6wS%2FTN6eekudrxnDqbkdQ%3D%3D" rel="nofollow" target="_blank">排序算法:QuickSort</a></li><li><a href="https://link.segmentfault.com/?enc=y3NNrUHSz06YQMJgHgsHfA%3D%3D.Ay5vCtU8wAL0TeBVYsI4MVLW5%2F8ozo8Tx1ymj8KlPVxpVNCLgOEETyu%2Fx7c9RGpKgmrcsY6SlSufFgybcLfSkg%3D%3D" rel="nofollow" target="_blank">箭头函数与普通函数的区别?</a></li><li><a href="https://link.segmentfault.com/?enc=qZceTc4ky8cd0Nmuf%2B9v2w%3D%3D.3tWkuXKZIJCgWJ%2FuAB2LkbH3XG7gkZjx9RS2a4tLtzktrRRe25PoizSl%2F8N%2F7QjevhP1%2F5nNqh4wb7hmjjeXbw%3D%3D" rel="nofollow" target="_blank">这是你理解的CSS选择器权重吗?</a></li><li><a href="https://link.segmentfault.com/?enc=Hq9p5WCgb4oje526%2Bt%2BczA%3D%3D.%2FX0uubBQGaUI7ribyXF7INiUJyvqSPhpS9yoKgvQ0FEFe1NJgZ5dw3czl3h95nX3ARSa7OP9Uc4dxIKBft7ETQ%3D%3D" rel="nofollow" target="_blank">JS 中 call, apply, bind 概念、用法、区别及实现?</a></li><li><a href="https://link.segmentfault.com/?enc=obgx5uZvV5VFYSQ8xIcPwA%3D%3D.RdBaLcy8biWHE3jvOfx4dwKwqBijSN%2FqqE073zsBAKNHDFWuLQi%2FRLoiQgoTKpUS8SCC1vvI16efDmFJMBm5Kg%3D%3D" rel="nofollow" target="_blank">常用位运算方法?</a></li><li><a href="https://link.segmentfault.com/?enc=TjSnqfvAR0d6R%2F0CdCJ7SQ%3D%3D.993%2F9ztyMs9pzPPoUDM6PJSfsotNLemwcSFpd1c8VLOa2s8jJaMgAWAlXp5gFwvzavSK%2BhSTWdS0FJ9Lcq1X%2Fw%3D%3D" rel="nofollow" target="_blank">Vue数据监听Object.definedProperty()方法的实现</a></li><li><a href="https://link.segmentfault.com/?enc=dK8cdoKmUkPhijFg8zOvUA%3D%3D.vGgz7oDaELlVSe2RyLwDJ54k6y3U82OlU7S8i8jJmkGnZIib5C0seVOEjDLLU1Dzvw0lklDrXPvEKrfKGV253A%3D%3D" rel="nofollow" target="_blank">为什么 0.1+ 0.2 != 0.3,如何让其相等?</a></li><li><a href="https://link.segmentfault.com/?enc=fFad3JkdVXBKFl7HkC%2BxHg%3D%3D.JH%2BPwJ%2BFTPQGTj8ijBzLUsOUsb0P7J7v5wzembbSc3HlcSseskbs0Gy%2FXwkny5od%2FHKCiXCsgqEqxdbQid7nvA%3D%3D" rel="nofollow" target="_blank">聊聊对 this 的理解?</a></li><li><p><a href="https://link.segmentfault.com/?enc=3qAWQaR4MCrNPlr6bWliuQ%3D%3D.lU6P4px7%2FA1eUIWdauYFJv8tsHyfyfDTAH5qVTZTT0GJidXqFDYLV5YgkVT0IHGU74%2FTAm5xoeXU0aSIDBRYMA%3D%3D" rel="nofollow" target="_blank">JavaScript 为什么要进行变量提升,它导致了什么问题?</a></p><h2 id="item-0-8">最后:</h2></li><li>欢迎关注 <a href="https://link.segmentfault.com/?enc=0HnJK4%2BNhDUw8GBaE%2B4d%2BQ%3D%3D.lwf%2FbJ%2BJGYzwVsxVrCwH974NbIJcos659Mx50i8TF4zvlZqkSr0n5Y6sVa3OLSdk4svPtgYbPIeDRgYscfEm1wvY0kdWKxnnXgMOLUbgk1OmQOwS7N1CG8dBi1rndv5hJC941cnmYcHR548y4tG6r7qtwjgFYw%2BGc3PhN9ecqMNN8AfCatriLPZksXS8KVb72zpj3Jh3yfwlEPJOT0qoi4mlBPqjKWA0QttR25H%2BcyurxDNFLhEsrq5VwSUYrloWzMh6FO6nV4SpnxKVvz%2FUH53kkX5nIbqNJRfnGJHVw2U%3D" rel="nofollow" target="_blank">『前端进阶圈』</a> 公众号 ,一起探索学习前端技术......</li><li>公众号回复 <a href="https://link.segmentfault.com/?enc=7h0rDQ7bUo%2BdqhUh21OpQQ%3D%3D.DPpmVsgH81G7dhp3LGstbGVMMJMPbD2MH1r6gwiIZKq%2BI4IQbarH2DaKO417ruIB558IrK7t2baNfkDgXXtS%2F%2Br68tt17oAiC7WUfba9t4K1g1x%2FuzJFz3HBypzuZdwBh1m9F3cYqV3oB5ONjE4LRTDRTQnAin3Dh%2FCiWapEzumCrJ%2ByersONQo0XsnN8pfJdbdbgONPcIuzDhgrAJPtpJ0MIfMD%2BQ4MwjqYoCKfe7ytcQv7XTFF2M5q8gdBLZUOVJ5AQfPsVvfiJ7o0Zslg1jgKPPVvKAM4Yw122NYsTrE%3D" rel="nofollow" target="_blank">加群</a><a href="https://link.segmentfault.com/?enc=%2BTJ0rvFxqgaMVdarF%2Bwb%2Fg%3D%3D.ZnF4UOqBDts1brGvCeZxfPf1yKWpZHXgEBg0x6zNwJgX%2B8rJgtjm9t0MpFK4KaZBwvvMNTPYJxrBYzhoD37QBfljaYhcsJDbvEwuk1y4TSS%2F5TqNnQ%2BPINqh87lv5k6DKD5MeMOwzAM2KFeBJMUu1VgsS1KhW2fE8FT8Cc%2Fc%2Fshl47nb%2BZQQDOYJ0w1hLy%2FVvmSmxdO1vq%2BN6aRlMmxFFj7hrhuJQjIwSXVj9cO0JLDdYTfEilo1eJfS%2FOthVj6O8BMq%2Fo%2FzJR0pnhGLpqPJ%2FO1hQvEL3OEYaoLY7QOPE%2BQ%3D" rel="nofollow" target="_blank">扫码</a>, 即可加入前端交流学习群,一起快乐摸鱼和学习......</li><li>公众号回复 <a href="https://link.segmentfault.com/?enc=Sqb3XLQYOJa576S2czE7pA%3D%3D.%2BJbw%2BSK10JIG3qGO4%2F0awJNH1Qyu59cq%2BhlnmhqBmVbLkiAUO2pt1hJiqmDjPzt%2B%2FYy%2FOKdEsawVrJ9sfkvh%2BuxPkmXP%2F22Wy0adJd79oGIWnzdaFAX118y3jsiBDg2R6lhoxSZK46prfjr0AI%2B0N4qOdHGDNAC6pKaQMpac8zcLlAzk6qpKnr8rtu2rpVNzvRWQCOHjMfBuR9vdlC07ILZjbnQIqo7yTuyofOYZU%2F7jvvgKyRixWyGGuF%2BspCuRhmA2asesWRtw4WXYevTfRM4pe8hA5XlneQrf11emlZ0%3D" rel="nofollow" target="_blank">加好友</a>,即可添加为好友<br></li></ol>