动态执行eval

JavaScript的代码从是运行在一个闭包环境。

JavaScript代码的解释执行过程:

1.在JavaScript中,代码文本是先被解释为语法树,然后按照语法树来执行。

2.在每次执行语法树中的一个函数的实例时,会将语法树中与该函数相关的形式参数、函数局部变量、upvalue以及子函数等信息复制到一个结构中,该结构称为ScriptObject(调用对象)。

3.ScriptObject动态关联到一个闭包,闭包与ScriptObject具有不同的生存周期;

4.按照语法树来执行函数体中的代码,需要访问变量时,先考察ScriptObject中的局部变量等,最后考察upvalue。

这个过程着哦功能,闭包是ScriptObject的执行环境,ScriptObject的数据都存储在闭包。而ScriptObject只是对数据进行标记。

JavaScript的eval()从是将被执行的代码文本视为一个代码块(block),而代码块包含语句组。JavsScript的语句存在返回值,通过最后一条语句返回。(除空语句和控制语句之外)。

如果控制语句,没有返回值哦,在eval的语句执行系统里面

alert(eval('for(var i=0;i<10;i++);'));

返回的是undefined。

如果是赋值语句,没有返回值哦,在eval的语句执行系统里面

alert(eval('i=6; for (var i=0; i<10; i++);;;;'));

返回的是6.

在eval里面,返回的就是最后一条语句。

在eval里面,声明一个对象,

eval('({ value: 1 })')

因为大括号{}在eval的语句执行系统里面会被当作复合语句的标示,等同于if()后面的{}。所以要用运算符()。

eval()的执行环境是当前函数的闭包。

var i = 100;
function myFunc(){
    var i = 'test';
    eval('i = "hello".');
}
myFunc();

alert(i);

注意点就是,变量作用域会变化。

var i = 100;
function myFunc(ctx){
    alert('value is: ' + i);//这里的i调用的是外部变量i
    eval(ctx);
    alert('value is: ' + i);//这里的i,因为上一条语句的eval里面声明了个i,所以调用上一条语句的
}
myFunc('var i = 10');

动态方法调用call与apply

call与apply功能一样,参数不一样。

什么是call:

function Obj(){this.value="对象!";}
    var value="global 变量";
    function Fun1(){alert(this.value);}

    window.Fun1();   //global 变量
    Fun1.call(window);  //global 变量
    Fun1.call(document.getElementById('myText'));  //input text
    Fun1.call(new Obj());   //对象!

call的第一个参数,通常是对象,用来替换Fun1方法里面的this。call的第二个,第三个参数等等,就是Fun1方法的参数了。

 

call的this引用传递例子:

function foo(){
    alert(this.name);
}

function MyObject(){
    this.name = 'MyObject';
}

MyObject.prototype.doAction = function(){
    foo.call(this);
}

var obj3 = new MyObject();
obj3.doAction(); 
call的传递参数例子:
function clac_area(w, h){
    alert(w * h);
}

function Area(){
    this.name = 'MyObject';
}

Area.prototype.doCalc = function(v1, v2){
    clac_area.call(this,v1, v2);
}

var area = new Area();
area.doCalc(10 ,20);

callee与caller

callee是好东西,是arguments的属性,arguments.callee表示函数对象自身。

一,可以用来获取形式参数和实际参数的个数

function calleeLengthDemo(arg1, arg2) {
            alert(arguments.callee.toString());

            if (arguments.length == arguments.callee.length) {

                window.alert("验证形参和实参长度正确!");

                return;

            } else {

                alert("实参长度:" + arguments.length);

                alert("形参长度: " + arguments.callee.length);

            }

        }
     calleeLengthDemo(1);

二,用于匿名函数调用自身,防止全局变量污染咯

函数内部包含了对自身的引用,函数名仅仅是一个变量名,在函数内部调用即相当于调用一个全局变量。

var fn=function(n){

        if(n>0) return n+fn(n-1);

        return 0;

     }

     alert(fn(10))

不能很好的体现出是调用自身,这时使用callee会是一个比较好的方法

var fn=(function(n){

        if(n>0) return n+arguments.callee(n-1);

        return 0;

     })(10);

     alert(fn)