第一部分 01 類型 值 和 原生函數(shù)

類型

類型是值的內(nèi)部特征檩咱,它定義了值的行為,以使其區(qū)別于其他值绊含。

1.2 內(nèi)置類型

JS有七種內(nèi)置類型:

  1. 空值 null
  2. 未定義 undefined
  3. 布爾值 boolean
  4. 數(shù)字 Number
  5. 字符串 String
  6. 對(duì)象 Object
  7. 符號(hào) Symbol

除對(duì)象外芦倒,其他統(tǒng)稱為基本類型不翩。

可用typeof 運(yùn)算符查看值的類型,返回類型的字符串值器钟。

typeof undefined === "undefined";   // true
typeof true === "boolean";  // true
typeof 42 === "number";  // true
typeof "42" === "string";  // true
typeof { life: 42 } === "object";  // true
typeof Symbol() === "symbol";  // true

null 不在此列妙蔗。它比較特殊,topeof對(duì)它處理有問題:

typeof null === "object";  // true

這個(gè)bug由來已久眉反。我們需要使用復(fù)合條件來檢測(cè)null值的類型:

var a = null;
(!a && typeof a === "object");  // true

null 是基本類型中唯一一個(gè)“假值”類型寸五,typeof對(duì)它的返回值為"object"

還有一種情況:

typeof function a() { /*...*/ } === "function";  // true

函數(shù)不僅是對(duì)象,還擁有屬性:

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

函數(shù)對(duì)象的length屬性是其聲明的參數(shù)的個(gè)數(shù)

在來看看數(shù)組:

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

數(shù)組也是對(duì)象韧拒。確切地說,它也是object的一個(gè)"子類型".

1.3 值和類型

JS中變量是沒有類型的叛溢,只有值才有。變量可隨時(shí)持有任何類型的值厢蒜。

1.3.1 undefined 和 undeclared

變量在未持有值是時(shí)候?yàn)閡ndefined烹植。此時(shí)typeof返回“undefined”

已在作用域中聲明但還沒賦值的變量,是undefined的鄙才。
還沒有在作用域中聲明過的變量是undecleared的促绵。

var a;
a;  // undefined
b; // ReferenceError: b is not defined

這個(gè)提示容易讓人誤解為"b is undefined"∨埃“b is not found” 或 "b is not declared"會(huì)更準(zhǔn)確尖坤。

1.3.2 typeof Undeclared

如何在程序中檢查全局變量DEBUG才會(huì)出現(xiàn)ReferenceError錯(cuò)誤。這時(shí)typeof的安全防范機(jī)制就成了好幫手:

// 這樣會(huì)拋出錯(cuò)誤
if(DEBUG){
    //...
}

//這樣是安全的
if(typeof DEBUG !== "undefined"){
    //...
}

從技術(shù)角度說场梆,typeof的安全防范機(jī)制對(duì)于非全局變量也很管用,如檢查變量是否已經(jīng)在宿主程序中定義過:

function doSomethingCool() {
    var helper = (typeof FeatureXYZ !== 'undefined') ? FeatureXYZ : function() { /*...*/ }
    var val = helper();
}

還有依賴注入“dependency injection”設(shè)計(jì)模式纯路,就是將依賴通過參數(shù)顯式地傳遞到函數(shù)中:

function doSomethingCool(FeatureXYZ){
    var helper = FeatureXYZ || function() { /*...*/ }
    var val = helper();
}

2.1數(shù)組

類數(shù)組

有時(shí)需要將類數(shù)組轉(zhuǎn)換為真正的數(shù)組驰唬,這一般通過數(shù)組工具函數(shù)(如indexOf()、concat()叫编、forEach() 等)來實(shí)現(xiàn)。

例如:一些DOM查詢操作會(huì)返回DOM元素列表卷谈,或arguments并非真正的數(shù)組恃逻。工具函數(shù)slice()經(jīng)常被用于這種類轉(zhuǎn)換:

function foo() {
    var arr = Array.prototype.slice.call( arguments );
    arr.push( "bam" );
    console.log( arr );
}
foo( "bar", "baz" );   // ["bar", "baz", "bam"]

slice() 返回參數(shù)列表的一個(gè)數(shù)組復(fù)本。ES6的Array.from() 也能實(shí)現(xiàn)同樣的功能:

var arr = Array.from( arguments );

2.2 字符串

JS中字符串和字符數(shù)組并不是一回事

var a = "foo";
var b = ["f", "o", "o"];

