位置: 编程技术 - 正文

理解 JavaScript Scoping & Hoisting(二)(理解的英文)

编辑:rootadmin

推荐整理分享理解 JavaScript Scoping & Hoisting(二)(理解的英文),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:理解的近义词,理解词语的方法有哪些,理解的英文,理解的意思,理解词语的方法有哪些,理解的意思,理解的英文,理解词语的方法有哪些,内容如对您有帮助,希望把文章链接给更多的朋友!

Scoping & Hoisting

上面这段代码在运行时会产生什么结果?

尽管对于有经验的程序员来说这只是小菜一碟,不过我还是顺着初学者常见的思路做一番描述:

1.创建了全局变量 a,定义其值为 .创建了函数 foo3.在 foo 的函数体内,if 语句将不会执行,因为 !a 会将变量 a 转变成布尔的假值,也就是 false4.跳过条件分支,alert 变量 a,最终的结果应该是输出 1

嗯,看起来无懈可击的推理啊,但让人惊讶的是:答案竟然是 2!为什么?

别着急,我会解释给你听。首先我要告诉你这不是什么错误,而是 JavaScript 语言解释器的一个(非官方的)特性,某人(Ben Cherry)把这个特性叫做:Hoisting(目前尚未有标准的翻译,比较常见的是提升)。

声明与定义

为了理解 Hoisting,我们先来看一个简单的情况:

var a = 1;

你是否想过,上面这句代码在运行的时候到底发生了什么? 你是否知道,就这句代码而言,“声明变量 a” 和 “定义变量 a”这两个说法哪一个才是正确的?&#;下例叫做 “声明变量”:

var a;

&#;下例叫做 “定义变量”:

var a = 1;

&#;声明:是指你声称某样东西的存在,比如一个变量或一个函数;但你没有说明这样东西到底是什么,仅仅是告诉解释器这样东西存在而已;&#;定义:是指你指明了某样东西的具体实现,比如一个变量的值是多少,一个函数的函数体是什么,确切的表达了这样东西的意义。

总结一下:

var a; // 这是声明a = 1; // 这是定义(赋值)var a = 1; // 合二为一:声明变量的存在并赋值给它

重点来了:当你以为你只做了一件事情的时候(var a = 1),实际上解释器把这件事情分解成了两个步骤,一个是声明(var a),另一个是定义(a = 1)。

这和 Hoisting 有何关系?

回到最开始的那个令人困惑的例子,我告诉你解释器是如何分析你的代码的:

如代码所示,在进入函数体后解释器声明了新的变量 a,而无论 if 语句的条件如何,都将为新的变量 a 赋值为 2。你若不相信可以在函数体外面 alert(a),然后再执行 foo() 对比一下结果就知道了。

理解 JavaScript Scoping & Hoisting(二)(理解的英文)

Scoping(作用域)

有人可能会问了:“为什么不是在 if 语句内声明变量 a?”

因为 JavaScript 没有块级作用域(Block Scoping),只有函数作用域(Function Scoping),所以说不是看见一对花括号 {} 就代表产生了新的作用域,和 C 不一样!

当解析器读到 if 语句的时候,它发现此处有一个变量声明和赋值,于是解析器会将其声明提升至当前作用域的顶部(这是默认行为,并且无法更改),这个行为就叫做 Hoisting。

OK,大家都懂了,你懂了吗……

懂了不代表就会用了,就拿最开始的例子来说,如果我就是想要 alert(a) 出那个 1 可咋整呢?

创建新的作用域

alert(a) 在执行的时候,会去寻找变量 a 的位置,它从当前作用域开始向上(或者说向外)一直查找到顶层作用域为止,若是找不到就报 undefined。

因为在 alert(a) 的同级作用域里,我们再次声明了本地变量 a,所以它报 2;所以我们可以把本地变量 a 的声明向下(或者说向内)移动,这样 alert(a) 就找不到它了。

记住:JavaScript 只有函数作用域!

你或许在无数的 JavaScript 书籍和文章里读到过:“请始终保持作用域内所有变量的声明放置在作用域的顶部”,现在你应该明白为什么有此一说了吧?因为这样可以避免 Hoisting 特性给你带来的困扰(我不是很情愿这么说,因为 Hoisting 本身并没有什么错),也可以很明确的告诉所有阅读代码的人(包括你自己)在当前作用域内有哪些变量可以访问。但是,变量声明的提升并非 Hoisting 的全部。在 JavaScript 中,有四种方式可以让命名进入到作用域中(按优先级):

1.语言定义的命名:比如 this 或者 arguments,它们在所有作用域内都有效且优先级最高,所以在任何地方你都不能把变量命名为 this 之类的,这样是没有意义的2.形式参数:函数定义时声明的形式参数会作为变量被 hoisting 至该函数的作用域内。所以形式参数是本地的,不是外部的或者全局的。当然你可以在执行函数的时候把外部变量传进来,但是传进来之后就是本地的了3.函数声明:函数体内部还可以声明函数,不过它们也都是本地的了4.变量声明:这个优先级其实还是最低的,不过它们也都是最常用的

另外,还记得之前我们讨论过 声明 和 定义 的区别吧?当时我并没有说为什么要理解这个区别,不过现在是时候了,记住:

Hosting 只提升了命名,没有提升定义

