0

0

JavaScript打破作用域的牢笼

黄舟

黄舟

发布时间:2017-02-27 14:25:11

|

1326人浏览过

|

来源于php中文网

原创

JavaScript打破作用域的牢笼

javascript作为一种松散型语言,有着很多令人瞠目结舌的特性(往往是一些令人捉摸不透的奇怪特性),本文我们将介绍如何使用javascript的一些特性来打破常规编程语言“作用域的牢笼”。

1.JavaScript声明提升

很多人应该知道,js有变量声明提升、函数声明提升的特性。不管你之前是否了解,看下面的代码运行的结果是否符合你的预期:

var a=123;
//可以运行
abc();
//报错:def is not a function
def();
function abc(){
    //undefined
    console.log(a);
    var a="hello";
    //hello
    console.log(a);
}
var def=function(){
    console.log("def");
}

实际上js在运行时会对代码进行两轮扫描。第一轮,初始化变量;第二轮,执行代码。第二轮执行代码很好理解,不过第一轮过程比较模糊。具体来说,第一轮会做下面三件事:

(1)声明并初始化函数参数

(2)声明局部变量,包括将匿名函数赋给一个局部变量,但并不初始化他们

立即学习Java免费学习笔记(深入)”;

(3)声明并初始化函数

明白了这些理论基础之后,上面那段代码在第一轮扫描之后实际上被js编译器“翻译”成了如下代码:

var a;
a=123;
function abc(){
    //局部变量,将会取代外部的a
    var a;
    //undefined
    console.log(a);
    var a="hello";
    //hello
    console.log(a);
}
var def;
//可以运行
abc();
//报错:def is not a function
def();
var def=function(){
    console.log("def");
}

现在再来看注释里展示的程序运行时输出,是不是觉得顺理成章了。这就是js声明提升在当中起到的作用。

知道了js声明提升的作用机制之后,我们来看下面这段代码:

var obj={};
function start(){
    //undefined
    //This is obj.a
    console.log(obj.a);
    //undefined
    //This is a
    console.log(a);
    //成功输出
    //成功输出
    console.log("页面执行完成");
}

start();
var a="This is a";
obj.a="This is obj.a";
start();

上述注释第一行表示第一次执行start()方法时的输出,第二行表示第二次执行start()方法的输出。可以看到,由于js声明提升的存在,两次执行start()方法都没有报错。下面来看对这个例子进行小小的修改:

启山智软物流配送系统
启山智软物流配送系统

启山智软物流配送是基于Spring Cloud 和 Vue.js的JAVA物流配送系统。包含总控制后台 、城市合伙人(商家pc端)、 区域团长后台 、用户端小程序 、手机H5等多个操作模块。为响应用户需求我们新增了后台自定义装修组件模块,使页面更加美观,操作更加灵活简便。淘宝商品CSV一键导入,提升用户使用感。还有与众不同的管理台侧边栏设计,打破传统管理台样式。 另有公众号接龙、引导页上传、区域团

下载
var obj={};
function start(){
    //undefined
    //This is obj.a
    console.log(obj.a);
    //报错
    //This is a
    console.log(a);
    //因为上一行的报错导致后续代码不执行
    //成功输出
    console.log("页面执行完成");
}

start();
/*---------------另一个js文件----------------*/
var a="This is a";
obj.a="This is obj.a";
start();

此时,由于将a变量的声明推迟到另一个js文件中,导致第一次执行的时候console.log(a)代码报错,从而后续的js代码不再执行。不过第二次执行start()方法仍然正常执行。这就是为什么几乎所有地方都推荐大家使用“js命名空间”来部署不同的js文件。下面我们用一段代码来总结声明提升+命名空间如何巧妙的“打破作用于的牢笼”:

/*-----------------第一个js文件----------------*/
var App={};
App.first=(function(){
    function a(){
        App.second.b();
    }

    return {
        a:a
    };
})();

/*-----------------另一个js文件----------------*/
App.second=(function(){
    function b(){
        console.log("This is second.b");
    }

    return {
        b:b
    };
})();

//程序起点,输出This is second.b
App.first.a();

这段程序将不会有任何报错,我们可以在第一个js文件内访问任何App命名空间后续的属性,只要程序起点在所有必要的赋值工作之后执行,就不会有任何问题。这个例子成功的展示了如何通过合理的设计代码结构来充分利用js语言的动态特性。

