[ES6系列-04]再也不乱“哇”了:用 let 与 const 替代 var

【原创】码路工人 Coder-Power

大家好,这里是码路工人有力量,我是码路工人,你们是力量。

github-pages
博客园cnblogs



今天的内容是,关于 JavaScript 中定义变量的变化(其实不确切,函数,常量表示被冷落)。



首先,回顾下 var 定义存在的问题

1. 哇。。var 好乱。。

1.1 可以重复定义

/* eg.0
    * multi-definition of var-variable
    */
//--------------------------------------
var band = "The Beatles"
var band = "The Scorpions"

console.log(band)     // Scorpions
//--------------------------------------

以上代码没有报错,而是打印出了第二次定义的内容Scorpions。这..在C#等其它语言中必然是无法想象的。

JS:哎悲惨的童年,往事不堪回首。虽然被设计的简陋粗糙了些,但用起来方便啊,通过努力,一样成为Web时代的高富帅。现在有钱了,美容养生造起来~~~

1.2 可以先使用后定义

/* eg.1
    * use before be definied
    */
//--------------------------------------
age = 18
console.log(age)        // 18
var age = 10
console.log(age)        // 10
//--------------------------------------

这就是变量提升啦。在编译的时候,会先将var定义的变量放到最上面,但这时候值并没有,还是undefined,赋值顺序为 18->10,所以有了一上例示例注释中的打印结果。

这里,还有一个优先级的问题,function > variable,即函数大于普通变量。

1.3 没有块级作用域

/* eg.2
    * [var]use before variable be definied
    */
//--------------------------------------
function foo() {
    var band = "Michael Learn To Rock"
}

console.log(band)        // Michael Learn To Rock
//--------------------------------------

块级作用域应该有:if(boolVal){ 这里 }for(...){ 这里 },还有function(){ 这里 },其实即使不是函数直接一对花括号也是产生块级的地方。

var没有块级作用域,意味着在块级外面也能够访问。上例中的结果说明了这一点。

IIFE(Immediately Invoked Function Expression) 立即执行函数了解一下(这个准备在后面的文章中单独介绍)。



然后咱们来看看 ES6 带来了什么

2. let const 来拯救

2.1 letconst 都有块级作用域

码麻再也不担心我在暗处受伤害了:

限定在块级作用域内不会被外部访问修改。

/* eg.3
    * can not access out of block
    */
//--------------------------------------
// eg.3.1
function music() {
    let band = "Mr. Big"
    const songs = ["The chain", "To be with you", "Wild world"]

    this.data = {
        band,songs
    }
}
console.log(band, songs)
// Uncaught ReferenceError: band is not defined
//--------------------------------------

上面的打印直接报错,函数外是不能访问到内部用let/const声明的变量/常量的。

扩展一下:但可以绑定到对象属性上,属性本身外部可见。如下面的示例(在上例的基础上):

// eg.3.2
let m = new music()
console.log(m.data)
// { band: 'Mr. Big', songs: [ 'The chain', 'To be with you', 'Wild world' ] }

2.2 letconst 都有不存在变量提升

不给糖就捣蛋。要想使用先定义。

/* eg.4
    * [let/const]use after be definied
    */
//--------------------------------------
// eg.2.1
band = "Queen"
let band
// Uncaught ReferenceError: Cannot access 'band' before initialization

// eg.2.2
song = "Bohemian Rhapsody"
const song
// Uncaught SyntaxError: Missing initializer in const declaration
//--------------------------------------

未定义先使用?直接报错给你看。(看,报的错还不一样,下面还会提到)

2.3 letconst 都不能重复定义

/* eg.4
    * [let/const]can not defined duplicately
    */
//--------------------------------------
// eg.4.1
let band = "Guns&Rose"
let band = "Nirvana"
// Uncaught SyntaxError: Identifier 'band' has already been declared

// eg.4.2
const song = "November Rain"
const song = "Smells Like Teen Spirit"
// Uncaught SyntaxError: Identifier 'song' has already been declared
//--------------------------------------

简单的规则无需解释。我就是你的唯一!

2.4 let 定义变量

/* eg.5
    * [let/const]can not defined duplicately
    */
//--------------------------------------
let singer = "Bob Dylan"
console.log(singer)     // Bob Dylan

singer = "Bryan Adams"
console.log(singer)     // Bryan Adams
//--------------------------------------

变量确实是可变的。

注:像字符串与数值,栈中存放地址,堆中保持常量池,比较两个字面量的时候,比的是地址所以会全等(===),而再次给变量赋值的时候,改变的是地址指向,常量池中的原字符串/数值还是存在的(等没有引用会回收)。

关于 ===== 可以看之前发的另一篇[传送][AboutEqual]。

2.5 const 定义常量

