前言
系列首发于公众号『前端进阶圈』 ,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。
JavaScript类型、值和原生函数大揭秘, 前端开发者必看!
类型
ECMAScript 一共有七种语言类型:
Undefined、Null、Boolean、String、Number、Object、Symbol内置类型
- 函数不仅是对象,还拥有属性。
在函数中的 length 属性是参数的个数 如下代码:
function a(b,c){ // do something } a.length; // 2a.length; // 2typeof [...] 为什么等于 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); // 2console.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); // trueES6 开始我们可使用工具函数 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 ------>', 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>