不建议使用的with和永远不要使用的eval

一、with语句 扩展一个语句的作用域链。

JavaScript查找某个未使用命名空间的变量时,会通过作用域链来查找,作用域链是跟执行代码的context或者包含这个变量的函数有关。'with'语句将某个对象添加到作用域链的顶部,如果在statement中有某个未使用命名空间的变量,跟作用域链中的某个属性同名,则这个变量将指向这个属性值。如果沒有同名的属性,则将拋出异常。

不推荐使用with,在 ECMAScript 5 严格模式中该标签已被禁止。推荐的替代方案是声明一个临时变量来承载你所需要的属性。

 比如:下面代码完全可以用var PI = Math.PI来代替

        var a, x, y;
        var r = 10;

        with(Math) {
            a = PI * r * r;
            x = r * cos(PI);
            y = r * sin(PI / 2);
        }

(1)性能方面的利弊

利:with语句可以在不造成性能损失的情況下,减少变量的长度。其造成的附加计算量很少。使用'with'可以减少不必要的指针路径解析运算。需要注意的是,很多情況下,也可以不使用with语句,而是使用一个临时变量来保存指针,来达到同样的效果。

弊:with语句使得程序在查找变量值时,都是先在指定的对象中查找。所以那些本来不是这个对象的属性的变量,查找起来将会很慢。如果是在对性能要求较高的场合,'with'下面的statement语句中的变量,只应该包含这个指定对象的属性。

(2)语义不明的弊端

弊端:with语句使得代码不易阅读,同时使得JavaScript编译器难以在作用域链上查找某个变量,难以决定应该在哪个对象上来取值。请看下面的例子:

function f(x, o) {
  with (o)
    print(x);
}

f被调用时,x有可能能取到值,也可能是undefined,如果能取到, 有可能是在o上取的值,也可能是函数的第一个参数x的值(如果o中没有这个属性的话)。如果你忘记在作为第二个参数的对象o中定义x这个属性,程序并不会报错,只是取到另一个值而已。

弊端:使用with语句的代码,无法向前兼容,特別是在使用一些原生数据类型的时候。看下面的例子:

function f(foo, values) {
    with (foo) {
        console.log(values)
    }
}

如果是在ECMAScript 5环境调用f([1,2,3], obj),则with语句中变量values将指向函数的第二个参数values。但是,ECMAScript 6标准给Array.prototype添加了一个新属性values,所有数组实例将继承这个属性。所以在ECMAScript 6环境中,with语句中变量values将指向[1,2,3].values

with示例

1、with 语句用于设置代码在特定对象中的作用域。

例如:

        var obj = {
            name: "obj"
        }
        var name = "window";
        function func(){
            var name = "func";
            with(obj){
                console.log(name);
            }
        }
        func();

打印的结果:obj;

实际上:对于with语句而言,会将指定的对象添加到作用域链中。

        var obj = {
            // name: "obj"
        }
        var name = "window";
        function func(){
            var name = "func";
            with(obj){
                console.log(name);
            }
        }
        func();

打印的结果:func;

2、理解with的作用,理解函数作用域链和this对象

例如:

({
x: 10,
foo: function () {
    function bar() {
        console.log(x);
        console.log(y);
        console.log(this.x);
    }
    with (this) {
        var x = 20;
        var y = 30;
        bar.call(this);
    }
}
}).foo();

分析:

with的特点:(请完全理解下面的with特点)

作用域链的顶部添加with传入的对象,即:with内先查找和操作该对象的属性,如果该对象没有找到,再往作用域链的下一级查找,然后操作操作。obj作用域——>函数1——>函数2——>...——>window全局作用域)
问题中,变量声明提示和函数声明提升后的实际代码是:

({
x: 10,
foo: function () {
    var x;//默认undefined,等会分析要用到
    var y;//默认undefined
    function bar() {
        console.log(x);
        console.log(y);
        console.log(this.x);
    }
    with (this) {
        x = 20;
        y = 30;
        bar.call(this);
    }
}
}).foo();

var x; x变量的默认值undefined;
var y;y变量的默认值undefined;
等会分析会用到

当代码走到with中时,this是外面的大对象。
(1)x =20
根据with的特点(上面提到的),先在this大对象中找x属性(对象中叫属性,函数叫变量),巧了,this大对象有x:10,将值改为20;
(2)y =30
同样的,在this大对象中找y属性,没有!再去foo函数中y变量,有!设置y为30;
(3)bar.call(this)
大家要注意:call apply bind(ES5)都是只改变this指向,this指向只与this对象相关的操作有关。与函数变量没有一点关系!!!

执行bar函数,call修改this指向,指向大对象。

bar函数执行
(1)打印变量x。bar函数中没有变量x,往上面的作用域找,foo函数中有变量x,x的值是undefined。(with改变的x是指大对象的x属性)
(2)打印变量y。bar函数没有变量y,往上找,foo函数中有变量y,值为30。(with语句改变y的时候,先去大对象中找y属性,没有,再去foo函数中找到y变量,并将其修改为30)
(3)打印this.x。打印大对象的x属性,值为20。

所以结果:

变量x:undefined
变量y:30
this.x:20

 

二、eval()

eval() 函数会将传入的字符串当做 JavaScript 代码进行执行。如果 eval() 的参数不是字符串, eval() 会将参数原封不动地返回。

性能不好,运行速度慢,甚至容易被攻击。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值