1. 程式人生 > >ECMAScript 學習筆記(2)--基本類型及語法相關

ECMAScript 學習筆記(2)--基本類型及語法相關

ECMAScript 學習筆記

1、變量名區分大小寫; 註意代碼塊的概念。
變量分為原始值和引用值:原始值存儲在棧,引用值存儲在堆(引用值一般是一個指針或對象名、函數名)。在C語言中編譯的程序占用的內存分為以下幾個部分:棧區(由系統分配/內存塊連續)、堆區(由程序員分配與釋放或系統結束後釋放/鏈表結構不連續的內存塊)、全局區、文字常量區、程序代碼。
(1)原始類型有5種:Undefined、Null、Boolean、Number、String
Null專用值為null表示尚存在的對象,Undefined申明變量未初始化賦予該值(不等同於未定義的值,typeof無法區分是未聲明還是未初始化)

var oTemp;
typeof(oTemp);

console.log(oTemp == undefined);

結果為:

Hello
undefined
true

如果直接未聲明使用oTemp ==undefined程序報錯,null ==undefined是true說明兩值相等,但是不代表含義相同。
Infinity表示無窮大,往往用isFinite()方法確保該數不是無窮大。還有一個特殊值是NaN,表示非數,不用使用NaN==NaN(輸出false)判單非數,使用isNaN()判斷非數。

console.log(NaN ==NaN);
var i=123;
console.log(isNaN(i)+‘+++++++‘+isNaN(a));

結果為:

false
false+++++++true

Number可以為32位整數也可以為64位浮點數,String大小是沒有固定的

(2)引用類型通常叫做class,遇到引用值也就是處理對象。ECMAScript中其實沒有類這個詞,主要用對象定義,等同其他語言的類概念。

(3)以js舉例:JavaScript的執行上下文生成之後,會創建一個叫做變量對象的特殊對象,基礎數據類型往往都會保存在變量對象中,引用數據類型的值是保存在堆內存中的對象。JavaScript不允許直接訪問堆內存數據,需要通過地址引用訪問(操作地址值指向堆內存空間數據訪問),如下代碼:

var a = 10;
var b = a;

b = 100;
console.log(a); //a=10 a、b是兩個獨立的變量空間,相互不幹擾

再看:

var a= { m: 10, n: 20 }
var b = a;
b. m= 15;
console.log(a.m); //輸出15 a、b兩個不同空間變量指向同一個地址引用

2、函數聲明整體提升,變量的聲明提升到(一種理解得比較形象好記憶的方式,並非本質原理,原理參考3)。
沒有聲明或直接賦值的變量會報錯:

console.log(a) //error

後面的變量聲明會提前到最前面

console.log(global); // undefined
var global = ‘global‘;
console.log(global); // global

function fn () {
  console.log(a); // undefined
  var a = ‘aaa‘;
  console.log(a); // aaa
}
fn();

var聲明的變量,內層變量可能會覆蓋外層變量,外層變量會作用的內層;js中未經聲明的變量歸window所有;js中全局變量都歸window所有。

var tmp = new Date();

function f() {
console.log(tmp);
if (false) {
var tmp = ‘hello world‘;
}
}

f(); // undefined

函數聲明有兩種:函數聲明式、函數字面量式(因為var定義的),後者無法函數提升,如下:
console.log(f1); // function f1() {}
console.log(f2); // undefined
function f1() {}
var f2 = function() {}

3、在程序執行前的預編譯中(執行上下文代碼執行過程),一共有4個過程要完成:
(1)創建active object(OA)
(2)找形參和變量聲明,將形參和變量聲明做為OA的屬性名,屬性值為Undefine(此步就是變量提升的本質)
(3)將實參和形參統一
(4)在函數體中找函數聲明,值賦予函數體
變量作用域要理解執行上下文的過程:創建變量對象、執行(變量賦值、函數引用、其他代碼)。其中創建分三個步驟:創建arguments對象,檢查function聲明創建屬性,檢查Var變量聲明創建屬性。

