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

JavaScript欺骗词法的eval、with与catch及其性能问题

Feb 28, 2017 pm 02:58 PM

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

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

热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无尽的。

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

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

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何使用WebSocket和JavaScript实现在线语音识别系统 如何使用WebSocket和JavaScript实现在线语音识别系统 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript实现在线语音识别系统引言:随着科技的不断发展,语音识别技术已经成为了人工智能领域的重要组成部分。而基于WebSocket和JavaScript实现的在线语音识别系统,具备了低延迟、实时性和跨平台的特点,成为了一种被广泛应用的解决方案。本文将介绍如何使用WebSocket和JavaScript来实现在线语音识别系

WebSocket与JavaScript:实现实时监控系统的关键技术 WebSocket与JavaScript:实现实时监控系统的关键技术 Dec 17, 2023 pm 05:30 PM

WebSocket与JavaScript:实现实时监控系统的关键技术引言:随着互联网技术的快速发展,实时监控系统在各个领域中得到了广泛的应用。而实现实时监控的关键技术之一就是WebSocket与JavaScript的结合使用。本文将介绍WebSocket与JavaScript在实时监控系统中的应用,并给出代码示例,详细解释其实现原理。一、WebSocket技

如何利用JavaScript和WebSocket实现实时在线点餐系统 如何利用JavaScript和WebSocket实现实时在线点餐系统 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket实现实时在线点餐系统介绍:随着互联网的普及和技术的进步,越来越多的餐厅开始提供在线点餐服务。为了实现实时在线点餐系统,我们可以利用JavaScript和WebSocket技术。WebSocket是一种基于TCP协议的全双工通信协议,可以实现客户端与服务器的实时双向通信。在实时在线点餐系统中,当用户选择菜品并下单

Vue开发注意事项:避免常见的内存占用和性能问题 Vue开发注意事项:避免常见的内存占用和性能问题 Nov 22, 2023 pm 02:38 PM

随着Vue的使用越来越广泛,Vue的开发者们也需要考虑如何优化Vue应用程序的性能和内存占用。本文将讨论Vue开发的一些注意事项,帮助开发者避免常见的内存占用和性能问题。避免无限循环当一个组件不断地更新自己的状态,或者一个组件不断地渲染它自己的子组件时,可能会导致无限循环。这种情况下,Vue将会耗尽内存并且使应用程序非常缓慢。为了避免这种情况,Vue提供了一

如何使用WebSocket和JavaScript实现在线预约系统 如何使用WebSocket和JavaScript实现在线预约系统 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript实现在线预约系统在当今数字化的时代,越来越多的业务和服务都需要提供在线预约功能。而实现一个高效、实时的在线预约系统是至关重要的。本文将介绍如何使用WebSocket和JavaScript来实现一个在线预约系统,并提供具体的代码示例。一、什么是WebSocketWebSocket是一种在单个TCP连接上进行全双工

JavaScript和WebSocket:打造高效的实时天气预报系统 JavaScript和WebSocket:打造高效的实时天气预报系统 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的实时天气预报系统引言:如今,天气预报的准确性对于日常生活以及决策制定具有重要意义。随着技术的发展,我们可以通过实时获取天气数据来提供更准确可靠的天气预报。在本文中,我们将学习如何使用JavaScript和WebSocket技术,来构建一个高效的实时天气预报系统。本文将通过具体的代码示例来展示实现的过程。We

简易JavaScript教程:获取HTTP状态码的方法 简易JavaScript教程:获取HTTP状态码的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教程:如何获取HTTP状态码,需要具体代码示例前言:在Web开发中,经常会涉及到与服务器进行数据交互的场景。在与服务器进行通信时,我们经常需要获取返回的HTTP状态码来判断操作是否成功,根据不同的状态码来进行相应的处理。本篇文章将教你如何使用JavaScript获取HTTP状态码,并提供一些实用的代码示例。使用XMLHttpRequest

javascript中如何使用insertBefore javascript中如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用于在DOM树中插入一个新的节点。这个方法需要两个参数:要插入的新节点和参考节点(即新节点将要被插入的位置的节点)。

See all articles