你不知道的前端數(shù)據(jù)類型(基礎(chǔ)+進(jìn)階篇)

類型&值

內(nèi)置類型: 7種 (null| undefined | boolean | number| string | object | symbol)

值類型轉(zhuǎn)換

Number<->String
let a = 123;
a.toString() //‘123’
String(a) //‘123’ String() 遵循toString()規(guī)范
let c = '3.14'
Number(c) //3.14

因?yàn)閿?shù)組的valueOf()無法轉(zhuǎn)換為簡單類型值,于是轉(zhuǎn)而調(diào)用ToString()


* 結(jié)合ES5規(guī)范談字符串轉(zhuǎn)換

如果其中一個(gè)操作數(shù)為字符串或通過調(diào)用Topermitive抽象操作后,再調(diào)用 [[DefaultValue]],以數(shù)字作為上下文,執(zhí)行拼接操作;否則進(jìn)行數(shù)字加法;
「這個(gè)地方有些繞,再查下規(guī)范」


執(zhí)行拼接操作
let a = {
  valueOf: () => 2;
  toString: (num) => '44'
}
a+ ' ' // '2'
String(a) //'44' 

因此我們在定義valueOftoString方法時(shí)要慎重,因?yàn)闀?huì)影響強(qiáng)制類型轉(zhuǎn)換結(jié)果。

  • 不建議使用封裝對(duì)象直接進(jìn)行判斷,因?yàn)榉祷氐闹凳冀K為 true
let a = new String("abc");
typeof a // "object"
a instanceof String // true
Object.prototype.toString.call(a) // "[object String]"
Number<->Boolean
// 判斷多個(gè)參數(shù)下是否唯一一個(gè)為true
const onlyOne= (args) => {
  let sum = 0;
  for(let i = 0,len = args.length; i < len; i++) {
    sum += Number(!!args[i]);
  }
  return sum === 1;
}
a = true;
b = false;
p(onlyOne([a,b]))
symbol <-> anyType

ES6中出現(xiàn)的 symbol 類型不能夠轉(zhuǎn)換為Number String

var s2= Symbol("not cool");
s2 + ""  // TypeError
Symbol("foo") === Symbol("foo"); // false

typeof 運(yùn)算符能幫助識(shí)別symbol類型

typeof Symbol() === 'Symbol'
typeof Symbol('foo') === 'Symbol'
Boolean <-> String/Others

掌握真 / 假值的重點(diǎn)在于理解布爾強(qiáng)制類型轉(zhuǎn)換

  • 規(guī)律總結(jié)
    以下這些是假值:
    ? undefined
    ? null
    ? false
    ? +0、-0NaN
    ? ""
    假值的布爾強(qiáng)制類型轉(zhuǎn)換結(jié)果為 false
  • 顯式調(diào)用Boolean() 進(jìn)行強(qiáng)制類型轉(zhuǎn)換
var a = "0";
var b = [];
var c = {};
var d = "";
var e = 0;
var f = null;
var g;
Boolean( a ); // true
Boolean( b ); // true
Boolean( c ); // true
Boolean( d ); // false
Boolean( e ); // false
Boolean( f ); // false
Boolean( g ); // false
  • 使用 運(yùn)算符 !!顯式地將值強(qiáng)制類型轉(zhuǎn)換為布爾值, 包含一次強(qiáng)制Boolean類型轉(zhuǎn)換,將真值反轉(zhuǎn)為假值再反轉(zhuǎn)回來。
數(shù)字
  • 判斷是否相等
    設(shè)置機(jī)器精度 Number.EPSILON = Math.pow(2,-52);
    Math.abs(n1 - n2) < Number.EPSILON;

  • 判斷是否為整數(shù)
    Number.isInteger()
    polyfill 版本
    return typeof num == 'number' && num % 1 == 0

  • x的引用還是副本
    x.length = 0 x.push (4,5,6,7) 并沒有創(chuàng)建一個(gè)新數(shù)組,而是改變了當(dāng)前的數(shù)組
    通過值復(fù)制傳遞復(fù)合值(如數(shù)組),就需要?jiǎng)?chuàng)建一個(gè)副本;

對(duì)象

封裝
var a = new Boolean(false);
得到的不是 false,而是一個(gè)真值

類型轉(zhuǎn)換
  1. 日期顯式轉(zhuǎn)換為數(shù)字
let l = new Date(); //1563943975689
let timeStamp = new Date().getTime();
// es5 中的方法
timeStamp = Date.now();
// Date.now() 的polyfill
if(!Date.now) {
  Date.now = function () {
    return +new Date();
  }
}
  1. 使用~進(jìn)行 32位運(yùn)算
    ~x 大致等于 -(x+1)
if(~a.indexOf('xx')) {
console.log("當(dāng)前沒有找到匹配")
}