1 var a = 10;
2 function aaa(){//step-4
3 alert(a);//step-5->執行alert,此時只能找到外面的a=10故彈框10
4 }
5 function bbb(){//step-2
6 var a = 20;
7 aaa();//step-3
8 }
9 //定義了函數沒啥用,調用才是真格的所以這裏是step-1
10 bbb();

作用域總結:
(1)ES6之前的js沒有塊級作用域(你可以自己閉包或其他方法實現),只有函數級作用域,函數外面的變量函數裏面可以找到,函數裏面的變量外面找不到
(2) 變量的查找是就近原則,去尋找var定義的變量,當就近沒有找到的時候就去查找外層。函數聲明比var聲明要優先。
(3)當參數跟局部變量重名時,優先級是等同的。傳參時,基本類型傳值,引用類型傳引用。
(4) 理解執行上下文:每個函數執行時產生執行上下文(EC),一個執行上下文定義了一個函數執行環境。

4、立即執行函數(自執行函數)的理解:
先說說如下函數的執行過程,聲明函數式makeCounter(),內部定義變量i,返回一個函數體,該函數體區塊變量i和被返回到的函數體makeCounter中i存儲地址一致,直接上代碼比較結果分析(這裏有點難理解):

function makeCounter() {
// i只是makeCounter函數內的局部變量
var i = 0;

return function() {
console.log( ++i );
};
}
console.log("1----"+makeCounter().toString());
console.log("2----"+(makeCounter())());
console.log("3----"+makeCounter.toString());
console.log("4----"+parseInt(makeCounter()));
var a=makeCounter();
console.log("5----"+a);
a();
顯示結果如下:
1----function () {
console.log(++i);
}
1 //註意這個結果,是由步驟2中console.log產生
2----undefined
3----function makeCounter() {
// i只是makeCounter函數內的局部變量
var i = 0;
return function () {
console.log(++i);
};
}
4----NaN
5----function () {
console.log(++i);
}
1

下面說明下為什麽最後console.log的不同結果:
**每次當控制器轉到可執行代碼的時候,就會進入一個執行上下文。執行上下文可以理解為當前代碼的執行環境,它會形成一個作用域。JavaScript中的運行環境大概包括三種情況:全局環境(JavaScript代碼運行起來會首先進入該環境)、函數環境(當函數被調用執行時,會進入當前函數中執行代碼)、eval。

**函數中,遇到return能直接終止可執行代碼的執行,因此會直接將當前上下文彈出棧。

(1)console.log("1----"+makeCounter().toString()) 對照1,顯示為function(){..},說明執行makeCounter()後函數體,return了的真正值:一個函數體
(2)console.log("2----"+(makeCounter())()) 對照顯示數值1 和 2----undefined,因為函數體function(){...}後加了(),那麽函數就立即執行了,所以打印了1。但是函數本身是沒有返回值的,所以會顯示undefine()
(3)console.log("3----"+makeCounter.toString()) 僅僅是輸出了這個名為makeCounter函數體中存儲的函數式全部代碼內容
(4)非數返回也好理解
(5)同2理解,這裏的實例化後然後用()執行和2一個道理
,唯一不同是沒有console.log(a())

4、立即執行函數的寫法:

// 最常用的兩種寫法
(function(){ / code / }()); // 推薦寫法
(function(){ / code / })();
//與運算符相關聯後
var i = function(){ return 10; }();
true && function(){ / code / }();
0, function(){ / code / }();

// 一元運算符
!function(){ / code / }();
~function(){ / code / }();
-function(){ / code / }();
+function(){ / code / }();

// 你也可以這樣
new function(){ / code / }
new function(){ / code / }() // 帶參數

6、let增加了塊級的作用,不在同一塊內的變量相互不幹擾,外層塊無法讀取內層塊let定義變量:

function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}

零散的記錄了一些,後面會做梳理

ECMAScript 學習筆記(2)--基本類型及語法相關