1.數值

js中只有一種數據類型number,而他們都是以IEEE-754標準格式表示的,針對小數,他們都是以二進位的來表示的,有些小數只能做到盡一定程度上的上的精確,但是無法保證精度丟失。

比如0.1,顯然0.1不能用2進位精確的表示,那麼必然會帶來精度缺失,比如1/3 = 0.333一樣,不管後面的小數位有多少,總是不能精確的表示。所以才會產生1.0-0.9 !==0.1這種情況。

2.值類型和引用類型的區別

2.1.JavaScript中的變數類型有哪些?

(1)值類型:字元串(string)、數值(number)、布爾值(boolean)、none、undefined、symbol

(2)引用類型:對象(Object)、數組(Array)、函數(Function)等

2.2.值類型和引用類型的區別

(1)值類型:

  1. 佔用空間固定,保存在棧中(當一個方法執行時,每個方法都會建立自己的內存棧,在這個方法內定義的變數將會逐個放入這塊棧內存里,隨著方法的執行結束,這個方法的內存棧也將自然銷毀了。因此,所有在方法中定義的變數都是放在棧內存中的;棧中存儲的是基礎變數以及一些對象的引用變數,基礎變數的值是存儲在棧中,而引用變數存儲在棧中的是指向堆中的數組或者對象的地址,這就是為何修改引用類型總會影響到其他指向這個地址的引用變數。)
  2. 保存與複製的是值本身
  3. 使用typeof檢測數據的類型
  4. 基本類型數據是值類型

(2)引用類型:

  1. 佔用空間不固定,保存在堆中(當我們在程序中創建一個對象時,這個對象將被保存到運行時數據區中,以便反覆利用(因為對象的創建成本通常較大),這個運行時數據區就是堆內存。堆內存中的對象不會隨方法的結束而銷毀,即使方法結束後,這個對象還可能被另一個引用變數所引用(方法的參數傳遞時很常見),則這個對象依然不會被銷毀,只有當一個對象沒有任何引用變數引用它時,系統的垃圾回收機制才會在核實的時候回收它。)
  2. 保存與複製的是指向對象的一個指針
  3. 使用instanceof檢測數據類型
  4. 使用new()方法構造出的對象是引用型

3.表達式與語句

表達式:js的一種短句,js解釋器會將其計算出一個結果;

數據訪問表達式:

語句:js整句或者命令,表達式計算出一個值,但是用來自行一使某件事情發生。js中某些需要語句的地方可以使用一個表達式來代替,這樣的語句稱為表達式語句。

4.函數表達式和函數聲明

函數聲明:function () { } 加上一個名字,就變成非匿名函數。

然後把他們賦值給另外一個對象就變成了函數表達式。

用函數聲明定義的函數可以在聲明之前調用,而表達式定義的只能在聲明之後調用。

原因:解釋器對著兩種讀取的順序不同,解釋器會事先讀取函數聲明,即函數聲明放在任何地方都能夠被調用;而函數表達式只有讀到所在行之後才能被讀取,然後調用。

補充:

1,使用var表達式定義的函數,只是聲明變數提前了,而變數初始化還在原來的地方,也是一開始對象是undefined,沒有賦值;

2,js不允許在函數聲明的後面直接使用小括弧,而表達式就沒有這個限制,可以使用~ 、!、+、-、()等讓解釋器把後面看作是一個函數表達式(自執行函數),這個操作符的作用是在語法上讓解釋器再執行一次evaluate,讓他變成一個表達式,表達式就有返回值,加上()讓他立即執行,具體哪些操作可以 可參考ECMA標準。

如:

(function(x, y){
alert(x + y);
})(2, 3); //把第一個括弧整體在F12中執行,發現返回值是一個函數,函數遇到()就會執行。
自執行函數類似於
var b=function () {
}
b();
其實最好的運算符還是()因為其他欄位可能會與返回的結果發生計算從而改變結果

5.自執行的匿名函數

1. 什麼是自執行的匿名函數?

它是指形如這樣的函數: (function {// code})();

2. 疑問

為什麼(function {// code})();可以被執行, 而function {// code}();卻會報錯?

3. 分析

(1). 首先, 要清楚兩者的區別:

(function {// code})是表達式, function {// code}是函數聲明.

(2). 其次, js"預編譯"的特點:

js在"預編譯"階段, 會解釋函數聲明, 但卻會忽略表式.

(3). 當js執行到function() {//code}();時, 由於function() {//code}在"預編譯"階段已經被解釋過, js會跳過function(){//code}, 試圖去執行();, 故會報錯;

當js執行到(function {// code})();時, 由於(function {// code})是表達式, js會去對它求解得到返回值, 由於返回值是一 個函數, 故而遇到();時, 便會被執行.

(4).優點 (function {// code})() 這裡的code可以任意編寫,匿名函數形成一個類似「容器」,容器外部不能訪問內部變數,從而命名不會發生衝突。

6.變數提升Hoisting:

6.1遇到script標籤的話,解釋器就會預解析將變數var和函數聲明提升,但不會執行函數,然後就進入context,context還是執行預解析相同的操作,直到沒有var和函數聲明。

如:

a=5;
show();
var a;
function show(){};

預解析:

function show(){};
var a;
a=5;
show();

函數聲明提升直接把整個函數提到執行環境的最頂端。

還可以使用匿名函數,但是匿名函數不存在函數提升,只有變數提升,因為函數名稱使用變數來表示。如果我們在作用域中重複地聲明同名函數,則會由後者覆蓋前者;

6.2 Temporal Dead Zone 臨死區域TDZ

在ES6中為了規避var的變數提升,引用了新的let 和const 兩種聲明,他們不會提升到頂部,只會提升到臨死區域,訪問TDZ中的變數會觸發運行錯誤,只有執行過聲明語句後,變數才會從TDZ中移除,然後就可以正常訪問

綜合來講,當js解釋器遇到變數聲明時,要麼提升至頂部(var),要麼提升至TDZ(let和const)。


推薦閱讀:
相关文章