当前位置: 首页 > article >正文

JS-变量提升与暂时性死区概念

变量提升(Hoisting)

变量提升(Hoisting)被认为是, Javascript中执行上下文 (特别是创建和执行阶段)工作方式的一种认识。在 ECMAScript® 2015 Language Specification 之前的JavaScript文档中找不到变量提升(Hoisting)这个词。例如,从概念的字面意义上说,“变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,但这么说并不准确。实际上变量和函数声明在代码里的位置是不会动的,而是在编译阶段被放入内存中。

变量声明提升

JavaScript 只会提升声明,不会提升其初始化。如果一个变量先被使用再被声明和赋值的话,使用时的值是 undefined。参见例子:

console.log(num); // Returns undefined
var num;
num = 6;

变量num提升后代码相当于:

var num;
console.log(num); // Returns undefined
num = 6;

如果你先赋值、再使用、最后声明该变量,使用时能获取到所赋的值

num = 6;
console.log(num); // returns 6
var num;

函数声明提升

JavaScript 在执行任何代码段之前,将函数声明放入内存中的优点之一是,你可以在声明一个函数之前使用该函数。例如:

// 正确的方式:先声明函数,再调用函数 (最佳实践)
function catName(name) {console.log("我的猫名叫 " + name);
}
catName("Tigger");
// 以上代码的执行结果是: "我的猫名叫 Tigger"

上面的代码片按照是你的正常思维(先声明,后调用)去书写的。现在,我们来看看当我们在写这个函数之前调用这个函数会发生什么:

// 不推荐的方式:先调用函数,再声明函数
catName("Chloe");
function catName(name) {console.log("我的猫名叫 " + name);
}
// 代码执行的结果是: "我的猫名叫 Chloe"

即使我们在定义这个函数之前调用它,函数仍然可以工作。这是因为在 JavaScript 中执行上下文的工作方式造成的。变量提升也适用于其他数据类型和变量。变量可以在声明之前进行初始化和使用。但是如果没有初始化,就不能使用它们。

注:函数和变量相比,会被优先提升。这意味着函数会被提升到更靠前的位置。

函数表达式声明的变量提升

console.log(func); // undefined
func() // Uncaught TypeError: func is not a function
var func = function() {console.log('hello');
}
func(); // output: 'hello'

总结

记住只有声明被提升!!!

  • 变量声明提升:var 声明语句,在声明和赋值之前可以访问到,返回值是undefined。

  • 函数声明提升:function 声明的函数,可以在声明之前调用该函数(不推荐使用)。

  • 函数表达式声明的变量提升:等同于变量提升,声明语句之后可以调用该函数。

解决方法

在JavaScript严格模式(strict mode)下工作(只需要添加 "use strict"; 在源码的最上面),使web浏览器更容易的解析代码。

使用let/const声明变量,这是ES6的一个新特性,而let声明的变量是不存在变量提升的作用。在函数作用域和块作用域(ES6之前无此概念)中实例化时,其中用let和const声明的变量会先被创建,但由于此时还未进行词法绑定,所以无论如何都不能被外部访问,如果试图访问则会抛出错误。而我们所说的暂时性死区(Temporal Dead Zone(TDZ))就是从程序执行作用域内创建变量,直至变量可以被访问这段时间。但是TDZ名词并没有明确地写在ES6的标准文件中,一开始是出现在ES Discussion讨论区中,是对于某些遇到在区块作用域绑定早于声明语句时的状况时,所使用的专用术语。

let/const声明

ES6之前,JavaScript的作用域(scope)分为全局作用域和函数作用域两种,通过var来声明变量。ES6退推出后,就引入了let/const和块级作用域的概念。let/const与var的主要不同有两个地    

变量提升(Hoisting)

变量提升(Hoisting)被认为是, Javascript中执行上下文 (特别是创建和执行阶段)工作方式的一种认识。在 ECMAScript® 2015 Language Specification 之前的JavaScript文档中找不到变量提升(Hoisting)这个词。例如,从概念的字面意义上说,“变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,但这么说并不准确。实际上变量和函数声明在代码里的位置是不会动的,而是在编译阶段被放入内存中。

变量声明提升

JavaScript 只会提升声明,不会提升其初始化。如果一个变量先被使用再被声明和赋值的话,使用时的值是 undefined。参见例子:

console.log(num); // Returns undefined
var num;
num = 6;

变量num提升后代码相当于:

var num;
console.log(num); // Returns undefined
num = 6;

如果你先赋值、再使用、最后声明该变量,使用时能获取到所赋的值

num = 6;
console.log(num); // returns 6
var num;

函数声明提升

JavaScript 在执行任何代码段之前,将函数声明放入内存中的优点之一是,你可以在声明一个函数之前使用该函数。例如:

// 正确的方式:先声明函数,再调用函数 (最佳实践)
function catName(name) {console.log("我的猫名叫 " + name);
}
catName("Tigger");
// 以上代码的执行结果是: "我的猫名叫 Tigger"

上面的代码片按照是你的正常思维(先声明,后调用)去书写的。现在,我们来看看当我们在写这个函数之前调用这个函数会发生什么:

// 不推荐的方式:先调用函数,再声明函数
catName("Chloe");
function catName(name) {console.log("我的猫名叫 " + name);
}
// 代码执行的结果是: "我的猫名叫 Chloe"

即使我们在定义这个函数之前调用它,函数仍然可以工作。这是因为在 JavaScript 中执行上下文的工作方式造成的。变量提升也适用于其他数据类型和变量。变量可以在声明之前进行初始化和使用。但是如果没有初始化,就不能使用它们。

注:函数和变量相比,会被优先提升。这意味着函数会被提升到更靠前的位置。

函数表达式声明的变量提升

console.log(func); // undefined
func() // Uncaught TypeError: func is not a function
var func = function() {console.log('hello');
}
func(); // output: 'hello'

总结

记住只有声明被提升!!!

  • 变量声明提升:var 声明语句,在声明和赋值之前可以访问到,返回值是undefined。

  • 函数声明提升:function 声明的函数,可以在声明之前调用该函数(不推荐使用)。

  • 函数表达式声明的变量提升:等同于变量提升,声明语句之后可以调用该函数。

解决方法

在JavaScript严格模式(strict mode)下工作(只需要添加 "use strict"; 在源码的最上面),使web浏览器更容易的解析代码。

使用let/const声明变量,这是ES6的一个新特性,而let声明的变量是不存在变量提升的作用。在函数作用域和块作用域(ES6之前无此概念)中实例化时,其中用let和const声明的变量会先被创建,但由于此时还未进行词法绑定,所以无论如何都不能被外部访问,如果试图访问则会抛出错误。而我们所说的暂时性死区(Temporal Dead Zone(TDZ))就是从程序执行作用域内创建变量,直至变量可以被访问这段时间。但是TDZ名词并没有明确地写在ES6的标准文件中,一开始是出现在ES Discussion讨论区中,是对于某些遇到在区块作用域绑定早于声明语句时的状况时,所使用的专用术语。

let/const声明

ES6之前,JavaScript的作用域(scope)分为全局作用域和函数作用域两种,通过var来声明变量。ES6退推出后,就引入了let/const和块级作用域的概念。let/const与var的主要不同有两个地方,下面通过几个示例来感受:

// undefinedconsole.log(name1);
// Uncaught ReferenceError: Cannot access 'name2' before initializationconsole.log(name2);
// Uncaught ReferenceError: Cannot access 'name2' before initializationconsole.log(name3);var name1 = "Jack";let name2 = "Alice";const name3 = "Bob";

在let/const声明之前访问对应的变量或常量,会报错Uncaught ReferenceError;var声明之前访问变量,则会得到undefined。

        var a = 8;if(true) {
// Uncaught ReferenceError: Cannot access 'a' before initializationa = 88; let a;    }

这里的if语句中a明明上边var声明并赋值了,为什么它还报个不能在初始化前访问呢?ES6明确规定如果区块中存在let/const命令,这个区块就对这些命令声明的变量,形成了一个封闭作用域。说白了就是在代码块内,在变量声明之前使用都是不可取的,会抛出错误。

if (true) {// TDZ开始tmp = 'abc'; // ReferenceErrorconsole.log(tmp); // ReferenceError
​let tmp; // TDZ结束console.log(tmp); // undefined
​tmp = 123;console.log(tmp); // 123
}运行结果:

参考:Hoisting(变量提升) - 术语表 | MDN | 理解ES6中的TDZ(暂时性死区) - 掘金

http://www.lryc.cn/news/2419608.html

相关文章:

  • 什么是WordPress?
  • jq-jquery根据内容设置select和input radio选中
  • 高数 | 工具及必备方法 | 【一元函数积分学】常用积分公式表
  • default-gateway和default-router的区别
  • Apche部署https详解
  • 采样定理的证明与推导
  • XSLT知识总结
  • 传说中的“摸奶节”!随便你怎么摸!
  • 社会网络分析与人脉网络:如何建立有效的人脉资源
  • Toybox、toolbox、busybox 软件协议
  • HTTP代理和SOCKS代理
  • 内存术语详解
  • 探索听诊器效应:了解声音在耳朵中的传播方式
  • StringTokenizer类的详解
  • 超音速启动 2020 年版发布
  • AMR音频格式分析
  • CrashRpt
  • 【音视频知识】MP4文件格式解析-详解
  • 日本的feature phone版twitter的follow链接
  • Android——bindService()方法启动服务
  • 汇编实验1——利用8255实现LED的流水点亮实验
  • td 元素属性 noWrap 防止折行、撑开及文字换行
  • 人类技术变革简史:娱乐产业的演进与创新
  • 安卓中GridView的使用
  • 史上最好理解的Unicode编码讲解(Unicode的前世今生)
  • Restorator软件使exe文件都不能打开,任务管理器不支持此接口
  • JavaScript-offset家族
  • Android支持暂停的CountDownTimer倒计时工具类
  • RAR Extractor - Unarchiver for Mac v6.5.0 解压缩软件
  • HTML5字体样式属性