~~只適用于32位的數(shù)字
Math.floor(-49.6) // -50
~~(-49.6) // -50

  1. parseInt(...)
    將參數(shù)強(qiáng)制處理為字符串再解析
    parseInt(1/0, 19) // 18 1/0 處理為Infinity n為無效字符,只處理到I,按照19進(jìn)制 得到18
  2. Boolean(...)顯式轉(zhuǎn)換
    4.1 最常用: !!
    a = !!"0" && !!{} && !![] // true
    d = !!"" && !!0 && !!null !!undefined // false
    Boolean(a)
&& || 操作符

|| 返回的是對(duì)應(yīng)的值 不同于C語言中的 true | false
守護(hù)運(yùn)算符&&

function fn() {
    console.log(a);
}
a && fn()
//  fn在條件判斷通過時(shí)才會(huì)執(zhí)行
其他類型和布爾類型之間的相等比較

如果Type(x)是boolean類型,結(jié)果返回 ToNumber(x) == y

let x = true;
let y = "42"
x == y; // false
// x被強(qiáng)制轉(zhuǎn)換為1;    1 == '42'

null undefined 之前的強(qiáng)制類型轉(zhuǎn)換是安全的

對(duì)象與非對(duì)象之間的相等比較

對(duì)象通過 Topremitive進(jìn)行強(qiáng)制類型轉(zhuǎn)換(如 toString()、 valueOf())

  1. 抽象關(guān)系比較
    2.1 雙方都是字符串,按照字母順序來比較
    2.2 為了保證安全,應(yīng)該在關(guān)系比較中進(jìn)行顯示強(qiáng)制類型轉(zhuǎn)化;
var a = { b : 2};
var b = { b : 3};
a > b //flase
a == b //false
a < b //false
a >= b // true  a<=b 被處理為 !(a>b) 小于等于其實(shí)是不大于
a <= b //true
運(yùn)算符優(yōu)先級(jí)

Javascript中的 && 和 || 運(yùn)算符返回它們其中一個(gè)操作數(shù)的值,而非 true 或者 false

數(shù)字精度

類數(shù)組:字符串和數(shù)組都是類數(shù)組,擁有l(wèi)ength和indexof(...)和concat(...)
字符串可以借用數(shù)組的方法,使用call

let dUpper = Array.prototype.map.call(a,function(v) {
  return v.toUpperCase()+ '.';
}).join("");

浮點(diǎn)數(shù):設(shè)定誤差范圍 2^-52

ES6中定義了Number.EPSILON代表浮點(diǎn)數(shù)的誤差范圍

//polyfill
if(!Number.EPSILON)
{
  Number.EPSILON = Math.pow(2,-52);
}

數(shù)字類型包含幾個(gè)特殊值: -Infinity +Infinity -0
特殊的數(shù)值 NaN
不是數(shù)字的數(shù)字 仍是數(shù)字類型
typeof NaN === "number"
NaN 為非自反的值 NaN !== NaN 使用內(nèi)建函數(shù)isNaN()判斷 該函數(shù)有個(gè)嚴(yán)重bug 判斷當(dāng)前數(shù)字不是NaN類型,也不是Number類型
math工具函數(shù)中 isNaN 的polyfill

if(!Number.isNaN) {
  Number.isNaN = function(n) {
    return typeof n === 'Number' && window.isNaN(n);
  }
}

區(qū)分正負(fù)0
function isNegZero(n) {
n = Number(n);
return (n === 0) && (1/n === -Infinity)
}
ES6中出現(xiàn)了 Object.is(...) 判斷兩個(gè)值是否完全相等,能夠使用== / === ,不使用 Object.is() 因?yàn)榍罢咝矢吒ㄓ?/p>

mentor's question
  1. 為什么+-Infinity Boolean后為 true
    根據(jù)MDN web docs
    -Infinity 仍為真值, Infinity是一個(gè)全局對(duì)象的一個(gè)屬性,即它是一個(gè)全局變量.
    *JavaScript 中的真值示例如下(將被轉(zhuǎn)換為 true,if 后的代碼段將被執(zhí)行)
if (true)
if ({})
if ([])
if (42)
if ("foo")
if (new Date())
if (-42)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)
  1. 標(biāo)志symbol 這個(gè)基本類型的作用是什么?
    一種不可變的并且值唯一的基本數(shù)據(jù)類型,用于定義屬性的key, 防止在多個(gè)屬性同時(shí)作用于對(duì)象時(shí)由于屬性重復(fù)引發(fā)覆蓋。

  2. object 轉(zhuǎn)為number 類型,得到的結(jié)果
    如果有對(duì)應(yīng)的數(shù)值可以轉(zhuǎn)換,得到數(shù)值,如果不能對(duì)應(yīng)轉(zhuǎn)換 NaN

let test1 = new Boolean(true) //undefined
let test2 = new Boolean(false) //undefined
Number(test1) //1
Number(test2) //0
let test3 = new Date() // Thu Aug 22 2019 10:57:06 GMT+0800 (中國標(biāo)準(zhǔn)時(shí)間)
Number(test3) //1566442626454 得到的是時(shí)間戳
let test4 = new String('999');
Number(test4) //999
let test5 = new String('999 888');
Number(test5) // NaN
let test6 = {
  a: {
  hahah: 'jajaja'
  }
}
Number(test6) //NaN
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容