它們都是類數(shù)組凸郑,都有l(wèi)ength屬性以及indexOf()(從ES5開始數(shù)組支持此方法) 和concat()方法

var a = "foo";
var b = ["f", "o", "o"];

a.length;  //3
b.length; //3

a.indexOf( "o" );  //1
b.indexOf( "o" );  //1

var c = a.concat( "bar" );   //  "foobar"
var d = b.concat( ["b", "a", "r"] );   //  ["f", "o", "o", "b", "a", "r"]

a === c;   // false
b === d;  // false

a;   // "foo"
b;  // ["f", "o", "o"]

JS中字符串是不可變的芙沥,而數(shù)組是可變的。許多數(shù)組函數(shù)用來處理字符串很方便而昨。

a.join;   //undefined
a.map;  // undefined

var c = Array.prototype.join.call( a, "-" );
var d = Array.prototype.map.call( a, function(v){
    return v.toUpperCase() + ".";
} ).join("");

c;   // "f-o-o"
d;  // "F.O.O"

數(shù)組有一個(gè)反轉(zhuǎn)函數(shù) reverse()歌憨,可惜字符串無法借用,因?yàn)樽址遣豢勺兊摹?br> 一個(gè)變通的辦法是選將字符串轉(zhuǎn)換為數(shù)組甲抖,處理后在轉(zhuǎn)換回字符串:

var c = a.split( "" ).reverse().join();

c;  // "oof" 

2.4 特殊數(shù)值

  1. undefined 指從未賦值
  2. null 指曾賦過值心铃,但目前沒值

void 運(yùn)算符
undefined是一個(gè)內(nèi)置標(biāo)識(shí)符,值為undefined柱衔。通過void運(yùn)算符即可得到該值愉棱。

表達(dá)式 void __ 沒有返回值,因此返回結(jié)果是undefined或链。void并不改變表達(dá)式的結(jié)果档押,只是表達(dá)式不返回值:

var a = 42;
console.log( void a, a );   // undefined 42

void 運(yùn)算符在其他地方也能派上用場(chǎng)祈纯,比如不讓表達(dá)式返回任何結(jié)果

function doSomething() {
    // 注:APP.ready 由程序自己定義
    if(!APP.ready) {
        // 稍后在試
        return void setTimeout( doSomething, 100 );
    }
    var result;
    // 其他
    return result;
}

這里setTimeout() 函數(shù)返回一個(gè)數(shù)值,但是為了確保if語(yǔ)句不產(chǎn)生誤報(bào)(false positive)粒没,我們要void掉它簇爆。

2.4.3 特殊的數(shù)字

NaN 意指 “不是一個(gè)數(shù)字” not a number
NaN 是一個(gè)特殊值爽撒,它和自身不相等响蓉,是唯一一個(gè)非自反的值枫甲。
從ES6起可使用工具函數(shù) Number.isNaN()。

JS的運(yùn)算結(jié)果有可能溢出想幻,此時(shí)結(jié)果為Infinity 或 -Infinity

JSON.stringify(-0) 返回 “0”,而JSON.parse("-0"); 返回 -0

2.4.4 特殊等式

由于NaN和自身不相等闹究,所以必須使用ES6中的Number.isNaN()食店。而-0 等于 0,因此我們必須使用isNgeZero()這樣的工具函數(shù)

ES6加入了一個(gè)工具方法Object.is() 來判斷兩個(gè)值是否絕對(duì)相等砂代,可用來處理上述所有的特殊情況

2.5 值和引用

簡(jiǎn)單值(scalar primitive)率挣,總是通過值復(fù)制的方式來賦值/傳遞,包括null 捶箱、nudefined 动漾、 字符串、數(shù)字晨川、布爾和Symbol删豺。
復(fù)合值(compound value)-對(duì)象和函數(shù),則總是通過引用復(fù)制的方式來賦值/傳遞妈拌。
由于引用指向的是值本身而非變量蓬蝶,所以一個(gè)引用無法更改另一個(gè)引用的指向猜惋。

var a = [1, 2, 3];
var b = a;
a;  // [1, 2, 3]
b; // [1, 2, 3]

// 然后
b = [4, 5, 6];
a;  // [1, 2, 3]
b; // [4, 5, 6]

原生函數(shù)可被當(dāng)作構(gòu)造函數(shù)來使用培愁,但其構(gòu)造出來的對(duì)象可能會(huì)和我們?cè)O(shè)想的有所出入:

var a = new String( "abc" );
typeof a;    // Object
a instanceof String;  // true
Object.prototype.toString.call( a );   // "[object String]"

