成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

分析 JavaScript 的數(shù)據(jù)類型與變量

Mike617 / 1753人閱讀

摘要:基本數(shù)據(jù)類型在中,基本數(shù)據(jù)類型有種,即數(shù)值字符串布爾值。兩個布爾值轉(zhuǎn)為數(shù)值進行比較。對于對象和布爾值,調(diào)用它們的方法得到對應(yīng)的字符串值,然后進行字符串相加。減法對于字符串布爾值或者,自動調(diào)用,轉(zhuǎn)換結(jié)果若為,那么最終結(jié)果為。

這篇文章,來聊聊 JS 中的數(shù)據(jù)類型與變量。這是在學(xué)習(xí) JS 時最基礎(chǔ)的一類問題,但卻很重要。希望我的分享有幫助到你。

文章開頭,我先提幾個面試中遇到的問題:

比如:

如何理解參數(shù)的按值傳遞?

什么是暫時性死區(qū)?

什么是變量提升?

全局變量和 window 的屬性有什么區(qū)別?為什么?

... ...

這篇文章的風(fēng)格,在分析知識點的同時,插入一些我經(jīng)歷過的面試題。

基本數(shù)據(jù)類型

在 JS 中,基本數(shù)據(jù)類型有 6 種,即數(shù)值、字符串、布爾值、null、undefined、Symbol。

對于基本數(shù)據(jù)類型,我們需要明白的是:基本類型在內(nèi)存中的存儲方式是棧。每一個值都是多帶帶存放,互不影響。

基本類型都是按值訪問的。在比較時,按值進行比較:

1 === 1 // true
引用數(shù)據(jù)類型

引用類型的值保存在堆中,而引用是保存在棧中。

引用類型按引用訪問。在比較時,也比較的引用:

{} === {} // => false
參數(shù)的傳遞方式

在 JS 中,參數(shù)可以是任何類型的值,甚至可以是函數(shù)。

這里要分析的是參數(shù)是以哪種類型傳遞的?引用類型還是基本類型?

先看一個基礎(chǔ)的例子:

var out_num = 1;

function addOne(in_num) {
    in_num += 1;
    return in_num;
}

addOne(out_num); // => 2
out_num // => 1

這個例子中,我們給 addOne() 函數(shù)傳遞一個實參 out_num,這個時 out_num 會傳遞給 in_num,即內(nèi)部存在著 in_num = out_num 的過程。最后我們看到的結(jié)果是 out_num 并沒有被函數(shù)改變,說明 in_num 和 out_num 是兩個在內(nèi)存中獨立存放的值,即按值傳遞。

再來看一個變形:

var out_obj = { value: 1 };

function addOne(in_obj) {
    in_obj.value += 1;
    return in_obj;
}

addOne(out_obj); // => { value: 2 }
out_obj // => { value: 2 }

問題來了?函數(shù)參數(shù)不是按值傳遞嗎?為什么這里函數(shù)內(nèi)部的處理反映到外部了?這是一個超級超級超級的理解誤區(qū)。

首先,我們還是得擺正觀點,即函數(shù)參數(shù)是按值傳遞的。那這里怎么理解呢?對于引用類型而言,前面說引用類型分為引用和實際的內(nèi)存空間。在這里 out_obj 依舊傳遞給 in_obj,即 in_obj = out_objout_obj 和 in_obj 是兩個引用,它們在內(nèi)存中的存儲方式是獨立的,但是它們卻指向同一塊內(nèi)存。

in_obj.value = 1 則是直接操作的實際對象。實際對象的改變,會同步到所有引用這個實際對象的引用。


你再來看這個例子,或許就會更清晰一些。

var out_obj = { value: 1 };

function addOne(in_obj) {
    in_obj = { value: 2 };
    return in_obj;
}

addOne(out_obj); // => { value: 2 }
out_obj // => { value: 1 }

你只要抓住一點:對象的賦值就會造成引用指向的實際對象發(fā)生改變。

如何判斷數(shù)據(jù)類型

判斷數(shù)據(jù)類型,通常有三種具體的方法:

1、typeof 操作符

typeof 操作符返回一個表示數(shù)據(jù)類型的字符串。它存在以下明顯的缺陷:

typeof null // => "object"

typeof [] // => "object"

這是因為在 JS 語言設(shè)計之初遺留的 bug。可以閱讀這篇文章 http://2ality.com/2013/10/typ... 了解更多關(guān)于 typeof 處理 null 的問題。

所以 typeof 最好用于判斷一些基本類型,比如數(shù)值、字符串、布爾值、undefined、Symbol。

