搜索
首页web前端js教程JavaScript欺骗词法的eval、with与catch及其性能问题

正常来说,执行期上下文的作用域链是不会改变的 

JavaScript中的词法作用域并不是一成不变的
(词法作用域/静态作用域: 作用域由书写代码时函数声明位置决定)
有几种机制是可以欺骗词法的
它们是with()、eval()还有try-catch语句的catch子句
其中with和eval我们不应该去使用(会产生很多问题)
欺骗词法的意思就是欺骗词法作用域
也就是说,它们在运行时改变了作用域链
下面我就来谈谈这些可以欺骗词法的机制

eval

eval()函数接受一个字符串作为参数,并且解析字符串生成代码

var a = 123;eval('console.log(a)');// 123

于是控制台打印了123
执行了eval函数之后
js引擎并不知道这段代码时动态插入的,并且修改了作用域链
引擎还会像往常一样查找作用域链
看下面的代码

var a = 1;function demo(){
    eval('var a = 2;');//欺骗词法
    console.log(a);// 2}
demo();

当eval函数执行时,在demo函数执行环境的最顶端作用域添加了变量a
这个局部环境中的a“遮蔽”了全局环境的a
最终导致程序打印2

eval()函数不仅可以修改它当前所处的作用域,甚至还可以修改全局作用域
无论怎样,它都可以在运行期修改词法作用域

ES5的严格模式对这个函数加了一些限制,我把上面的代码加上局部严格模式

var a = 1;function demo(){    'use strict';    eval('var a = 2;');
    console.log(a);// 1}
demo();

我们发现这回控制台打印了1
这是因为在严格模式下,eval()运行时拥有自己独立的词法作用域(省的它给执行环境的作用域链捣乱)
这样其中的声明就无法修改它所在的作用域了

这种可以动态产生代码的还有两个和它很像
定时器setTimeout()和setInterval()第一个参数可以是代码字符串
还有函数构造器new Function()的最后一个参数同样接受代码字符串
和eval()一样,不要使用这种用法,这会带来严重的性能问题,这个问题一会儿再说

with

另一个不建议使用的欺骗词法的语法就是这个with关键字
with通常用作重复引用某个对象的多个属性的快捷方式
好处是可以不需要重复的引用对象本身
比如我想重复使用console对象

console.log(1);console.info(2);console.warn(3);

使用with关键字

with(console){    log(1);    info(2);    warn(3);
}

打印

看起来with好像没什么问题,但是看下面

function demo(obj){
    with(obj){
        a = 5;
    }
}var obj1 = {a:1};var obj2 = {b:2};

demo(obj1);
console.log(obj1.a);// 5demo(obj2);
console.log(obj2.a);// undefinedconsole.log(a);//5 -->变量a居然泄漏到了全局环境

我们发现使用with关键字修改了obj1的a
但是它不仅没有在obj2上增加a,反而产生副作用泄露到了全局
这是因为with可以把一个对象处理为一个完全隔离的词法作用域(放到作用域链的最前面)
所以在它内部产生执行a = 5;
它会向下查找作用域链,但没有找到,于是在全局创建了一个a变量(没有var 的声明)

注意:虽然with产生了一个词法作用域,但是with内部的正常var声明不会被限制在这个块作用域中
也就是说声明在with外部的作用域
像这样

function demo(){
    var obj = {};    with(obj){        var b = 1;
        console.log(b); // 1
    }
    console.log(b); // 1}
demo();
console.log(b);// Uncaught ReferenceError: b is not defined

而且with关键字在ES5的严格模式干脆就不让用
如果你尝试使用你会看到这样的错误:

这里写图片描述

catch

除了eval与with之外,try-catch语句中的catch子句同样可以修改执行环境的作用域链
当try代码块内发生错误,执行流立即跳转到catch子句
随后把异常对象推入一个可变对象并且放到作用域链最前面,这和with很像
一旦catch子句执行完毕,作用域链就会恢复原样

但是和eval和with不同,try-catch还是相对有用,不用完全抛弃(虽然我没用过)

性能

欺骗词法会产生性能问题
js引擎在编译阶段会进行性能优化,很多优化依赖于能够根据代码词法进行静态分析
预先确定了变量和函数的定义位置,才能快速找到标识符
但是eval或with无法判断标识符位置(存在于代码执行过程中,无法静态分析)
也就是说:在eval和with面前,js引擎所有的优化没有任何意义(简直酷炫)
既然没意义,js引擎干脆就不优化了
这样就导致程序运行变慢了

对于with,它还有自己独特的性能问题…
产生了作用域,就会导致它所在的函数的所有局部变量处于第二个作用链对象
访问代价更高了

对于try-catch语句,如果我们想要使用,可以这样做

try{    ...}catch(e){
    handleError(e);
}

在catch语句中只执行了一段代码,委托给一个函数用于处理错误
这样没有局部变量的访问
作用域链的临时改变就不会影响性能

总结

总结一下重点

  • 词法作用域意味着作用域是书写代码时函数声明的位置来决定
    编译时词法分析阶段能知道所有标识符在哪里及如何声明

  • eval可以对代码字符串进行演算,借此在运行时修改了词法作用域

  • with通过将一个对象引用当作作用域来处理,借此在运行时创建了词法作用域

  • eval在严格模式下会产生独立词法作用域,无法修改所在作用域

  • with在严格模式下禁止使用

  • eval与with(还有catch)可以欺骗词法,在执行时修改作用域链

  • eval与with致使js引擎无法在编译阶段优化作用域查找(无法静态分析),导致程序变慢

说了这么多,就是要告诉大家不要使用with关键字和eval函数~( ̄0 ̄)/

 以上就是JavaScript欺骗词法的eval、with与catch及其性能问题的内容,更多相关内容请关注PHP中文网(www.php.cn)!


声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

如何使用Next.js(前端集成)构建多租户SaaS应用程序如何使用Next.js(前端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:22 AM

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript:探索网络语言的多功能性JavaScript:探索网络语言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的演变:当前的趋势和未来前景JavaScript的演变:当前的趋势和未来前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

神秘的JavaScript:它的作用以及为什么重要神秘的JavaScript:它的作用以及为什么重要Apr 09, 2025 am 12:07 AM

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

Python还是JavaScript更好?Python还是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。 1.Python以简洁语法和丰富库生态着称,适用于数据分析和Web开发。 2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

如何安装JavaScript?如何安装JavaScript?Apr 05, 2025 am 12:16 AM

JavaScript不需要安装,因为它已内置于现代浏览器中。你只需文本编辑器和浏览器即可开始使用。1)在浏览器环境中,通过标签嵌入HTML文件中运行。2)在Node.js环境中,下载并安装Node.js后,通过命令行运行JavaScript文件。

在Quartz中如何在任务开始前发送通知?在Quartz中如何在任务开始前发送通知?Apr 04, 2025 pm 09:24 PM

如何在Quartz中提前发送任务通知在使用Quartz定时器进行任务调度时,任务的执行时间是由cron表达式设定的。现�...

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。