摘要:在之前,中没有常量声明方式,有的仅仅是一种命名上的约定。这样就可以最大程度上规避变量的意外变化来使程序发生异常的可能性。为了避免作用域的污染,在中需要使用一个立即执行函数来确保变量的作用域范围。
在 ES6 之前,JS 中没有常量声明方式,有的仅仅是一种命名上的约定。
var PI = 3.14; PI = 4; console.log(PI); // 4
我们用大写变量名来标识这是一个常量,但这种约定并不能保证常量的不可变,在程序的执行过程中,依旧有可能改变该常量的值。
而在 ES6 中,给出了声明一个常量的方法:
const PI = 3.14; PI = 4; // Uncaught TypeError: Assignment to constant variable.
通过 const 声明的常量在赋值之后不能再次进行赋值,否则会报错。
在使用 ES6 的程序中,我们提倡对变量声明时采用 const 来代替 var。在确实需要改变变量的值的时候使用 let。这样就可以最大程度上规避变量的意外变化来使程序发生异常的可能性。
有句老生常谈的话,JS 中一切皆对象。JS 中的数据类型有两类,一类是按值传递,另一类使按引用传递。
对于字符串数字等基本类型,变量保存的指向该值实际数据的内存地址。而对于对象,变量保存的是指向该对象的一个内存引用。
所以,实际上 const 绑定的不可变常量对于对象而言,是其指向的对象的内存地址绑定不可变,而非指向对象的属性不可改变。
const person = { name: "John", age: 20 }; person.name = "Tom"; console.log(person.name); // Tom person = {} // Uncaught TypeError
除了对多次赋值的错误提示外,使用 let 和 const 以代替带来的好处还有实现了块级作用域。
在任何一本 es6 之前的 js 书中,变量部分几乎都会告诉我们,js 中的变量没有块级作用域。作用域是函数作用域。
顺着作用域链,在非函数内声明的变量会存在于全局作用域中,在浏览器环境中,他会变成 window 对象的一个属性。
var PI = 3.14 console.log(window.PI) // 3.14
为了避免作用域的污染,在 ES5 中需要使用一个立即执行函数来确保变量的作用域范围。
(function () { var PI = 3.14; console.log(PI); // 3.14 })(); console.log(PI); //undefined
此时形成了一个闭包。
一个经典问题,循环绑定事件:
var buttons = document.querySelectorAll(".button"); for (var i = 0; i < buttons.length; ++i) { buttons[i].addEnentListener("click", function(evt) { console.log(i) }, false) }
在页面中,为三个按钮绑定 click 事件,输出相应按钮的数组下标索引。
结果我们可以看到,三个按钮绑定的 i 值均为 3。也就是说,在上述循环中,按钮绑定的值为 i 最后一次自增的值。
为了将绑定的 i 值限定在每次循环内,也就是需要在 for 循环内形成块级作用域。
在 ES5 之前,可以这样改写:
var buttons = document.querySelectorAll(".button"); for (var i = 0; i < buttons.length; ++i) { (function (i) { buttons[i].addEventListener("click", function(evt) { console.log(i) }, false) })(i) }
利用闭包,我们保存来每次循环三次生成三个作用域,三个作用域的值互不影响。
闭包使得变量的生命周期得以延续。
而对于 ES6,有了 let,就可以直接用起来了。
const buttons = document.querySelectorAll(".button"); for (let i = 0; i < buttons.length; ++i) { buttons[i].addEventListener("click", function(evt) { console.log(i) }, false) }
前面我们提到过,使用 var 声明的变量在全局作用域中会成为全局对象的一个属性:
window.PI = 3.14; var PI = 4; console.log(PI); // 4 console.log(window.PI); // 4
而 const 和 let 声明的变量并不会成为全局对象的属性。也不会更改原先的属性值,而是"遮蔽"该值。
window.PI = 3.14; const PI = 4; console.log(PI); // 4 console.log(window.PI); // 3.14变量声明提升与临时死区
在使用 const 和 let 来代替 var 使用时,需要关注到不同的一点是,const 和 let 不存在变量声明提升:
const welcome = function (name) { console.log(welcome_text); var welcome_text = `hello ${name}`; }; welcome("Rainy"); // undefined
JS 引擎在扫描代码时,遇到 var 声明的变量会将其提升至作用域顶部。因而在这里,console.log() 函数访问 welcome_text 变量,变量声明提升之后未进行赋值,返回 undefined。
而遇到 const 和 let 声明的变量时,并不会将其提升至作用域顶部,此时该变量位于临时死区(TDZ)中,直到遇到该变量声明语句才会移出 TDZ,在此之前访问该变量都会抛出错误。
const welcome = function (name) { console.log(welcome_text); const welcome_text = `hello ${name}` }; welcome("Rainy"); // Uncaught ReferenceError: welcome_text is not defined
-EOF-
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/94935.html
摘要:在年正式发布了,简称,又称为。再次简写循环迭代数组每个元素都执行一次回调函数。方法用于调用数组的每个元素,并将元素传递给回调函数。注意对于空数组是不会执行回调函数的。 转载请注明出处 原文连接 http://blog.huanghanlian.com/article/5c7aa6c7bf3acc0864870f9d es6 是什么 首先弄明白ECMA和js的关系。ECMA是标准,Jav...
摘要:在年正式发布了,简称,又称为。再次简写循环迭代数组每个元素都执行一次回调函数。方法用于调用数组的每个元素,并将元素传递给回调函数。注意对于空数组是不会执行回调函数的。 转载请注明出处 原文连接 http://blog.huanghanlian.com/article/5c7aa6c7bf3acc0864870f9d es6 是什么 首先弄明白ECMA和js的关系。ECMA是标准,Jav...
摘要:以下,请求两个,当两个异步请求返还结果后,再请求第三个此处为调用后的结果的数组对于来说,只要参数数组有一个元素变为决定态,便返回新的。 showImg(https://segmentfault.com/img/remote/1460000015444020); Promise 札记 研究 Promise 的动机大体有以下几点: 对其 api 的不熟悉以及对实现机制的好奇; 很多库(比...
一、语法规则 选择器{ 属性1:属性值1; 属性2:属性值2; ...... } /*注释*/ 二、如何在html中应用CSS 1. 外部引用css文件 css文件:css/layout.css(css文件夹和HTML位于同一个目录下) 2. 内部嵌入css /*css代码*/ 3...
阅读 4132·2021-11-22 13:52
阅读 2499·2021-11-22 13:52
阅读 3671·2021-11-19 09:59
阅读 1173·2021-11-17 09:33
阅读 2434·2019-08-30 10:53
阅读 1189·2019-08-29 17:28
阅读 1295·2019-08-29 17:03
阅读 3087·2019-08-26 11:31