萬盛學電腦網

 萬盛學電腦網 >> 腳本專題 >> javascript >> 理解Javascript的動態語言特性

理解Javascript的動態語言特性

   這篇文章主要介紹了理解Javascript的動態語言特性,需要的朋友可以參考下

  Javascript是一種解釋性語言,而並非編譯性,它不能編譯成二進制文件。

  理解動態執行與閉包的概念

  動態執行:javascript提供eval()函數,用於動態解釋一段文本,並在當前上下文環境中執行。

  首先我們需要理解的是eval()方法它有全局閉包和當前函數的閉包,比如如下代碼,大家認為會輸出什麼呢?

  ?

1 2 3 4 5 6 7 var i = 100; function myFunc() { var i = 'test'; eval('i = "hello."'); } myFunc(); alert(i); // 100

  首先我們來看看先定義一個變量i=100,然後調用myFunc這個函數,然後修改局部變量i,使他從值 'test'變成'hello', 但是我們知道eval的含義是立即執行一段文本的含義;因此上面的代碼我們可以寫成如下代碼:

  ?

1 2 3 4 5 6 7 8 9 var i = 100; function myFunc() { var i = 'test'; (function(){ return (i = "hello."); })(); } myFunc(); alert(i); // 100

  這樣就很明顯了,執行myFunc()這個方法後,i的值從test變為hello的值,但是由於是閉包,i的值為hello,它不能被外部使用,所以浏覽器打印的都是100值;

  我們都知道eval()是javascript的全局對象Global提供的方法,而如果要訪問Global對象的方法,可以通過宿主對象-在浏覽器中是window來提供;按道理來說,下面的代碼應該也是輸出100;如下:

  ?

1 2 3 4 5 6 7 var i = 100; function myFunc() { var i = 'test'; window.eval('i="hello."'); } myFunc(); alert(i);

  然後不幸的是:在IE下不管是window.eval()還是eval()方法輸出的都是100;但是在標准浏覽器下使用window.eval(),輸出的是hello,使用eval()方法的輸出的是100; 因為IE下使用的是JScript引擎的,而標准浏覽器下是SpiderMonkey Javascript引擎的,正是因為不同的javascript引擎對eval()所使用的閉包環境的理解並不相同。

  理解eval使用全局閉包的場合

  如下代碼:

  ?

1 2 3 4 5 6 7 var i = 100; function myFunc() { var i = 'test'; window.eval('i="hello."'); } myFunc(); alert(i);

  在標准浏覽器下,打印的是hello,但是在IE下打印的是100;如果使用如下代碼:

  ?

1 2 3 4 5 6 7 8 var i = 100; function myFunc() { var i = 'test'; //window.eval('i="hello."'); eval.call(window,'i="hello"'); } myFunc(); alert(i);

  也是一樣的,也是給eval方法提供一種訪問全局閉包的能力;但是在IE下Jscript的eval()沒有這種能力,IE下一只打印的是100;不過在IE下可以使用另一種方法得到一個完美的結果,window.execScript()方法中執行的代碼總是會在全局閉包中執行,如下代碼:

  ?

1 2 3 4 5 6 7 8 var i = 100; function myFunc() { var i = 'test'; window.execScript('i="hello."'); //eval.call(window,'i="hello"'); } myFunc(); alert(i); // 打印hello

  JScript()引擎使用execScript()來將eval在全局閉包與函數閉包的不同表現分離出來,而Mozilla的javascript引擎則使用eval()函數的不同調用形式來區分它們。二者實現方法有不同,但是可以使用不同的方式實現全局閉包;

  理解eval()使用當前函數的閉包

  一般情況下,eval()總是使用當前函數的閉包,如下代碼:

  ?

1 2 3 4 5 6 7 var i = 100; function myFunc() { var i = 'test'; eval('i="hello."'); } myFunc(); alert(i); // 100

  如上代碼:因為eval作用與是函數內的代碼,所以輸出的是全局變量i等於100;

  eval()總是被執行的代碼文本視為一個代碼塊,代碼塊中包含的是語句,復合語句或語句組。

  我們可以使用如下代碼取得字符串,數字和布爾值;

  eval('true'); // true

  eval('"this is a char"'); // string

  eval('3'); // 數字3

  但是我們不能使用同樣的方法取得一個對象;如下代碼:

  eval('{name:"MyName",value:1}');

  如上代碼會報錯;如下:Uncaught SyntaxError: Unexpected

  其實如上那樣寫代碼,{name:"MyName",value:1},eval會將一對大括號視為一個復合語句來標識,如下分析:

  第一個冒號成了 “標簽聲明”標示符。

  {“標簽聲明”的左操作數}name成了標簽。

  MyName成了字符串直接量;

  Value成了變量標示符。

  對第二個冒號不能合理地作語法分析,出現語法分析期異常;

  如果我們只有這樣一個就不會報錯了,如下代碼:

  eval('{name:"MyName"}')

  輸出"MyName";

  那如果我們想要解決上面的問題要如何解決呢?我們可以加一個小括號包圍起來,使其成為一個表達式語句,如下代碼:

  eval('({name:"MyName",value:1})')

  輸出一個對象Object {name: "MyName", value: 1}

  但是如下的匿名函數加小括號括起來在IE下的就不行了,如下代碼:

  var func = eval('(function(){})');

  alert(typeof func); // IE下是undefined

  在標准浏覽器chrome和firefox是打印function,但是在IE下的JScript引擎下打印的是undefined,在這種情況下,我們可以通過具名函數來實現;如下:

  eval('function func(){}');

  alert(typeof func); // 打印是function

  我們使用eval時候,最常見的是ajax請求服務器端返回一個字符串的格式的數據,我們需要把字符串的格式的數據轉換為json格式;如下代碼:

  // 比如服務器返回的數據是如下字符串,想轉換成json對象如下:

  var data = '{"name":"Mike","sex":"女","age":"29"}';

  console.log(eval("("+data+")"));

  打印Object {name: "Mike", sex: "女", age: "29"} 就變成了一個對象;

  // 或者直接如下 ,都可以

  console.log(eval("("+'{"name":"Mike","sex":"女","age":"29"}'+")"));

  我們還需要明白的是使用eval或者with語句,他們都會改變作用域的問題,比如使用eval如下代碼:

  ?

1 2 3 4 5 6 7 var
copyright © 萬盛學電腦網 all rights reserved