这一点和我们接下来要讲到的东西息息相关,请看:

函数声明与函数表达式的差别

先看两个例子:

同学,在了解了 Scoping & Hoisting 之后,你知道怎么解释这一切了吧?

在第一个例子里,函数 foo 是一个声明,既然是声明就会被提升(我特意包裹了一个外层作用域,因为全局作用域需要你的想象,不是那么直观,但是道理是一样的),所以在执行 foo() 之前,作用域就知道函数 foo 的存在了。这叫做函数声明(Function Declaration),函数声明会连通命名和函数体一起被提升至作用域顶部。

然而在第二个例子里,被提升的仅仅是变量名 foo,至于它的定义依然停留在原处。因此在执行 foo() 之前,作用域只知道 foo 的命名,不知道它到底是什么,所以执行会报错(通常会是:undefined is not a function)。这叫做函数表达式(Function Expression),函数表达式只有命名会被提升,定义的函数体则不会。

尾记:Ben Cherry 的原文解释的更加详细,只不过是英文而已。我这篇是借花献佛,主要是更浅显的解释给初学者听,若要看更多的示例,请移步原作,谢谢。

每天一篇javascript学习小结(属性定义方法) 定义(Definition).定义属性需要使用相应的函数,比如:Object.defineProperty(obj,"prop",propDesc)如果obj没有prop这个自身属性,则该函数的作用是给obj添加一个自身属性

跟我学习javascript的作用域与作用域链 作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理。今天这篇文章对JavaScript作用域和作用域链作简

跟我学习javascript的this关键字 本文仅就这一问题展开讨论,阅罢本文,读者若能正确回答JavaScript中的What'sthis问题,作为作者,我就会觉得花费这么多功夫,撰写这样一篇文章是值得

标签: 理解的英文

本文链接地址:https://www.jiuchutong.com/biancheng/385438.html 转载请保留说明!

上一篇:js立即执行函数: (function ( ){})( ) 与 (function ( ){}( )) 有什么区别?(js立即执行函数作用)

下一篇:每天一篇javascript学习小结(属性定义方法)(每天一篇小练笔30字)

  • 营业税金及附加包括哪些
  • 什么是免税合并
  • 土地使用权转让是什么意思
  • 出租房屋转为投资房屋
  • 火车票丢了怎么补打报销凭证
  • 机票行程单上没有日期怎么回事
  • 开票不确认收入可以吗
  • 车船税每年都要交吗标准多少
  • 装修公司一般纳税人税率是多少啊
  • 轿车被盗
  • 企业递延所得税费用的计算公式
  • 淘汰生产母猪处理销售收入的分录怎么处理?
  • 代交社保费会计账务处理
  • 购买饲料计入哪个科目?
  • 应付账款多付了
  • 外贸出口企业城市排名
  • 差额征税的差额怎么算
  • 二手车交易公司需要什么资质
  • 如何查询以前申诉进度
  • 客户忠诚度的表现行为有哪些
  • 技术合同 免税
  • 股权质押权如何实现
  • 电子税务局哪里打印发票
  • 购买方开具红字信息表
  • 卖护肤品赚钱吗
  • 文件夹如何更改图标
  • 调增应纳税所得额季度申报表怎么填
  • 计提房租费
  • win10任务栏快捷图标不见了
  • 认定科技型中小企业简单吗
  • igfxext.exe
  • PHP:preg_split()的用法_PCRE正则函数
  • 辅导期一般纳税人可以抵扣进项吗
  • 出差补贴是必须的吗
  • 发票已到货未到会计处理
  • bds.exe
  • 会计利润类科目是什么
  • 小型微利企业税收优惠2023
  • 资产负债表的资产方能够提供的信息包括
  • codeignitor
  • 你让他心动他让你心安
  • 定额发票新旧版区别
  • 员工离职后个税申报系统如何操作
  • 给股东分配股利
  • python中事件处理的方法
  • phpcms二次开发教程
  • 直接人工费和应付职工薪酬
  • 辅助生产车间工人工资计入
  • 所得税视同销售行为有哪些呢?
  • 企业所得税放入什么科目
  • 小规模纳税人不超过30万怎么做账
  • 合伙企业所得税征收方式
  • 现金流量表中支付的税费怎么填
  • centos执行sh
  • 年底计提坏账收回一部分怎么处理
  • 差额开票和全额开票
  • MSSQL 2008 自动备份数据库的设置方法
  • 国企注册资本实缴
  • 有限合伙企业中谨慎有限合伙人的应当
  • 支付技术研究开发费
  • 疫情期间减免的六大行业
  • 小微企业不用缴纳社保可以吗现在
  • 贸易公司的成本怎么做
  • 营业收入包括哪些内容?
  • 统计得到的一组数据有80个
  • xp系统安装惠普1010教程
  • Win10预览版桌面图标和任务栏不翼而飞怎么办?
  • 修改双系统的引导顺序
  • 怎么关闭windows更新提示
  • 安装最新的Google应用
  • spes监控原理
  • perl中sub
  • cmd读取d盘
  • shell脚本.sh
  • jQuery实现磁力图片跟随效果完整示例
  • js怎么学扎实
  • python list的操作
  • 税务上的工会经费是必须交的吗?
  • 江苏电子税务局官网登录入口
  • 增值税专用发票怎么开
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设