2、instanceof 操作符

typeof 的背后是通過判斷 type tags 來判斷數(shù)據(jù)類型,而 instanceof 則是通過判斷構(gòu)造函數(shù)的 prototype 是否出現(xiàn)在對象原型鏈上的任何位置。

舉個例子:

{} instanceof Object // => true

[] instanceof Array // => true
[] instanceof Object // => true

也判斷自定義類型:

function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
var auto = new Car("Honda", "Accord", 1998);

console.log(auto instanceof Car);
// => true

console.log(auto instanceof Object);
// => true

所以,對于字面量形式的基本數(shù)據(jù)類型,不能通過 instanceof 判斷:

1 instanceof Number // => false

Number(1) instanceof Number // => false

new Number(1) instanceof Number // => true

3、Object.prototype.toString()

這是目前最為推薦的一種方法,可以更加精細(xì)且準(zhǔn)確的判斷任何數(shù)據(jù)類型,甚至是 JSON、正則、日期、錯誤等等。在 Lodash 中,其判斷數(shù)據(jù)類型的核心也是 Object.prototype.toString() 方法。

Object.prototype.toString.call(JSON) // => "[object JSON]"

關(guān)于這背后的原理,你可以閱讀這篇文章 http://www.cnblogs.com/ziyunf...

4、其他

上面三種是通用的判斷數(shù)據(jù)類型的方法。面試中還會出現(xiàn)如何判斷一個數(shù)組、如何判斷 NaN、如何判斷類數(shù)組對象、如何判斷一個空對象等問題。這一類問題比較開放,解決思路通常是抓住判斷數(shù)據(jù)的核心特點。

舉個例子:判斷類數(shù)組對象。

你先要知道 JS 中類數(shù)組對象是什么樣子的,并尋求一個實際的參照物,比如 arguments 就是類數(shù)組對象。那么類數(shù)組對象具有的特點是:真值 & 對象 & 具有 length 屬性 & length 為整數(shù) & length 的范圍大于等于 0,小于等于最大安全正整數(shù)(Number.MAX_SAFE_INTEGER)。

在你分析特點的時候,答案就呼之欲出了。【注意全面性】

數(shù)據(jù)類型如何轉(zhuǎn)換

JS 數(shù)據(jù)類型的動態(tài)性將貫穿整個 JS 的學(xué)習(xí),這是 JS 非常重要的特性,很多現(xiàn)象就是因為動態(tài)性的存在而成為 JS 獨有。

正是由于動態(tài)性,JS 的數(shù)據(jù)類型可能在你毫無察覺的情況下,就發(fā)生了改變,直到運行時報錯。

這里主要分析下面 8 種轉(zhuǎn)換規(guī)則。

1、if 語句

if 語句中的類型轉(zhuǎn)換是最常見的。

if (isTrue) {
    // ...
} else {}

在 if 語句中,會自動調(diào)用 Boolean() 轉(zhuǎn)型函數(shù)對變量 isTrue 進行轉(zhuǎn)換。

當(dāng) isTrue 的值是 null, undefined, 0, NaN, "" 時,都會轉(zhuǎn)為 false。其余值除 false 本身外都會轉(zhuǎn)為 true。

2、Number() 轉(zhuǎn)型函數(shù)

我們重點關(guān)注 null undefined 以及字符串在 Number() 下的轉(zhuǎn)換:

Number(null) // => 0
Number(undefined) // => NaN
Number("") // => 0
Number("123") // => 123
Number("123abc") // => NaN

注意和 parseInt() 對比。

3、parseInt()

parseInt(null) // => NaN
parseInt(undefined) // => NaN
parseInt("") // => NaN
parseInt("123") // => 123
parseInt("123abc") // => 123

4、==

這里需要注意的是:

null == undefined // => true

null == 0 // => false
undefined == false // => false

null 與 undefined 的相等性是由 ECMA-262 規(guī)定的,并且 null 與 undefined 在比較相等性時不能轉(zhuǎn)換為其他任何值。

5、關(guān)系操作符

對于兩個字符串的比較,是比較的字符編碼值:

"B" < "a" // => true

一個數(shù)值,另一個其他類型,都將轉(zhuǎn)為數(shù)字進行比較。

兩個布爾值轉(zhuǎn)為數(shù)值進行比較。

對象,先調(diào)用 valueOf(),若不存在該方法,則調(diào)用 toString()。

6、加法

加法中特別注意的是,數(shù)字和字符串相加,將數(shù)字轉(zhuǎn)為字符串。

"1" + 2 => // "12"
1 + 2 => // 3