通過構(gòu)造函數(shù)創(chuàng)建出來的是封裝了基本類型值的封裝對(duì)象竭钝。

3.1 內(nèi)部屬性[[Class]]

所有typeof 返回值為 “object”的對(duì)象都包含一個(gè)內(nèi)部屬性[[Class]]。這個(gè)屬性無法直接訪問卧波,一般通過 Object.prototype.toString() 來查看庇茫。

Object.prototype.toString.call( [1, 2, 3] );
// "[object Array]"

Object.prototype.toString.call( /regex-literal/i );
// "[object RegExp]"

null 和 undefined這樣的原生構(gòu)造函數(shù)并不存在,但是內(nèi)部[[Class]]屬性值仍然是 "Null" 和 "Undefined"

基本類型值通常稱為“包裝”

3.2封裝對(duì)象包裝

由于基本類型值沒有.length和.toString()這樣的屬性和方法查坪,需要通過封裝對(duì)象才能訪問宁炫,此時(shí)JS會(huì)自動(dòng)為基本類型值包裝一個(gè)封裝對(duì)象:

var a = "abc";
a.length;  //3
b.toUpperCase();   // "ABC"

一般情況下,我們不需要直接使用封裝對(duì)象望忆,最好的辦法是讓JS引擎自己決定什么時(shí)候應(yīng)該使用封裝對(duì)象竿秆。

3.3 拆封

如果想要得到封裝對(duì)象中的基本類型值,可使用valueOf()函數(shù)

var a = new String( "abc" );
var b = new Number( -42 );
var c = new Boolean( true );

a.valueOf();  // "abc"
b.valueOf();  //  42
c.valueOf();  // true

3.4 原生函數(shù)作為構(gòu)造函數(shù)

應(yīng)盡量避免使用構(gòu)造函數(shù)歉备,除非十分必要匪燕,同為它們經(jīng)常會(huì)產(chǎn)生意想不到的結(jié)果。

3.4.1 Array()

var a = new Array(1, 2, 3);
a;  // [1, 2, 3]

var b = [1, 2, 3];
b;  // [1, 2, 3]

Array構(gòu)造函數(shù)只帶一個(gè)數(shù)字參數(shù)的時(shí)候肚豺,該參數(shù)會(huì)被作為數(shù)組的預(yù)設(shè)長(zhǎng)度(length)界拦,而非只充當(dāng)數(shù)組中的一個(gè)元素享甸。更關(guān)鍵的是,數(shù)組并沒有預(yù)設(shè)長(zhǎng)度這個(gè)概念蛉威。這樣創(chuàng)建出來的只是一個(gè)空數(shù)組,只不過它的length 屬性被設(shè)置成了指定的值哲虾。這會(huì)導(dǎo)致一些怪異行為择示。

我們可創(chuàng)建包含空單元的數(shù)組栅盲,只要將length屬性設(shè)置為超過實(shí)際單元的值,就能隱式地制造出空單元谈秫。還可通過delete來制造出一個(gè)空單元拟烫。

join() 首先假定數(shù)組不為空,然后通過length屬性值來遍歷其中的元素硕淑。
map() 直接遍歷數(shù)組中的元素喜颁,無元素則執(zhí)行失敗

array.apply(null, {length: 3}); 執(zhí)行的實(shí)際上是 Array( undefined, undefined, undefined);雖然這有些奇怪和繁瑣,但是其結(jié)果遠(yuǎn)比Array(3) 更準(zhǔn)確可靠

總之隔披,永遠(yuǎn)不要?jiǎng)?chuàng)建和使用空單元數(shù)組寂拆。

3.4.2 Object() Function() RegExp()

同樣,除非萬(wàn)不得已鬓长,否則盡量不要使用 Object() Function() RegExp()
在實(shí)際情況中沒有必要使用new Object() 來創(chuàng)建對(duì)象尝江,因?yàn)檫@樣就無法像常量形式那樣一次設(shè)定多個(gè)屬性,而必須逐一設(shè)定啤覆。

構(gòu)造函數(shù)Function 只在極少數(shù)情況下很有用,比如動(dòng)態(tài)定義函數(shù)和函數(shù)體的時(shí)候相恃。
強(qiáng)烈建議使用常量(如 /^a*b+/g)形式來定義正則表達(dá)式笨觅。這樣不僅語(yǔ)法簡(jiǎn)單,執(zhí)行效率也更高杀糯,因?yàn)镴S引擎在代碼執(zhí)行前會(huì)對(duì)它們進(jìn)行預(yù)編譯和緩存炮温。

