这几次都是些的基础文章,可能好多人会说基础不太重要,做前端这么久,也没用到多少基础 (首先恭喜你,已经进提前进入了被优化名单)

下面我们来详细解答一下基础是什么。

let 知识, 基础 if (知识 === '房子') {基础 = '地基'
}
if (知识 === '大树') {基础 = '树根'
}
if (知识 === '天空') {基础 = '阶梯'console.log('基础 makes you up, up, up…… 直到你碰头')
}
………………

怎么样?认识到基础的重要性了吧,如果没有了基础,代码就好像无根之木,空中楼阁,虽然赏心悦目,但总是短暂的。

直到你真正领悟了底层是怎么运作的,你才能够真正做到 他强任他强,清风拂山岗;他横自他横,明月照大江。

扯远了,收~

回到我们的正题。今天带大家了解以下 JavaScript 中的作用域问题。请拭拭拭拭拭拭目以待。(自己 get 重点)。

先从最基础的开始讲起。

1.什么是作用域

作用域是什么这个问题,好多人都回答不好。请注意:通常来说,作用域就是限制一个变量在程序中的使用范围。

搜嘎,突然有一种 “同行十二年,不知木兰是女郎” 的赶脚。

1.1 全局和局部

了解了作用域的名字来由之后。我们来认识一下它。

JavaScript 中作用域的边界是以函数划分。有 全局局部 作用域之分。

  • 全局作用域:声明在全局的变量或者不使用var声明的变量在整个程序中都是可用的,所以叫全局作用域
  • 局部作用域:声明在函数体内的变量,在整个函数执行环境和其子函数内都是可用的,但是在函数外访问不到,所以叫局部作用域

小栗子 同学上场:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
</body>
</html>
<script>var global = "我是全局变量,全局都能看到我";global2 = "我也是全局变量,全局都能看到我";function getName() {var name = "我是局部变量,只能在getName函数内才能找到我"}
</script>

1.2 预解析和变量提升

看到标题的同学是不是会稍有一愣。预解析是什么玩意儿?变量提升又是啥?(知道答案的同学请配合这个无聊的作者一下,假装一愣神。)

咳咳~不忙,等本大神(经)来解释一下。

预解析是在程序执行之前,会进行一遍预检。查找当前作用域内由 functionvar 。并且每次更换作用域都会在此作用域中执行预解析

变量提升是指,在查找到由 functionvar 后,首先在当前作用域的顶端定义好并赋给默认值。var的默认值为 undefinedfunction的默认值为函数本身

注:

​ 像 var getName = function() {} 这种代码会被当做变量定义,而不会当做函数定义。

“让一下,让一下……” 远处小栗子携大量代码滚滚而来~~

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
</body>
</html>
<script>console.log(global) // undefinedconsole.log(getName) // function getName(){}var global = 1;function getName () {}
</script>

诶?怎么这样?我不是定义了global吗?怎么会输出 undefined 难道是javascript出现了bug?

不要多想,预解析和变量提升的过程中,并不会将变量赋值,而只是定义,等真正执行的时候才会赋值。修改一下代码,在global变量下方再次打印。

var global = 1;
console.log(global); // 1

解释:当执行到打印函数的时候,global已经被赋值为 1。此时已经在执行代码的阶段,而不是在预解析阶段。

先练练手:

猜想一下,下方程序如何输出。

console.log(a) // 1
var a = 1;
console.log(a) // 2
getName()
function getName () {console.log(a) // 3console.log(b) // 4a = 2;console.log(a) // 5var b = 3;console.log(b) // 6function b(){}
}

此时你的答案是什么呢?

针对上方代码,通过图解的方式看下预解析的执行过程。

ps:(上图画的太复杂,看完需要耐心)

1.3 var和function的优先级

细心地同学可能会发现一个问题,上面的代码,在getName函数中,我既定义了 b变量,也定义了 b函数。为什么在 console.log(b) // 4 的时候会输出 undefined

因为在预解析的过程中,会先查找 function 然后再查找 var 所以,function 会被 var 覆盖。这里我们会理解为 在预解析过程中,function的优先级高于var。高优先级的会被低优先级的覆盖 (是不是很绕?没关系,多想想,加深下理解)