對于對象和布爾值,調(diào)用它們的 toString() 方法得到對應(yīng)的字符串值,然后進行字符串相加。對于 undefined 和 null 調(diào)用 String() 取得字符串 "undeifned" 和 "null"。

{ value: 1 } + true // => "[object Object]true"

7、減法

對于字符串、布爾值、null 或者 undefined,自動調(diào)用 Number(),轉(zhuǎn)換結(jié)果若為 NaN,那么最終結(jié)果為 NaN。

對于對象,先調(diào)用 valueOf(),如果得到 NaN,結(jié)果為 NaN。如果沒有 valueOf(),則調(diào)用 toString()。

8、乘法、除法

對于非數(shù)值,都會調(diào)用 Number() 轉(zhuǎn)型函數(shù)。

變量提升與暫時性死區(qū)

JS 中有三種聲明變量的方式:var, let, const。

var 聲明變量最大的一個特點是存在變量提升。

console.log(a); // undefined
var a = 1;
console.log(a); // 1

第一個打印結(jié)果表示,在聲明變量 a 之前,a 就已經(jīng)可以訪問了,只不過并未賦值。這就是變量提升現(xiàn)象。(具體原因,我放在后面分析作用域的時候來寫)

let 和 const 就不存在這個問題,但是又引入了暫時性死區(qū)這樣的概念。

/**
* 這上面都屬于變量 a 的暫時性死區(qū)
* console.log(a) // => Reference Error
*/
let a = 1;
console.log(a); // => 1

即聲明 a 之前,不能夠訪問 a,而直接報錯。

而暫時性死區(qū)的出現(xiàn)又引出另外一個問題,即 typeof 不再安全。你可以參考這篇文章 http://es-discourse.com/t/why...

補充:一個經(jīng)典面試題

for (var i = 0; i < 4; i++) {
    setTimeout(function(){
        console.log(i);
    }, i * 1000);
}

我先不再這里展開分析,我打算放到異步與事件循環(huán)機制中去分析。不過這里將 var 替換成 let 可以作為一種解決方案。如果你有興趣,也可以先去分析。

對于 const,這里再補充一點,用于加深對基本類型和引用類型的理解。

const a = 1;
const b = { value: 1 };

a = 2; // => Error
b.value = 2; // => 2
b = { value: 2 }; // => Error

本質(zhì)上,const 并不是保證變量的值不得改動,而是變量指向的內(nèi)存地址不得改動。

聲明全局變量

直接通過 var 聲明全局變量,這個全局變量會作為 window 對象的一個屬性。

var a = 1;
window.a // => 1

在這里提出兩個問題,一是 let 聲明的全局變量會成為 window 的屬性嗎?二是 var 聲明的全局變量和直接在 window 創(chuàng)建屬性有沒有區(qū)別?

先來回答第一問題。let 聲明的全局變量不會成為 window 的屬性。用什么來支撐這樣的結(jié)論呢?在 ES6 中,對于 let 和 const 聲明的變量從一開始就形成封閉作用域。想想之前的暫時性死區(qū)。

第二個問題,var 聲明的全局變量和直接在 window 創(chuàng)建屬性存在著本質(zhì)的區(qū)別。先看下面的代碼:

var a = 1;
window.a // => 1

window.b = 2;

delete window.a
delete window.b

window.a // => 1
window.b // => undefined

我們可以看到,直接創(chuàng)建在 window 上的屬性可以被 delete 刪除,而 var 創(chuàng)建的全局屬性則不會。這是現(xiàn)象,通過現(xiàn)象看本質(zhì),二者本質(zhì)上的區(qū)別在于:

使用 var 聲明的全局變量的 [[configurable]] 數(shù)據(jù)屬性的值為 false,不能通過 delete 刪除。而直接在對象上創(chuàng)建的屬性默認(rèn) [[configurable]] 的值為 true,即可以被 delete 刪除。(關(guān)于 [[configurable]] 屬性,在后面的文章中分析對象的時候還會提到)

小結(jié)

在這篇「數(shù)據(jù)類型與變量」文章中,分析了 7 個大類。再來回顧一下:

基本類型、引用類型、參數(shù)傳遞方式、如何判斷數(shù)據(jù)類型、數(shù)據(jù)類型如何轉(zhuǎn)換、變量提升與暫時性死區(qū)、聲明全局變量。

這些不僅是校招面試中的高頻考點,也是學(xué)習(xí) JS 必不可少的知識點。

