首页 > 其他分享 >[JS] 动态执行JS与修改词法作用域

[JS] 动态执行JS与修改词法作用域

时间:2024-06-17 13:32:18浏览次数:17  
标签:作用域 JS 词法 eval foo 标识符

相关可行的操作

  1. eval: 同步执行,当前作用域;
  2. setTimeout: 异步执行,全局作用域;

第1个参数可以传入函数对象,也可以传入字符串,即要执行的代码。

  1. script: 同步执行,全局作用域;

创建script标签,并设置innerHTML为要执行的代码。

  1. Function: 同步执行,全局作用域。

Function构造函数可以传入字符串,生成一个函数对象。


对词法作用域的影响

eval

eval可以通过动态地执行JS代码从而修改(欺骗)当前的词法作用域,观察如下代码:

function foo(str, a){
    eval(str);
    console.log(a, b);
}
var b = 2;
foo("var b=3;", 1); // 1, 3

在函数中,执行eval(..)var b=3;带入该词法作用域,导致console.log(..)中对b的右值引用找到的是3,而不会查询到外部的b=2

在默认情况下,eval会对所处的词法作用域进行修改。
严格模式下,eval在运行时有其自己的词法作用域,即其动态执行的JS声明语句不会影响到eval语句所处的词法作用域。

function foo(str){
    "use strict";
    eval(str);
    console.log(a); // ReferenceError: a is not defined
}
foo("var a = 2;");

with

除了eval另外可以修改词法作用域的语法是with关键字。

function foo(obj){
    with(obj){
        a = 2;
    }
}

var o1 = {a: 3};
var o2 = {b: 3};

foo(o1);
console.log(o1.a);  // 2
foo(o2);
console.log(o2.a); // undefined
console.log(a); // 2 (a被泄露到全局作用域了)

with接受一个对象,并将这个对象处理为一个完全隔离的词法作用域,这个对象的属性会被处理为定义在这个作用域内的词法标识符。
所以当o1传递给with时,with声明的作用域是o1,包含了同o1.a对应的标识符a,这个左值引用可以找到目标,并成功完成赋值操作。
o2传递给with时,with声明的词法作用域会包含同o2.b对应的标识符b,但是没有标识符a,此时赋值操作会进行LHS标识符查询,向外层作用域查找。
由于在o2的作用域、foo的函数作用域、全局作用域都没有找到标识符a,因此当a = 2执行时,会在全局作用域自动创建一个全局变量(如果是严格模式则不会)。

性能问题

JS引擎会在编译阶段进行性能优化,其中部分优化依赖于根据代码的词法进行静态分析,并预先确定所有变量和函数的定义位置,才能在执行过程中快速找到标识符。
evalwith这种可能动态更改词法作用域的操作会导致JS引擎无法在词法分析阶段明确标识符的位置,因此所有优化可能都是无意义的,甚至JS引擎可能在读取代码中使用了evalwith,就放弃优化了。
因此,在开发中应该避免使用evalwith

引用

[1] Scope and Closures, Kyle Simpson著(O'Reilly, 2014) 978-1-491-33558-8。

标签:作用域,JS,词法,eval,foo,标识符
From: https://www.cnblogs.com/feixianxing/p/18252203/dynamically-execute-javascript-and-scope

相关文章

  • js基础文档
    数据类型数据分为基本数据类型(String,Number,Boolean,Null,Undefined,Symbol)和对象数据类型。基本数据类型的特点:直接存储在栈(stack)中的数据引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里引用数据类型在栈中存储了指针,该指针指向堆中该实体的起......
  • 基于Vue+Nodejs实现医药商城销售系统
    作者主页:编程指南针作者简介:Java领域优质创作者、CSDN博客专家、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师主要内容:Java项目、Python项目、前端项目、人工智能与大数据、简历模板、学习资料、面试题库、技术互......
  • 获取three.js两点之间的控制点
    首先有两个点: constv0=newTHREE.Vector3(item.x,item.y,item.z);constv3=newTHREE.Vector3(item.target.x,item.target.y,item.target.z);如果想要获取中间点的控制线直接调用方法 getBezierPoint(v0,v3);getBezierPoint(v0,v3){//获取两点的控制点......
  • JS数组常用方法总结,含ES6新方法,附示例代码
    ......
  • JS逆向入门
    C级通关第一题打开页面https://www.aqistudy.cn/实现接口https://www.aqistudy.cn/apinew/aqistudyapi.php的正常请求并获取明文响应分析开着F12进页面遇到无限debugger一个neverpausehere下去关闭所有断点Activatebreakpoint(Ctrl+F8),随便逛逛网站找找目标接口......
  • js实现实现九宫格乱序抽奖
    我们以前写的九宫格抽奖,都是顺时针按照顺序进行旋转抽奖,今天给大家分享一下乱序,就是不按照一定顺序的。用户的具体步骤:用户点击开始抽奖时,奖项开始随机闪,闪到一定次数后停止并且进行抽奖成功提示;这个闪到一定的次数,次数是随机的;就是当我们点击按钮时生成一个随机数(就相当于是......
  • 要将URL参数转换为JSON对象,可以使用以下函数:
    要将URL参数转换为JSON对象,可以使用以下函数:javascriptfunctiongetQueryParams(url){//使用正则表达式提取URL参数constparamsString=url.split('?')[1];if(!paramsString){return{};}//将参数字符串分割成数组,并解析键值对constparams=......
  • 【图像隐写】基于Jsteg算法实现JPEG图像信息隐藏,可设置DCT系数 嵌入率附Matlab代码
     ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,代码获取、论文复现及科研仿真合作可私信。......
  • 【PL理论】(24) C- 语言:有块的作用域 | 更新的语法 | 新的语义域 | 环境 vs. 内存
    ......
  • 【three.js案例一】智慧星球
    直接附上源码:import*asTHREEfrom'three';import{OrbitControls}from'three/addons/controls/OrbitControls.js';//场景constscene=newTHREE.Scene();constgeometry=newTHREE.SphereGeometry(50,32,16);console.log('.postion�......