2.作用域链

作用域链的执行我们在之前就讲过了,有没有人注意到?有没有?

好吧,没有人回答我,看来是没人注意到了。

就在练手代码中,getName()函数内,向上查找 a 变量的过程,那个就是作用域链的查找过程。

闲言少叙,上高清大图:

特别注意:作用域只能从下向上查找,不可逆向。(从函数外不能访问函数内的变量)

3. 从全局获取函数内部的变量

上面讲到,在函数外访问函数内的变量是访问不到的,如果我坚持要访问呢?(一般情况下,这种钻牛角尖的人都容易挨打)

好吧,既然你要访问,那也是有方法的,我们可以在函数内将变量返回出来,这样就可以访问到函数内的变量了。

多说无益,还是代码最实在:

console.log(getA()); // 通过这种方式,我们就可以访问到 a 变量。function getA() {var a = 1;return a;
}

发散一下思维,你还知道其他方式吗?

4. 块级作用域

在ES6到来的时候,javascript迎来一个全新的概念,-- 块级作用域。顾名思义,块级作用域可以让变量只在一块代码内生效。

举个栗子:

{var a = 1
}
console.log(a)

上述栗子中的代码会正常输出,但是下方的代码会抛出 a 变量未定义的错误a is not defined

{let a = 1;
}
console.log(a)

也就是说a变量只在花括号内生效,在花括号外是访问不到的。

可以声明块级作用域的方式有两种。letconst

目前为止,我们看到了三个定义变量的方式,接下来,让我们瞅瞅他们之间的不同。

4.1 var、let、const的异同

同: 都可以声明变量。

异:

var 存在局部作用域,可变量提升,声明的值可更改。

console.log(a)
var a = 1;
a = 2;
// 上述操作都可以

let 存在块级作用域,不可变量提升,声明的值可修改。(只可以先声明变量,然后再使用)

console.log(a) // 会报错,  a is not defined
let a = 1;
a = 2;

const 存在块级作用域,不可变量提升,声明的值本身不可修改(只可以先声明变量,然后再使用)

const a = 1;
a = 2; // 会报错,a不可修改// 下述情况可运行
const a = []
a[0] = 1;

注意:

  • const声明的叫做常量,不可以修改其本身,但如果声明的是复杂类型的对象,对象里的值是可修改的。

这里你会发现一个问题,三者的功能是逐步增强的。

4.2 TDZ介绍(暂时性死区)为什么let和const不能变量提升。

使用letconst声明的变量,在预解析的时候会将变量放入到一个暂时不可访问的区间中,此时访问变量会提示未定义错误,在给变量赋值后,将变量放入到正常的执行环境中。使变量可以正常访问。

console.log(a) // 此时的a在TDZ中
let a = 1;     // 将a从TDZ中移出来
console.log(a) // 此时可以正常访问a变量

相信你现在已经充满能量,打开你的代码,学会分析每一步的执行顺序吧。

range作用于对象global失败_彻底弄懂JavaScript作用域问题相关推荐

  1. java接口防抖_彻底弄懂节流和防抖

    节流和防抖 这两个东西,你肯定听过,就是两种优化浏览器性能的手段.相关文章你肯定也看过,如果还是不太清楚,没关系,看完这篇短文,相信你能轻松理解其中差别. 防抖(deounce) 我们先说防抖吧,这里 ...

  2. 方法range作用于对象worksheet时失败_VB.NET Excel操作类(获取工作簿列表和工作表列表及工作表对象)...

    效果展示 引用excel类 Imports Microsoft.Office.Interop Excel类代码开始 Public Class Cls_excel 返回Excel对象 ''' ''' 返 ...

  3. python from. import失败_彻底搞懂Python 中的 import 与 from import

    以下文章来源&作者:青南(谢乾坤) 摄影:产品经理:kingname 的第一套乐高 你好,我是谢乾坤,前网易高级数据挖掘工程师.现任微软最有价值专家(Python 方向),有6年 Python ...

  4. 关于python函数对变量的作用、错误的是_关于python变量的作用域问题

    有这样一个函数: def outside(): x=[] print(id(x)) def inside(): print(id(x)) x[:]=[1,2,3] print(id(x)) insid ...

  5. 离线缓存占内存吗_彻底弄懂浏览器缓存策略

    浏览器缓存策略对于前端开发同学来说不陌生,大家都有一定的了解,但如果没有系统的归纳总结,可能三言两语很难说明白,甚至说错,尤其在面试过程中感触颇深,很多候选人对这类基础知识竟然都是一知半解,说出几个概 ...

  6. $.ligerdialog.open中确定按钮加事件_彻底搞懂JavaScript中的this指向问题

    JavaScript中的this是让很多开发者头疼的地方,而this关键字又是一个非常重要的语法点.毫不夸张地说,不理解它的含义,大部分开发任务都无法完成. 想要理解this,你可以先记住以下两点: ...

  7. stringbuilder调用tostring常量池_彻底弄懂java中的常量池

    作者:tracy_666链接:https://www.jianshu.com/p/55f65dac1b4b JVM常量池主要分为Class文件常量池.运行时常量池,全局字符串常量池,以及基本类型包装类 ...

  8. c++ unicode转换中文_彻底弄懂UTF-8、Unicode、宽字符、locale

    结论 宽字符类型wchar_t locale 为什么需要宽字符类型 多字节字符串和宽字符串相互转换 最近使用到了wchar_t类型,所以准备详细探究下,没想到水还挺深,网上的资料大多都是复制粘贴,只有 ...

  9. future.cancel不能关闭线程_彻底弄懂线程池-newFixedThreadPool实现线程池

    public class ExecutorServiceTest { public static void main(String[] args) throws IOException, Interr ...

最新文章

  1. Python爬虫之诗歌接龙
  2. python微型web框架flask介绍
  3. CentOS7下zip解压和unzip压缩文件
  4. runtimeexception异常_应用系统的异常管理-持续更新
  5. 【C/C++多线程编程之七】pthread信号量
  6. 开源导入导出库Magicodes.IE 多sheet导入教程
  7. 数据库MySQL/mariadb知识点——数据类型
  8. 用了这么多年的 Java 泛型,你对它到底有多了解?
  9. git clone 某次提交前代码_git提交代码常用命令
  10. c# 用正则表达式获取开始和结束字符串中间的值
  11. python 拼音识别_Python_语音合成
  12. WLAN 无线网络 02 - 频率、信道、编码、调制
  13. MSSQL有关时间函数知识(转)
  14. 《上海悠悠接口自动化平台》-5.测试计划与定时任务
  15. tf卡无法格式化怎么修复?解决方法分享
  16. IDEA如何从断点里获取对象所有数据(数据量很大且不好Ctrl+C)
  17. 生物特征识别门禁系统分类和基本概念
  18. 前端笔记1(选择器,动态增添/修改页面元素)
  19. 深入浅出WMS之入库流程解析
  20. 云里黑白21——win10 企业版更新系统后开始菜单左键点不出来

热门文章

  1. python3.4安装matplotlib_在python3.7下怎么安装matplotlib
  2. java更新新的知识要怎么知道_晟司小蒙告诉你,Java技术知识点,不定时更新!!!...
  3. 界面上下固定_【技术浅析】三通道机床自动上下料控制方法应用
  4. python环境搭建什么意思_如何搭建Python环境
  5. java 创建文件夹的方法_java中创建文件夹的方法
  6. java 泛型 擦除_Java泛型和类型擦除
  7. newman执行测试_postman+newman+Jenkins之API全自动化测试(MAC)
  8. 支付系统中订单redis防重的使用
  9. 持续集成框架,自动部署服务搭建jenkins+maven+svn(git)+shell
  10. 操作系统之文件管理:9、磁盘的结构与磁盘调度算法(先来先服务FCFS、最短寻找时间优先SSTF、扫描算法SCAN、循环扫描算法C-SCAN、LOOK调度算法、C-LOOK调度算法)