1. 程式人生 > >JavaScript基礎入門教程(三)

JavaScript基礎入門教程(三)

直接 復制 一般來說 得到 方式 註意 元素 nbsp 通過

說明

  前面的兩篇博客介紹了js中的基本知識中的變量類型、標識符等。這篇博客主要談表達式以及運算符。

原始表達式

  原始表達式就是表達式中最小的,不能在分割的表達式,一般指變量、常數直接量、關鍵字(true、false、null、this),這裏需要註意的是undefined是一個全局變量,而不是關鍵字。

對象和數組的初始化表達式

  數組初始化表達式是一個方括號,中間放置數組中的元素,元素間用逗號分割。元素可以是表達式、數組、空。

1 []    //一個空數組,數組裏面沒有元素
2 [1+2,3+4]    //一個擁有兩個元素的數組,第一個是3,第二個是7。
3 [[1,2,3],[4,5,6],[7,8,9,]]    //
數組中的元素還可以是數組。 4 [1,,,,5] //數組中的元素可以為空,這時空位會填充值undefined。

  在執行var a=[1,,,,5]這條語句後,在chrome中表現為下圖所示:

技術分享圖片

  對象初始化表達式和數組初始化表達式非常類似。

1 var stu={name:"張三", age:15};    //定義一個擁有兩個屬性的對象。

  上面這行初始化對象的表達式類似於下面的數組,事實上js也確實支持這種寫法訪問對象中的屬性。

1 stu["name"]="張三";
2 stu["age"]=15;

  如果你學過java那麽上面那句var stu={name:"張三", age:15};可以很容易的寫成下面的java代碼:

 1 class Student{
 2     String name;
 3     int age;
 4 
 5     Student(String name, int age){
 6         this.name=name;
 7         this.age=age;
 8     }
 9 }
10 
11 Student stu=new Student("張三", 15);

  不過js可以完美支持多層的內部類,而java卻對內部類有好多限制。

屬性訪問表達式

  在js中,屬性訪問有①expression.identifier、②expression[expression]這兩種方式。其中第一種雖然方便卻只能用於對象,而且要求訪問的屬性(identifier)不能是關鍵字、不能含有空格、不能是數字。而第二種訪問方式不僅支持對象還能用於數組,並且用於對象訪問自己的屬性時沒有第一種那麽多的限制。

1 var o={x:1, y:{z:3}};
2 var a=[o, 4, [5, 6]];
3 o.x   //1:訪問o的x屬性
4 o.y.z    //3:訪問o的y的z屬性
5 o["x"]    //1:訪問o的x屬性
6 a[1]    //4:訪問a的索引為1的元素
7 a[2]["1"]    //6:訪問a[2]中的索引為1的元素
8 a[0].x    //1:通過訪問a[0]得到o,再訪問o的x屬性

運算符

技術分享圖片

  js所支持的運算符如上圖所示,學過其它編程的同學基本上看上一眼就知道了。這裏只對需要註意的部分做出說明。在基本算術運算符(加減乘除和求余)只有加法是相對有難度的,因為有時候它是加法,而有時候它又是字符串連接符,具體用法可概括為只有+運算符兩邊都是數字才是加法,更詳細的用法請參考這篇博客。此外還需要談的就是求余運算符,其運算結果的符號和左操作數相同,即5%1=1、-5%1=-1。

  在js的位運算時,會有一個隱式轉換過程。默認情況下js中的數字都是存儲為64位浮點數格式,在位運算的時候會轉換為32位整數,所以隱式轉換會截斷小數部分和整數中超過32位能表示的部分。此外NaN、infinity和-infinity會轉換為0。

  關於等於(==)運算符和嚴格等於(===)運算符請參考本系列教程的第一篇。

in運算符

  in運算符希望它的左操作數是一個字符串或者能轉換為字符串,希望它的右操作數是一個對象。如果右側對象擁有一個名為左操作數的屬性則整個in表達式返回true。

1 var point={x:1, y:1};
2 "x" in point    //true:對象中有一個名為x的屬性
3 "z" in point    //false:對象中不存在一個名為z的屬性
4 "toString" in point    //true:對象繼承了toString()方法
5 
6 var data=[7, 8, 9];
7 "0" in data    //true:數字包含下標為0的元素
8 1 in data    //true:數字轉換為字符串
9 3 in data    //false:沒有索引為3的元素

&&與||

  學過C和java等語言的同學應該知道這兩個運算符有一個特性就是短路,這個特性在js中也同樣存在,習慣性利用這種特性為函數提供默認值。

1 function copy(o, p){
2     o.p = p || {};
3 }

  上面的代碼中,如果copy函數被調用的時候p形參有值,則將p復制給o.p,否則將默認值{}復制給o.p。

表達式計算

  在js中存在一個函數叫eval(),雖然這是一個函數,但一般被當成運算符來對待。一般來說函數是可以起別名的,比如var f=eval;再通過f調用eval函數。但是一般不推薦對eval函數起別名,ECMAScript3標準甚至直接禁止對eval函數起別名,所以說它幾乎被當成運算符對待。之所以這樣是因為這涉及到代碼優化的問題,如果允許對eval函數起別名將嚴重影響代碼的優化過程。

  上面談了eval的特點,現在來說一下它的作用。這個函數只有一個參數,且一般是字符串。如果傳入的參數是字符串,js解釋器會把這個字符串當成js代碼來執行,且其執行環境為直接調用這個eval函數的上下文(下面將詳細解釋),如果其傳入的參數不是字符串,則eval函數直接返回這個參數值。

1 var global=1;
2 var foo = function(ele){
3     var local = 2;
4     eval(ele);
5     console.log(where);
6 }
7 foo("console.log(global);console.log(local);var where=‘I am here!‘;");
8 console.log(where);

  上面這行代碼的執行結果(在chrome中)如下圖所示:

技術分享圖片

  根據上面所說的eval的執行環境為直接調用eval的上下文,在上圖顯示的結果中為第8行所處的上下文,這樣的話eval自然能訪問global和local變量,但是其定義的where變量只能讓foo函數內部且在第8行以後的代碼訪問,這樣以來第9行代碼能正確執行,而第12行代碼拋出異常。

  前面談過ECMAScript3禁止對eval起別名,但是現實中大多數解釋器的實現並非如此,之後的ECMAScript5標準也允許別名調用,但規範了其行為。當eval被別名調用時,其運行環境永遠為全局環境,與其調用者環境沒有關系,也就是說間接調用(別名調用)無法讀、寫、定義局部變量。

 1 var geval = eval;
 2 var x = "global", y = "global";
 3 function f(){
 4     var x="local";
 5     eval("x += ‘ changed‘;");
 6     return x;
 7 }
 8 function g(){
 9     var y="local";
10     geval("y += ‘ changed‘;");
11     return y;
12 }
13 console.log(f(), x);
14 console.log(g(), y);

  上面代碼執行的結果(在chrome中)為:

技術分享圖片

JavaScript基礎入門教程(三)