JavaScript深入【表達式和運算符(上集)】你能過我8關js運算符的題目嗎?


 

博主留言 (茗洋芳竹 


      每一個高手成功之路,都要學會怎樣與孤獨打交道 。我是個傻孩子,孤獨竟然是我的夫人,每天晚上都會坐在我旁邊看我學習,寫博客。馬上要離開ASP.NET生涯,投奔PHP了,一切都是那么突然,因此我的《ASP.NET MVC4 In Action》學習竟然不像以前那么有動力開始小題大做了。一句話:生活不會去適應你,所以你要去適應生活。

雖然現在沒有上班,很累很墮落,但是每到了晚上,我就會去學習,不是因為堅持,而是我別無選擇------茗洋芳竹

imageimage

 

當我寫完這篇博客的時候,已經是第二天的6點半了,經過6個小時的整理與demo的編寫,有些疲憊,但是還是很有收獲。

1.    原來最簡單的  變量名也是一個表達式,我腦子有了表達式的一個概念了,每次的復雜運算都是表達式的結合。

2.    原來在JavaScript中,數組中的列表逗號之間的元素可以省略,這時省略的空位會填充值undefined。數組直接量的元素列表結尾處可以留下單個逗號,這時並不會創建一個新的值為undefined的元素。所以我們當讀數組中根本不存在的值的時候,會提示讀取的元素為undefined。

3.    三元運算符的來源,舉一反三地理解了,一元運算符,二元運算符。最終結合 運算順序的規律,我真正的理解了下面這個表達式:

       q=a?b:c?d:e?f:g;

4.    我自己可以成功 完成 遞增運算的 充分講解,以后不怕這種考  運算順序的題目了

5.    我自己出了 8 道js運算符題目,如果你想挑戰來證明自己的js能力, 請點擊我就能快速到達      

6.    ~運算符的使用  點擊快速到達

7.  數組有個sort方法,調用后,竟然排序了原來的數組,還有排序的規律

上篇博客地址 :JavaScript深入【詞法結構,類型,值和變量】原來也不簡單

                                              

 

 

表達式 (茗洋芳竹 


 

1.1 原始表達式

           表達式的做小單位--它們不在包含其他表達式,JS中的原始表達式:常量或者直接量、關鍵字和變量

           例如:

  //原始表達式  第一種原始表達式  --直接量
  var a="hello world";  //字符串直接量
  var b=/pattern/; //正則表達式直接量
  
  //第二種原始表達式  --保留字   true,false,null,this(返回當前對象)
  var c=true;
  var d=null;
  var global=this;    //this並不是常量,它在程序的不同地方返回的值也不相同。在一個方法體內,this返回調用這個方法的對象
  
  //第三種原始表達式  --變量
  var i;
  var sum;
  var c=undefined;    //undefined是全局變量

         

           常見錯誤解釋:當JavaScript代碼中出現了標識符,JavaScript會將其當做變量而去查找它的值。如果變量名不存在,表達式運算結果為undefined。然而,在ECMAScript5的嚴格模式中,對不存在的變量進行求值會拋出一個引用錯誤異常。

 

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

       ①對象和數組初始化表達式實際上是一個新創建的對象和數組。這些初始化表達式有時稱作“對象直接量”和“數組直接量”

         它們所包含的成員或者元素都是子表達式。

       例如:

  //對象和數組的初始化表達式
  var h=[];               //創建一個空數組:[]代表空數組
  var j=[1+2,3+4];        //擁有兩個元素的數組,第一個是3,第二個是7
  var k=[[1,2,3],[4,5,6],[7,8,9]];    //js中的數組中的元素可以是對象

          數組直接量中的列表逗號之間的元素可以省略,這時省略的空位會填充值undefined。數組直接量的元素列表結尾處可以留下單個逗號,這時並不會創建一個新的值為undefined的元素。

       例如:

  var l=[1,,,,5];      // 等同於      var l [1,undefined,undefined,undefined,5]
  alert(l[3]);     //undefined

 

        ②對象直接量類似,用 “:”  隔開 key:value

       例如:

  var p={x:2,y:-1.2,z:"哈哈哈"};
  var q={};
  q.x=2.3;
  q.y=-1.2;
  alert(q.x+"   "+q.y);
  //對象直接量也可以嵌套
  var rectangle1={ "up_left":{x:2,y:2},
                  "up_right":{x:8,y:2},
                  "down_left":{x:2,y:10},
                  "down_left":{x:8,y:10}
      };
  var rectangle2={ "top_left":{x:0,y:0},
                  "width":p.x,
                  "height":p.y
      };

 

1.3 函數定義表達式
 var area_square=function(x){
        return x*x;
        }      
    alert(area_square(10));
    
    var area_round=function GetArea_Round(r){
        return (Math.PI*r*r).toFixed(2);
        }
 //    alert(GetArea_Round(10)); //這樣是錯的
     alert(area_round(10));
     

     用個變量保存一個函數,調用的時候,直接變量名(參數),而不能是函數function后面的那個名字。

     函數定義表達式,var 變量名=function(參數,參數){…}

 

1.4 屬性訪問表達式
     var o={x:1,y:{z:3}};
     var a=[o,4,[5,6]];
     alert(o.x);         //1
     alert(o.y.z);       //3
     alert(o["x"]);      //1
     alert(a[1]);        //4 索引是從0開始的,1代表第二個值,即4
     alert(a[2]["1"]);   //6  表達式a[2]中索引為1的元素
     alert(a[2][1]);     //6  表達式a[2]中索引為1的元
     alert(a[0].x);      //1  表達式a[0]的x屬性

 

1.5 調用表達式
     //調用表達式
     //1. 調用自己的函數
       function ReturnString(name){
           return "我的姓名是:"+name;
           }
       var c=ReturnString("茗洋芳竹");
       alert(c);
     
     //2.調用系統的函數
      var maxNumber=Math.max(1,2,3,4,5);   //參數至少1個,可以多個數字
      alert(maxNumber);
      
     //3.調用對象的方法
     var unordered_array=[34,51,11,35,633,25];
     var unordered_array2=["banana","apple","group","Play","zero","continue","1s","11s","2p"];
     var ordered_array=unordered_array.sort();
     var ordered_array2=unordered_array2.sort();
     alert(ordered_array.toString());
     alert(unordered_array2.toString());   //sort(),改變了原數組,說明是數組引用類型,並不是復制了數組
     alert(ordered_array2.toString());    //排序字符的時候,按照數字,英文大寫字母A-Z,然后小寫字母a-z順序排序
     

某些東東,我就用圖片順便表示

    image

1.6 對象創建表達式

         概念:對象創建表達式創建一個對象並調用一個函數(構造函數)初始化新對象的屬性。類似於 函數調用表達式,只是對象創建表達式之前多了一個關鍵字new:

    var obj=new Object();   //創建一個對象
    // var point=new Point(2,3);      //Point類是自己定義的
     
     var obj2=new Object;
     var date=new Date;
     alert(date);

如果一個對象創建表達式不需要傳入任何參數傳給構造函數的話,那么這對空圓括號是可以省略掉的

 


 

 

運算符 (茗洋芳竹 


2.1 運算符概述

         大多數運算符都是由標點符號表示的,比如 “+”和“=”。還有一些運算符是由關鍵字表示的,比如delete和instanceof。

         下面一張表是按照 運算符優先級排序的,從高到低。

         水平分割線分隔開來的運算符具有不同的優先級。

         標題為A的列    表示運算符的結合性,L(從左到右)或R(從右到左)

         標題為N的列    表示操作數的個數

         標題為“類型”的列   表示期望的操作數類型,以及運算符的結果類型(在“→”符號之后)

image
①lval是left-value的簡寫,意思是“左值”
2.1.1 操作數的個數
運算符可以根據其操作數的個數分類:
①一元運算符:它們將一個表達式轉換為另一個稍復雜的的表達式。比如表達式“-X”中的“-”運算符就是個一元運算符,是將操作數X求負數。

②二元運算符:比如“*”乘號,將兩個表達式合並成一個稍復雜的表達式,換言之,它們的操作數均是兩個,比如5*2

③三元運算符:比如“?:”,它將三個表達式合並成一個表達式。例如:
   
     var name="茗洋芳竹";
     var sanyuan_surname=name.indexOf("茗洋")>-1?"茗洋":"未知";
     
     //等同於下面的if語句
     var if_surname="無名";
     if(name.indexOf("茗洋")>-1){
         if_surname="茗洋";
     }else{
         if_surname="未知";
        }
        
     alert(sanyuan_surname+"   "+if_surname);       //茗洋
 
2.1.2 操作數類型和結果類型
一些運算符可以作用於任何類型數據,但仍然希望它們的操作數是指定類型的數據,並且大多數運算符返回(或計算出)一個特定類型的值。
左圖中“類型”列中列出了運算符操作數的類型(箭頭左)和運算結果(箭頭右)
  JavaScript運算符通常會對操作數進行類型轉換。比如乘號,表達式“3”*“5”是合法的。因為JavaScript會將操作數轉換為數字,返回值是15,而不是字符串“15
”。有些運算符比如“+”號,可以做加法運算,也可以做字符串連接。
2.1.3 左值
它是指:表達式只能出現在賦值運算符的左側.

 

2.1.4 運算符的副作用

          有一些的表達式具有很多副作用,前后的表達式運算會相互影響。賦值運算符最明顯:如果給一個變量或屬性賦值,那么那些使用這個變量或屬性的表達式的值都會發生改變。“++”和“--”遞增和遞減運算符與此類似,因為它們包含隱式的賦值delete運算符同樣有副作用:刪除一個屬性就像(但不完全一樣)給這個屬性賦值undefined。其他的JavaScript運算符都沒有副作用,但函數調用表達式和對象創建表達式有些特別,在函數體或者構造函數內部運用了這些運算符並產生了副作用的時候,我們說函數調用表達式和對象創建表達式是有副作用的。

 

2.1.5 運算符優先級(不管是JS還是其他語言,面試可能會碰到)

   那張圖表是有規律的。運算符優先級控制着運算符的執行順序。優先級高的運算符(圖片的頂部)的執行總是先於優先級低(圖片的底部)的運算符

例1:

      var w=x+y*z;

      運算符優先級:“*”>“+”>賦值運算符“=”,因此賦值操作是在右側的表達式計算出結果后進行的

 

例2:(我自己額外的題目,答案的字體顏色已被我設成白色,你可以鼠標選中答案后面的空白的地方查看,只是想幫助那些面試者解決心里的一個疑惑)   

如果7題中,你做錯了很多,就說明你真的還不理解運算符的計算順序,沒關系,下面我會讓你掌握的,也會讓你結合那張圖片,理解和學會 計算含有  遞增,遞減運算符的題目。先學習下面的,先不要糾結那幾道我出的題目。 

       第一關:

     var j=1;
     j=j=j+1;

           答案是2.

 

       第二關:

     var j=1;
     j=j++;
     alert(j);

          答案是1.

     

  (重點)第三關:

     var j=1;
     j=(j++)+j+(j++)+(++j)+j;
     alert(j);

          答案是13.

     

       第四關:

     var j=1;
     j+=j++;
     alert(j);

          答案是.

     

      第五關 :

     var j=1;
     j+=++j;
     alert(j);

          答案是3 .

 

 
           第六關 : 
          
     var j=1;
     j=j=j+1;
     j=j++;
     j+=++j;
     j+=j++;
     alert(j);
 
           答案是10. 
          
 
          
 
          
 
          
 
           第七關(分別彈出兩次框,有兩個答案) : 
          
 
          
     var i=1;
     i+=i/i+i++;
     alert(i);       //
     i++; 
     ++i;
     i+=i/i+(++i);
     alert(i);   //

        答案是3和12.

    

     第八關:

     var i=1;
     i+=(i++)+(++i)/i;   
     alert(i);

       答案是3.

 

其他說明:

首先說明一下單獨使用時i++等同於i=i+1;而i+=等同於  i=i+后面的表達式

順便說明一下 i++和 ++i的區別,i++單獨使用時候和++i一模一樣,i++是等i這個表達式運算結束后再運算i+1,然后改變i的值,

而++i是先運算i+1,然后改變i的值,然后再和外面的表達式結合,進行整體運算。

 

 

乘法和除法的優先級高於加法和減法,賦值運算符的優先級非常低,通常總是最后執行的。

 

例3:(涉及到屬性訪問表達式和方法調用時候,優先執行方法調用和屬性訪問表達式,它們優先級高於上圖列出的所有運算符)

     var o=[1,3,5];
     var c=[o,2,4,6];
     function GetExpression(k){
         return k/k*k+k/k-k;    
         }
     var g=5;
     g=g/GetExpression(g)+12/c[0][1]*g;
     alert(g);

答案是25.        (答案的字體已被我設成白色,你可以鼠標選中“答案是”后面的空白處查看)

 

    如果7題中,你做錯了很多,就說明你真的還不理解運算符的計算順序,沒關系,下面我會讓你學會的,也會讓你結合那張圖片,理解和學會 計算含有  遞增,遞減運算符的題目。先學習下面的,先不要糾結那幾道我出的題目。
   

2.1.6 運算符的結合性

     上張圖中的  標題為A的列說明了運算符的結合性質。L指從左往右結合,R指從右往左結合。結合性指定了在多個具有同樣優先級的運算符表達式中的運算順序。從左往右是指運算的執行是按照由左往右順序進行。例如:

      第四個例子是重點,以后會經常遇到,不一定是JavaScript語言,C#,Java中也有

      ①減法運算符是從左往右的結合性

       image

      因此  w=x-y-z和這段代碼一模一樣:w=((x-y)-z)

      ②~ 按位非運算符和 “-”求反運算符結合,這兩個運算符都是從右往左結合的

       image    

       首先我們先講解一下 ~ 的運算過程:首先改變符號,再減去1的一個運算

        例如:

      var x=10;
      var y=~x;
      alert(y);    // x先求反,得到-10,然后再減去1,得到-11,這就是最終結果

        最終我們彈出的框顯示的是 –11

        下面我們來結合一下~和-

      var x=10;
      var y=~-x;
      alert(y);    

         答案是9。 (答案的字體已被我設成白色,你可以鼠標選中“答案是”后面的空白處查看)

       

     理解過程:

        -號和~號都是從右往左結合,所以上面的第二行代碼等同於    var y=~(-x);

        -x的值就是 –10,然后再求反減去1,也就是 -10變成10,然后減一變成了 9。

 

     ③w=x=y=z中的   賦值運算,是從右往左結合的,所以代碼等同於w=(x=(y=z));

     ④?: 三元運算符的結合,它也是從右往左的結合性

        image

        代碼如下:

             q=a?b:c?d:e?f:g;

         效果就等同於

             q=a?b:(c?d:(e?f:g));

         現在看懂了嗎?所以運算符的結合性很重要。

 

2.1.7 運算順序(重點)

       運算符的優先級和結合性規定了它們在復雜的表達式中的運算順序,但是並沒有規定子表達式中的計算過程中的運算順序。

       JavaScript總是嚴格按照從左往右的順序來計算表達式。例如

       在表達式w=x+y*z中,首先計算子表達式w,然后計算x,y和z,然后y的值和z的值相乘,再加上x的值,最后將其賦值給表達式w所指代的變量或屬性。給表達式添加括號將會改變乘法、加法和賦值運算的關系,但從左往右的順序是不會改變的

       例1:(書中的一個例子,我覺得講解方式有問題,再例3中我會反駁)

      var a=1;
      var b=(a++)+a;
      alert(b);

        答案是。 (答案的字體已被我設成白色,你可以鼠標選中“答案是”后面的空白處查看)

        講解:

            1. 計算b

            2. 計算a++(我們假設為c);

            3. 計算c;

            4. 計算c+a;

            5. 將c+a的結果賦值給b。按照“++”的定義,在第二步中的a++結果依然是1,也就是c為1,隨后a立即增長1,因此在執行第三步的時候,a的值已經是2了,所以c+a  也就是 1+2,所以b的最終值等於3.

 

 

       例2:我們就我出的第三關我例子,在講解一下

            題目如下:

     var j=1;
        j=(j++)+j+(j++)+(++j)+j;
     alert(j);

          答案是13. (答案的字體已被我設成白色,你可以鼠標選中“答案是”后面的空白處查看)

          講解:

            1.我們先把第二行代碼 轉換如下

                j=a+j+b+c+j;

               a,b,c分別先替換掉那幾個遞增運算,此時都是+號運算,根據+號的結合性是從左往右(L)

            2. 首先計算a,所以a=1,隨后此時j遞增1,所以j=2了,然后再計算a后面的那個j,此時代碼可以替換如下

                j=1+2+b+c+j;

            3. 然后計算b,b=j++,即b=2;隨后,j遞增1,所以j=3了,所以 此時代碼可以替換如下

                j=1+2+2+c+j;

            4. 然后計算c,c=++j,即c=++3,即c=4;所以 此時代碼可以替換如下

                j=1+2+2+4+j;

              此時j已經變成4了,所以代碼可以替換成  j=1+2+2+4+4;

           5. 將最終的結果賦值給j,所以最終 j 最終 13

 

       例3:(改一下例1)

     例1:

      var a=1;
      var b=a+(a++);
      alert(b);

        答案是2。 (答案的字體已被我設成白色,你可以鼠標選中“答案是”后面的空白處查看)

         講解:

              1. 第二行代碼可替換成 b=a+c,其中c=a++;

              2. 如果按照例1的講解方式,應該先執行a++,然后a變成2了,最終的形式是b=2+1才對,也就是還是等於3

                 但是最終結果如下:

               image      

                而例1中的結果是

                image

                所以說按照 先++遞增運算符,然后在+號運算感覺不對,某些情況我覺的還是從左往右對,畢竟事實勝於雄辯

             3.  所以說 var b=a+(a++)的理解思路是 先假設b=a+c; 其中c=a++;然后由於+號是從左往右的結合性,所以

                  ①b=1+c;

                  ②b=1+(a++); 即b=1+1;隨后 a增長1,然后 b=2

             如果不相信這個思路,下面圖片還可以證明

                image

                image

都是從左往右,不在乎 先遞增運算符,如果在乎的話,var b=a+(++a);這個題目

就是先++1; 即c部分已經等於2了,然后此時a遞增變成2,那么此時var b=2+2才對,但是結果並不是

順便我們再解決一下疑惑,a運算完了,是夠遞增了,答案是遞增了,不管你是a++還是++a,代碼如圖

image

image

所以借此機會,我們可以講解一下我的 第七關題目:

第七關(分別彈出兩次框,有兩個答案) :
 
          
     var i=1;
     i+=i/i+i++;
     alert(i);       //
     i++; 
     ++i;
     i+=i/i+(++i);
     alert(i);   //

        答案是3和12.

        講解:

          1.   i+=i/i+i++; 即i=i+i/i+i++; 根據+號從左往右的結合性,i=1+1/1+i++;即i=2+i++;

          2.  然后i=2+1;不過隨后,受i++的影響,此時i等於2了;但是2+1=3最終進行了賦值操作,原本i=2,此時又等於3了

          3.  所以第一彈出框顯示3

          4.  經過兩次遞增,到達 第6行代碼時候,i已經變成5了

          5. i+=i/i+(++i); 即i=i+i/i+(++i); 根據+號從左往右的結合性,i=5+5/5+(++i);即i=6+(++5);

          6. 然后 i=6+(6),經過遞增后,此時i=6了,但是又因為賦值(=)運算,原本的i=6,此時經過賦值,變成12了。

 

我還做了幾個測試

   image

   image

 

 

本次博客,花大手筆講解 運算符的前一部分,重點原理性的解決關於遞增運算符的困擾。如果你看懂了,覺得還不錯,給個推薦好嗎?或者給個評論,你們的關心是我的動力。為了方便閱讀,所以運算符還剩的一點內容,在下一篇講解

 

相關代碼下載:點擊直接下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM