180306 表達式

表達式是js中的一個短語,js解釋器會將其計算出一個結果。

原始(原始值)表達式

  • 常量
  • 直接量
 1.23          //數字直接量
'hello'        //字符串直接量
/pattern/     //正則表達式直接量  
  • 關鍵字
true   //返回一個布爾值:真
false  //返回一個布爾值:假
null   //返回一個值:空
this   //返回'當前'對象
  • 變量
a            //返回變量a的值
undefined    //undefined是全局變量,它不是一個關鍵字
  • 當js中出現了標識符,js會將其當作變量而去查找它的值。如果變量名不存在,表達式運算結果爲undefined。而在es5嚴格模式中,對不存在的變量進行求值會拋出一個錯誤異常。

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

對象和數組的初始化表達式實際上是一個新創建的對象和數組。這些初始化表達式有時稱作 ‘對象直接量 ’,‘數組直接量 ’
和布爾值直接量不同,它們不是原始表達式,因爲 它們所包含的成員或者元素都是子表達式。

  • 數組直接量中的列表逗號之間的元素可以省略,這時省略的空位會填充值undefined。
var s = [1,,,,5];
  • 對象直接量中的屬性名可以是字符串而不是標識符。
var s = {'apple':{a:1,b:2}}

函數定義表達式

也可以叫做函數直接量

var square = function(x){return x * x};

屬性訪問表達式

屬性訪問表達式運算 得到一個對象屬性或一個數組的值。

expression.identifer
expression[expression]   //如果屬性名稱是一個【1】保留字或者包含【2】空格和標點符號,或者是【3】數字(對於數組來說)則必須使用方括號。
var o = {x:1,y:{z:3}};
var a = {o,4,[5,6]};
o.x         // 1:表達式o的屬性x
o.y.z       // 3:表達式o.y的z屬性
o['x']      // 1:表達式o的屬性x
a[1]        // 4:表達式a中索引爲1的元素
a[2]['1']   // 6:表達式a[2]中索引爲1的元素
a[0].x      // 1:表達式a[0]的x屬性

調用表達式

是一種調用函數或方法的語法表示。函數表達式開始,表達式後跟隨一個括號,括號內是一個以逗號隔開的參數列表。

f(0)  // f 是一個函數表達式,0是一個參數表達式
Math.max(x,y,z)  // Math.max 是一個函數;x,y,z是參數
a.sort()  // a.sort 是一個函數,它沒有參數

如果函數使用return語句給出一個返回值,那麼這個返回值就是整個調用表達式的值。

如果一個表達式是屬性訪問表達式,那麼這個調用稱做 ‘方法調用’。

在方法調用中,執行函數體的時候,作爲屬性訪問主題的對象和數組便是其調用方法內this的指向。這種特性使得在面向對象編程範例中,函數可以調用其宿主對象。


對象創建表達式

創建一個對象並調用一個函數初始化新對象的屬性。

調用的函數稱作構造函數

對象創建表達式和函數調用表達式非常相似,只是對象創建表達式之前多了一個關鍵字new,如果對象創建表達式不需要傳如任何參數給構造函數的話,那麼括號可以省略

new Object()
new Point(2,3)
new Object
new Date

運算符概述

運算順序

var a = 1;
var b =(a++)+a; //它這步a不變,這步結束a自增
console.log(b);

正確順序:

  1. 計算b [b = (a++)+a]
  2. 計算a++ (設 c) [c = 1]
  3. 計算a [a = 2]
  4. 計算c+a [3]
  5. c+a結果賦值給b [3]

算數表達式

‘+’ 運算符

  • 加法或字符串連接。
  • 如果存在字符串或類字符串(對象轉換爲字符串),優先考慮字符串連接。
  • 加法操作符行爲:
    如果其中一個操作數是對象,則根據對象到原始值的準換規則轉換成原始值。【toString() valueOf()】
    轉換後,如果其中一個操作數是字符串,另一個操作數也會被轉換爲字符串,然後進行連接。
    否則,都轉換成數字加法操作。
1 + 2 // 3 : 加法
'1' + '2' // '12' : 字符串連接
'1' + 2  // '12' : 數字轉換爲字符串後進行字符串拼接
1 + {} // '1[object Object]':對象轉換爲字符串後進行字符串連接
true + true // 2 : 布爾值轉化爲數字後做加法
2 + null // 2 : null轉化爲0後做加法
2 + undefined // NaN : undefined轉換爲NaN後做加法

一元算數運算符
’ + ’ ’ - ’ ’ ++ ’ ’ – ‘

  • 根據需要把操作數轉換爲數字。

位運算符


關係表達式

相等和不相等運算符

比較運算符

  • 更偏愛數字,只有兩個都是字符串的時候纔會進行字符串的比較
11 < 3 // 數字比較,false
'11' < '3' // 字符串比較,true
'11' < 3  // 數字的比較,false
'one' < 3 //數字的比較,'one'轉換爲NaN,false

in運算符

  • in運算符希望它的左操作數是一個字符串或可以轉換爲字符串,希望它的右操作數是一個對象。
  • 如果右側的對象 擁有一個名爲左操作數值的屬性名(索引),那麼表達式返回true
var point = {x:1,y:1};
'x' in point   // true : 對象有一個名爲'x'的屬性
'z' in point   // false : 對象中不存在名爲'z'的屬性
'toString' in point    // true : 對象繼承了toString()方法
var data = [7,8,9];   
'0' in data    // true : 數組包含元素'0'
1 in data      // true : 數字轉換爲字符串
3 in data      // false : 沒有索引爲3的元素