Tip1:《JavaScript 高級程序設(shè)計》這本書被稱作“前端的圣經(jīng)”是有原因的。對于正在準(zhǔn)備校園招聘的你,非常有必要!書讀百遍,其義自見。你會發(fā)現(xiàn)你在面試中遇到的絕大部分 JS 相關(guān)的知識點都能在這本書中找到“答案”!

Tip2:在準(zhǔn)備復(fù)習(xí)的過程中,注意知識的模塊性與相關(guān)性。你得有自己劃分知識模塊的能力,比如今天的「數(shù)據(jù)類型與變量」模塊。相關(guān)性是指,任何的知識都是由聯(lián)系的,比如這里牽涉到作用域、內(nèi)存等模塊。

這篇文章會不斷更新,如有出入,也希望你在后臺留言,或者 Email 給我:

[email protected]

文章首發(fā)在 cameraee 微信公眾號

并同步更新至以下平臺:

CSDN https://blog.csdn.net/swpu_leo
Segment fault https://segmentfault.com/u/sw...
掘金 https://juejin.im/user/58bd20...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/99293.html

相關(guān)文章

  • JavaScript instanceof運算符深入分析

    摘要:注意基本變量類型不是對象類型,只有基本包裝類型才是對象類型。至于顯示的原型,在里用屬性表示,這個是原型繼承的基礎(chǔ)知識,在這里就不在敘述了。 前言 如果你要開發(fā)一個復(fù)雜的產(chǎn)品,那么肯定少不了使用面向?qū)ο髾C制,當(dāng)然也避不開 Javascript 里面的繼承,instanceof 運算符是原生 Javascript 語言中用來判斷實例繼承的操作符。所以我們有必要深入理解該運算符! inst...

    zhangyucha0 評論0 收藏0
  • 前端基礎(chǔ)進階(一):內(nèi)存空間詳細(xì)圖解

    摘要:一棧數(shù)據(jù)結(jié)構(gòu)與不同,中并沒有嚴(yán)格意義上區(qū)分棧內(nèi)存與堆內(nèi)存。引用數(shù)據(jù)類型的值是保存在堆內(nèi)存中的對象。不允許直接訪問堆內(nèi)存中的位置,因此我們不能直接操作對象的堆內(nèi)存空間。為了更好的搞懂變量對象與堆內(nèi)存,我們可以結(jié)合以下例子與圖解進行理解。 showImg(https://segmentfault.com/img/remote/1460000009784102?w=1240&h=683); ...

    _Suqin 評論0 收藏0
  • javascript高級程序設(shè)計》筆記:內(nèi)存執(zhí)行環(huán)境

    摘要:因此,所有在方法中定義的變量都是放在棧內(nèi)存中的當(dāng)我們在程序中創(chuàng)建一個對象時,這個對象將被保存到運行時數(shù)據(jù)區(qū)中,以便反復(fù)利用因為對象的創(chuàng)建成本通常較大,這個運行時數(shù)據(jù)區(qū)就是堆內(nèi)存。 上一篇:《javascript高級程序設(shè)計》筆記:繼承近幾篇博客都會圍繞著圖中的知識點展開 showImg(https://segmentfault.com/img/bVY0C4?w=1330&h=618);...

    fuyi501 評論0 收藏0
  • JavaScript_高程三_01

    摘要:表示應(yīng)該立即下載腳本,但不妨礙頁面的其它操作。因此,在元素中設(shè)置,屬性,相當(dāng)于告知瀏覽器立即下載,但延遲執(zhí)行。在使用聲明變量但未對其加以初始化,這個值就是。特點任何涉及的操作例如都會返回多不計算中有可能導(dǎo)致問題 JavaScript 簡介 JavaScript實現(xiàn) 核心 (ECMAScript)文檔對象模型 (DOM)瀏覽器對象模型 (BOM) ECMAScript ECMA-262定...

    yvonne 評論0 收藏0
  • 夯實基礎(chǔ)-作用域閉包

    摘要:作用域分類作用域共有兩種主要的工作模型。換句話說,作用域鏈?zhǔn)腔谡{(diào)用棧的,而不是代碼中的作用域嵌套。詞法作用域詞法作用域中,又可分為全局作用域,函數(shù)作用域和塊級作用域。 一篇鞏固基礎(chǔ)的文章,也可能是一系列的文章,梳理知識的遺漏點,同時也探究很多理所當(dāng)然的事情背后的原理。 為什么探究基礎(chǔ)?因為你不去面試你就不知道基礎(chǔ)有多重要,或者是說當(dāng)你的工作經(jīng)歷沒有亮點的時候,基礎(chǔ)就是檢驗?zāi)愫脡牡囊豁?..

    daydream 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<