看到这里读者可能会觉得这文章有点标题党,上面的技巧只是通过代码布局来做出的一种“假象”:看上去前面的代码在访问不存在的属性,实际上真正执行时的顺序都是合理正确的。那下面本文将介绍真正的“跨作用于访问”技巧。

2.js执行时代码

大家都知道js语言有一个“eval()”方法,他就是一个典型的“真正打破作用于牢笼”的方法。看下面这段代码:

(function(){
    var code="console.log(a)";
    //This is a bird
    test(code);

    function test(code){
        console.log=function(arg){
            console.info("This is a "+arg);
        };
        var a="bird";
        eval(code);
    }
})();

看了这段代码,相信很多人可能会不禁感叹js的奇葩:“这也能行?!”。是的。test()方法由于声明提升的机制,因此能够被提前调用,正常执行。test()方法接受一个code参数,在test()方法内部我们重写了console.log方法,修改了一下输出格式,并且在test内部定义了一个私有变量var a=”bird”。在test方法最后我们使用eval来动态执行code的代码,打印结果非常神奇:浏览器使用了我们重写的console.log方法打印出了test方法内部的私有变量a。这是完全的作用域隔离。

类似的方法在js中还有很多,例如:eval(),setTimeout(),setInterval()以及部分原生对象的构造方法。但是有两点要提醒:

(1)这种方式会大大降低程序的执行效率。大家都知道js本身是解释性语言,其本身性能已经比编译型语言慢了好多个级别。在这基础之上如果我们再使用eval这样的方法去“再编译”一段字符串代码,程序的性能将会慢很多。

(2)使用这种方式编程会剧增代码的复杂度,分分钟你就会看不懂自己写的代码。本文介绍这种方法是希望能让读者全面的了解js语法特性从而能更好的修正、排错。本文完全不推荐在生产级别的代码中使用第二种方式。

 以上就是JavaScript打破作用域的牢笼的内容,更多相关内容请关注PHP中文网(www.php.cn)!

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
clawdbot ai使用教程 保姆级clawdbot部署安装手册
clawdbot ai使用教程 保姆级clawdbot部署安装手册

Clawdbot是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

14

2026.01.29

clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址
clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址

clawdbot龙虾机器人官网入口:https://clawd.bot/,clawdbot ai是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

7

2026.01.29

Golang 网络安全与加密实战
Golang 网络安全与加密实战

本专题系统讲解 Golang 在网络安全与加密技术中的应用,包括对称加密与非对称加密(AES、RSA)、哈希与数字签名、JWT身份认证、SSL/TLS 安全通信、常见网络攻击防范(如SQL注入、XSS、CSRF)及其防护措施。通过实战案例,帮助学习者掌握 如何使用 Go 语言保障网络通信的安全性,保护用户数据与隐私。

8

2026.01.29

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

545

2026.01.28

包子漫画在线官方入口大全
包子漫画在线官方入口大全

本合集汇总了包子漫画2026最新官方在线观看入口,涵盖备用域名、正版无广告链接及多端适配地址,助你畅享12700+高清漫画资源。阅读专题下面的文章了解更多详细内容。

191

2026.01.28

ao3中文版官网地址大全
ao3中文版官网地址大全

AO3最新中文版官网入口合集,汇总2026年主站及国内优化镜像链接,支持简体中文界面、无广告阅读与多设备同步。阅读专题下面的文章了解更多详细内容。

328

2026.01.28

php怎么写接口教程
php怎么写接口教程

本合集涵盖PHP接口开发基础、RESTful API设计、数据交互与安全处理等实用教程,助你快速掌握PHP接口编写技巧。阅读专题下面的文章了解更多详细内容。

11

2026.01.28

php中文乱码如何解决
php中文乱码如何解决

本文整理了php中文乱码如何解决及解决方法,阅读节专题下面的文章了解更多详细内容。

16

2026.01.28

Java 消息队列与异步架构实战
Java 消息队列与异步架构实战

本专题系统讲解 Java 在消息队列与异步系统架构中的核心应用,涵盖消息队列基本原理、Kafka 与 RabbitMQ 的使用场景对比、生产者与消费者模型、消息可靠性与顺序性保障、重复消费与幂等处理,以及在高并发系统中的异步解耦设计。通过实战案例,帮助学习者掌握 使用 Java 构建高吞吐、高可靠异步消息系统的完整思路。

10

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.3万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.5万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号