您现在的位置: 万盛学电脑网 >> 程序编程 >> 脚本专题 >> javascript >> 正文

理解Javascript的动态语言特性

作者:佚名    责任编辑:admin    更新时间:2022-06-22

   这篇文章主要介绍了理解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