JS: 终于咱也有常量了(C#里也叫const

2.5.1 常量定义后不可变

/* eg.6
    * use before be definied
    */
//--------------------------------------
// eg.6.1
const band = "The Eagles"
band = "The Beatles"
// TypeError: Assignment to constant variable.

// eg.6.2
const age = 18
age = 10
// TypeError: Assignment to constant variable.
//--------------------------------------

以上两个小例子中,说明字符串或数值的常量在定义后都是不能再改变的。

注意:这里不可变是指简单类型,复杂类型/对象里面的成员/属性是可以改变的。

/* eg.7
    * change the value of const-object's property
    */
//--------------------------------------
const person = {
    name = "Eagles",
    age = 18
}
console.log(person)
// { name: 'Eagles', age: 18 }

person.name = "Chicken"
person.age = 10
console.log(person)
// { name: 'Chicken', age: 10 }
//--------------------------------------

以上打印结果显示,const对象的属性name/age修改成功。

2.5.2 常量在且仅在定义时赋值(=定义时必须赋初始值,赋值后不能改)

/* eg.8
    * exception on define const
    */
//--------------------------------------
const foo
foo = "bar"
// SyntaxError: Missing initializer in const declaration
//--------------------------------------

不用解释,报异常了。定义const必须给值。(上面已经提到过了,就当加深印象再说一遍吧)



(示例中好像暴露了部分播放历史。。感兴趣的同学可以搜搜瞧下)



希望对你能有帮助,下篇再见。



欢迎关注分享,一起学习提高吧。



[ES6系列-04]再也不乱“哇”了:用 let 与 const 替代 var

原文地址:https://www.cnblogs.com/CoderMonkie/p/es6-about-let-and-const.html

时间: 2024-08-05 07:48:16

[ES6系列-04]再也不乱“哇”了:用 let 与 const 替代 var的相关文章

Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例

java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例 概要  和学习ArrayList一样,接下来呢,我们先对LinkedList有个整体认识,然后再学习它的源码:最后再通过实例来学会使用LinkedList.内容包括:第1部分 LinkedList介绍第2部分 LinkedList数

JavaScript进阶系列04,函数参数个数不确定情况下的解决方案

本篇主要体验函数参数个数不确定情况下的一个解决方案.先来看一段使用函数作为参数进行计算的实例. var calculate = function(x, y, fn) { return fn(x, y); }; var sum = function(x, y) { return x + y; }; var diff = function(x, y) { return x - y; }; var sumResult = calculate(1, 2, sum), diffResult = calcu

委托、Lambda表达式、事件系列04,委托链是怎样形成的, 多播委托

在"委托.Lambda表达式.事件系列01,委托是什么,委托的基本用法,委托的Method和Target属性"中,反编译委托,发现委托都是多播委托. 既然委托是多播委托,我们可以通过"+="把多个方法赋给委托变量,这样就形成了一个委托链, 它是怎样形成的?来看下面的例子: namespace ConsoleApplication3 { internal delegate void MySayDel(string msg); class Program { stati

线程系列04,传递数据给线程,线程命名,线程异常处理,线程池

本篇体验:如何传递数据给线程,如何给线程命名,线程的异常处理,线程池.实在是太基础的部分. □ 传递数据给线程 ※ 使用Lambda表达式 class Program { static void Main(string[] args) { Thread t = new Thread(() => Say("hello", "world")); t.Start(); } static void Say(string msg, string msg1) { Cons

php从入门到放弃系列-04.php页面间值传递和保持

php从入门到放弃系列-04.php页面间值传递和保持 一.目录结构 二.两次页面间传递值 在两次页面之间传递少量数据,可以使用get提交,也可以使用post提交,二者的区别恕不赘述. 1.get提交 使用get提交来传递数据,在链接地址中修改发送到服务器的 URL 如下所示http://www.cnblogs.com/MarkRao/p/php01.html?gName=mark&gAge=26 ,当然也可以在表单中设置method="get",php中接收get提交过来的数

[js高手之路] es6系列教程 - 迭代器,生成器,for...of,entries,values,keys等详解

接着上文[js高手之路] es6系列教程 - 迭代器与生成器详解继续. 在es6中引入了一个新的循环结构for ....of, 主要是用来循环可迭代的对象,那么什么是可迭代的对象呢? 可迭代的对象一般都有Symbol.iterator属性,你可以在控制台中用console.dir打印数组,Map,Set,在他们的原型对象(prototype)上面就能找到.这个属性与迭代器密切相关,通过该函数可以返回一个迭代器,下文,我会举一个例子.一般来说所有的集合对象(数组,Set,Map 以及字符串)都是可

java io系列04之 管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例

本章,我们对java 管道进行学习. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_04.html java 管道介绍 在java中,PipedOutputStream和PipedInputStream分别是管道输出流和管道输入流.它们的作用是让多线程可以通过管道进行线程间的通讯.在使用管道通信时,必须将PipedOutputStream和PipedInputStream配套使用.使 用管道通信时,大致的流程是:我们在线程A中向PipedOut

C#程序集系列04,在程序集包含多个module的场景下理解关键字internal

本篇在一个程序集包含多个module的场景下体验internal的含义. →查看F盘as文件夹下的文件→删除MainClass.exe→把MyFirstModule和MySecondModule组装到一个程序集中去现在,MyDll.dll程序集中包含了2个module.→反编译,把MyDLL.dll的IL代码显示到3.txt文件中→打开3.txt文件 // Metadata version: v4.0.30319 .assembly extern mscorlib { .publickeytok

C++矢量图形库系列(1)——矢量图形库乱谈(转)

转自:http://blog.sina.com.cn/s/blog_4265e1760100lg03.html 本系列篇章的主要内容是讲解矢量图形库的编译.开发和使用.并不对他们周边的内容做过多的描述,如性能对比等.本人博客所有文章全部都是个人原创,并保留一切权利.不是原创的内容本人一定会注明“转载”字样.所以如果您需要转载,请注明来源,谢谢. 矢量图形,这是一个非常熟悉但是又让人觉得陌生的东西.熟悉是因为听得太多了,Flash就大量应用了矢量图形技术,得以让一段完整的动画文件体积相比以逐帧图片