instanceof運算符

  • instanceof運算符希望左操作數是一個對象,右操作數標識對象的類。
  • 如果左側的對象是右側的實例,則返回true。
  • JS中對象的類是通過初始化它們的構造函數來定義的,這樣右操作數是一個函數。
var d = new Date();
d instanceof Date  // true : d是由Date()創建的
d instanceof Object  // true : 所有的對象都是Object()的實例
d instanceof Number  // false : d不是一個Number對象
var a = [1,2,3];
a instanceof Array  // true : a是一個數組
a instanceof Object // true : 所有的數組都是對象
a instanceof RegExp // false : 數組不是正則表達式
  • 所有的對象都是Object的實例。當通過instanceof判斷一個對象是否是一個類的實例的時候,這個判斷也會包含對‘父類’的檢測。

邏輯表達式

邏輯與(&&)

並不總是返回true和false。

運算符首先計算左操作數的值,即首先計算’&&’左側的表達式。如果計算結果是假值,那麼整個表達式的結果一定也是假值,因此’&&’這時簡單地返回左操作數的值,而並不會對右操作數進行計算。

如果左操作數是真值,那麼整個表達式的結果則依賴於右操作數的值。如果右操作數是真值,那麼整個表達式也是真值。因此,當左操作數的真值時,’&&’運算符計算右操作數的值並將其返回作爲整個表達式的計算結果。

var a = 10 && 20;   20


var o = {x:1};
var p = null;
o && o.x  // 1:o是真值,因此返回值爲o.x
p && p.x  // null:p是假值,因此返回值爲p
// 計算表達式p.x會拋出一個錯誤異常,而使用邏輯與運算符避免了問題。

邏輯與運算是否繼續執行,看左操作數是否爲真值或轉換爲真值
如果能,執行右操作數,返回右操作數的值;如果爲假值或轉換爲假值,返回左操作數的值,不繼續計算。

可以稱這種特性爲“短路”。

if (a == b) stop();
a == b && stop();

邏輯或(||)

首先計算第一個操作數的值,也就是說會首先計算左側的表達式。如果計算結果爲真值,那麼返回這個真值。否則,再計算第二個操作數的值,並返回這個表達式的結果。

常用方式是用來從一組備選表達式中選出第一個真值表打式:

var a = 10 || 20;    10 遇到真就返回

//如果max_width已經定義了,直接使用它;否則再preferences對象中查找max_width
//如果沒有定義它,則使用一個寫死的常量
var max = max_width || preference.max_width || 500

或者用來給參數提供默認值:

// 將o的成員屬性複製到p中,並返回p
function(o,p){
    p = p || {}; //如果向參數p沒有傳入任何對象,則使用一個新創建的對象
}

邏輯非(!)

首先將其操作數轉換爲布爾值,然後再對布爾值求反。也就是說’!’總是返回true或者false,並且可以通過使用兩次邏輯非運算得到一個值的等價布爾值:!!x


賦值表達式

帶操作的的賦值運算

  • 大多數情況下,表達式爲:a op= b
    和下面的表達式等價:a = a op b

  • 注意:在第一行中,表達式計算了一次,第二行計算了兩次。
    只有在a包含具有副作用的表達式(比如函數調用和賦值操作)的時候,兩者纔不等價。

  • a op= b + c -> a = a op (b + c)
var a = [10, 20, 30, 40];
var b = [10, 20, 30, 40];

var i = 0;   
var j = 0;

var test1 = a[i++] *= 2;
// a[0] = 10 * 2;
var test2 = b[j++] = b[j++] * 2;
// b[0] = b[1] * 2; 

i = 1; j = 2; test1 = 20; test2 = 40;
a = [20,20,30,40]; b = [40,20,30,40] 

表達式計算

eval()


其它運算符

  • 條件運算符
    條件運算符是JS中唯一一個三元運算符。
x > 0 ? x : -x  // 求絕對值

應用場景:判斷一個變量是否有定義(並擁有一個有意義的真值)

greeting = 'hello' + (username ? username : 'there');
// 與下面等價,更簡潔
greeting = 'hello';
if(username)
    greeting += username;
else
    greeting += 'there';
  • typeof運算符
x                typeof x
undefined       'undefined'
null            'object'
true false      'boolean'
數字,NaN        'number'
字符串           'string'
函數             'function'
內置對象          'object'
宿主對象          有編譯器各自實現的字符串,但不是以上的返回值 

typeof最常用的用法是寫在表達式中:

(typeof value == 'string') ? " ' " + value + " ' " : value

typeof可以帶上括號,讓其看起來像一個函數名:

typeof(i)

typeof對於區分原始值很有效,對於對象的類,則需要使用其他手段:instanceof運算符,class特性,constructor屬性。數組會被返回爲’object’。

  • delete運算符
var o = {x:1,y:2};
delete o.x;
'x' in o 

var a = [1,2,3];
delete a[2];
2 in a;   //false:元素2在數組中已經不存在了
a.length  //3:注意數組長度還是3,儘管刪除了這個元素,但刪除後留下了一個洞,沒有修改數組長度。

注意:刪除屬性或者刪除數組元素不僅僅是設置了一個undefined的值,這個屬性將不再存在。讀取一個不存在的屬性將返回undefined,所以檢測這個屬性是否真正的消失可以通過in運算符。

  • void運算符

操作數正常計算,但忽略計算結果並返回undefined。由於void會忽略操作數的值,因此在操作數具有副作用的時候使用void來讓程序更具語義。
這個運算符最常用在客戶端的URL中—-JavaScript:URL中,在URL中可以寫帶有副作用的表達式,而void則讓瀏覽器不必顯示這個表達式的計算結果:

<a href="javascript: window.open();">打開一個窗口</a>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章