有時(shí)RegExp()很有用,比如動(dòng)態(tài)定義正則表達(dá)式時(shí):

var name = "Kyle";
var namePattern = new RegExp( "\\b(?:" + name + ")+\\b", "ig" );
var matches = someText.match( namePattern );

3.4.3 Date() Error()

創(chuàng)建日期對(duì)象必須使用 new Date()倦挂。Date() 可帶參數(shù)担巩,用來指定日期和時(shí)間,而不帶參數(shù)的話則使用當(dāng)前日期和時(shí)間犯戏。

Date() 主要用來獲得當(dāng)前的Unix時(shí)間戳 (從 1970.1.1 開始計(jì)算拳话,以秒為單位)弃衍。該值可通過日期對(duì)象中的getTime() 來獲得。
從ES5 開始可使用Date.now() 來獲得镜盯。如果調(diào)用Date() 時(shí)不帶new關(guān)鍵字速缆,則會(huì)得到當(dāng)前日期的字符串值。

if(!Date.now){
    Date.now = function(){
        return (new Date()).getTime();
    }
}

構(gòu)造函數(shù)Error() 帶不帶new關(guān)鍵字都可剧董。
創(chuàng)建錯(cuò)誤對(duì)象主要是為了獲得當(dāng)前運(yùn)行棧的上下文。

function foo(x){
    if (!x) {
        throw new Error( "x wasn`t provided" );
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末侠草,一起剝皮案震驚了整個(gè)濱河市犁嗅,隨后出現(xiàn)的幾起案子褂微,更是在濱河造成了極大的恐慌园爷,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件求厕,死亡現(xiàn)場(chǎng)離奇詭異扰楼,居然都是意外死亡弦赖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門沼沈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來币厕,“玉大人,你說我怎么就攤上這事页衙⊥保” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)棒妨。 經(jīng)常有香客問我,道長(zhǎng)伏穆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任陪腌,我火速辦了婚禮诗鸭,結(jié)果婚禮上参滴,老公的妹妹穿的比我還像新娘。我一直安慰自己蝌箍,他們只是感情好暴心,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布酷勺。 她就那樣靜靜地躺著,像睡著了一般脆诉。 火紅的嫁衣襯著肌膚如雪击胜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天暇唾,我揣著相機(jī)與錄音辰斋,去河邊找鬼宫仗。 笑死够挂,一個(gè)胖子當(dāng)著我的面吹牛孽糖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播办悟,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼病蛉,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了琢感?” 一聲冷哼從身側(cè)響起探熔,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤诀艰,失蹤者是張志新(化名)和其女友劉穎饮六,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绿满,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡喇颁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年橘霎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了殖属。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡外潜,死狀恐怖挠唆,靈堂內(nèi)的尸體忽然破棺而出损搬,到底是詐尸還是另有隱情柜与,我是刑警寧澤嵌灰,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布沽瞭,位于F島的核電站,受9級(jí)特大地震影響驹溃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜豌鹤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一布疙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧截型,春花似錦儒溉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)锌唾。三九已至,卻和暖如春晌涕,著一層夾襖步出監(jiān)牢的瞬間余黎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工巡扇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乖坠。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓熊泵,卻偏偏與公主長(zhǎng)得像甸昏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子卒蘸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • 第5章 引用類型(返回首頁(yè)) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,216評(píng)論 0 4
  • ??引用類型的值(對(duì)象)是引用類型的一個(gè)實(shí)例祠肥。 ??在 ECMAscript 中梯皿,引用類型是一種數(shù)據(jù)結(jié)構(gòu),用于將數(shù)...
    霜天曉閱讀 1,044評(píng)論 0 1
  • 概要 64學(xué)時(shí) 3.5學(xué)分 章節(jié)安排 電子商務(wù)網(wǎng)站概況 HTML5+CSS3 JavaScript Node 電子...
    阿啊阿吖丁閱讀 9,128評(píng)論 0 3
  • 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的 JavaScript 類型 使用基本類型和基本包裝類型 引用類型的...
    悶油瓶小張閱讀 677評(píng)論 0 0
  • 函數(shù)和對(duì)象 1、函數(shù) 1.1 函數(shù)概述 函數(shù)對(duì)于任何一門語(yǔ)言來說都是核心的概念权逗。通過函數(shù)可以封裝任意多條語(yǔ)句冤议,而且...
    道無虛閱讀 4,550評(píng)論 0 5