【每日积累】javascript 一文弄懂eval

eval 动态化执行语句

概述

eval方法是javascript的全局方法,能够执行含有javascript代码的字符串,虽然eval方法带来强大的动态执行功能,但考虑其负面影响,建议少用,在特殊情况下可以使用eval方法动态改变代码的执行作用域来达到代码的灵活性

动态值,表达式和语句

  console.log(typeof eval('true')) // boolean
  console.log(typeof eval("'9'")) // string
  console.log(typeof eval('8')) // number

注意点:

  • 如果参数code 含有一个表达式,则计算该表达式并返回该计算值
    console.log(eval('1+1')); // 2
  • 如果参数code 含有一个或者多个javascript语句,则eval方法将执行这些语句
    console.log(eval('1+1')); // 2
    console.log(eval('8'))  // 单值表达式
    console.log(eval('8;')) // 单值语句
   //虽然它们语义不一样,但还是按照js的词法结构在解释器进行解析
  • 为了预防不可预知的错用,同时考虑到实现效率的问题。在ESv3 标准中,给eval加了禁制,不能将eval赋值给另一个属性,然后在代码里面灵活调用和禁止用户覆盖eval属性
   // es3 中
   let e = eval;
   console.log(e('8')) //  Evalerror 异常
   // 目前
   let e = eval;
   console.log(e('8+9')); // 17
  • 如果最后一个语句有返回值,则eval则返回这个值
  • 如果参数code 没有返回任何值,则eval返回undefined
    在js中,除了空语句和命令语句之外,一般语句都会有返回值,返回值由执行最后一个子语句或表达式的值决定
    let s = "for (let index = 0; index < 50; index++) { console.log(index);}"

    // 上面语句会执行 依次打印对应的index 0-49
    console.log(eval(s)) // undefined 说明eval总会将代码执行的值进行返回,如果没有就返回undefined
    // 
  • 如果参数code抛出异常,则eval会将异常传递给调用者。
 try {
    let s = "for (let index = 0; index < 50; index++) { ;}"
    console.log(eval(s)) // undefined
   } catch (error) {
     console.log(error.message); // 返回错误信息
   }
  • 大部分字符串参数的javascript函数和方法都会接受其他的参数,在继续操作之前把参数强制转换成字符串,但eval方法比较特殊,code参数如果不是原始的字符串,则eval不做任何处理并返回原始值。当传递给eval原始字符串值时,不要传递字符串对象。
    例如:
  let s = new String('1+2') // string 对象
  console.log(eval(s)); // 返回字符串“1+2”
  let s1 = "1+2"; // 原始的直接量
  console.log(eval(s1)) // 3
  console.log(typeof eval(s1)) // 返回为number类型

对象和函数直接量的歧义问题

  • eval方法能够很轻松地执行普通表达式或者语句,并返回对应的返回值,而在计算下方code则会返回异常产生歧义
    var o = '{user:"c88",pass:"123456"}';
    console.log(eval(o)) // thorw error
  • 或许你会产生上面表达式是否有错误,其实并没有,如果我们只定义一个属性却是正确的,则就表明对象产生对应的歧义问题!
    var b = '{user:"c88"}';
    console.log(eval(b)) // c88

    // 我们平时生成obj对象是 obj = { age : 12 , str:'123' } 
    //key 必须都是字符串,这是正确对象字面量的解析,产生歧义部分的问题:

上述产生歧义是复合语句和冒号导致 为了避免这种歧义采用下方code:

  var o = '({user:"c88",pass:"123456"})';
  console.log(eval(o)) //{user: 'c88', pass: '123456'}
  • function 也属于一种对象的表达形式,所以要通过function来进行处理字面量也需要避免歧义
    var o = "(function(){ return 8 })()"  console.log(8)
    or
    var o = "(function(){return 8}())" console.log(8)
    or
    var o = "function(){return 8}"
    console.log(eval("("+o+"())")) // 个人感觉不怎么推荐。
  • 对于数组对象,则不需要考虑上诉情况可以直接进行使用。
    var o = '["123","7777"][0]' 
    console.log(o) // 123

eval全局执行域及其兼容

  • 关于eval全局执行域是在javascript环境中,而javascript代码又必须在一定的环境进行运行,如全局域和局部域,这里的执行域我个人理解为特定的环境,貌似任何都离不开宿主这个词。对于被动态执行的code来说,这个问题就较为复杂,比如eval将在全局域中执行还是局部域之行。如下code example:
    var n  = 1; // global 
    function f(){
        var n= 3;
        eval('n=5') // local 
        // 如果想覆盖全局变量
        window.eval('n=5') //  则下方全局就打印 5
        console.log(n) // 5
    }
    f();
    console.log(n) //  1

eval当前执行域

  • 看上述例子可以看到,eval在全局执行的时候只会影响同名声明的变量,在函数里面声明只会影响当前作用域的同名变量,外部和内部域是隔离开来的!
    eval("var n = 1");
    function f(){
         eval("var n = 2");
         console.log(n) //2
    }
    f();
    console.log(n) //1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值