【前端17_JS】ES 6:Let 、Const、对象冻结、解构赋值、暂时性死区 TDZ、惰性求值、模板字符串
ES 6
- 简介
- let 声明变量
- 变量不提升
- 暂时性死区 TDZ
- const 静态变量 (常量*)
- 实质
- 引申
- 对象冻结
- 解构赋值
- 起步
- ...arr 展开运算符
- ...[] 数组拓展运算符
- 传参
- 找最大值
- 与三目运算符结合
- 空
- 模拟深复制
- 模拟 concat
- 结构解析
- 详细步骤
- 惰性求值
- 模板字符串
简介
- 2015年6月17日,ECMAScript 6发布正式版本,即ECMAScript 2015。
- ES6 是继 ES5 之后的一次主要改进,ES6 增添了许多必要的特性,例如:模块和类,以及一些实用特性,例如Maps、Sets、Promises、生成器(Generators)等。
- 尽管 ES6 做了大量的更新,但是它依旧完全向后兼容以前的版本,标准化委员会决定避免由不兼容版本语言导致的“web体验破碎”。结果是,所有老代码都可以正常运行,整个过渡也显得更为平滑,但随之而来的问题是,开发者们抱怨了多年的老问题依然存在。
let 声明变量
let 是新的变量声明
- 如果声明的位置是在代码块中,那么变量只能在代码块里有用
- 代码块,类似于
if
、for 循环
等等。
if(true){let a = 1;}console.log(a);//Uncaught ReferenceError: a is not defined
变量不提升
不像 var
,这个没有变量提升
所以,必须先声明,再使用
console.log(b);let b;//Uncaught ReferenceError: Cannot access 'b' before initialization
暂时性死区 TDZ
全称:temporal dead zone
声明变量之前不允许使用
if(true){/*TDZ start*/typeof temp;let temp;/* TDZ end*/console.log(temp);}//Uncaught ReferenceError: Cannot access 'temp' before initialization
- 注意 TDZ 的区域,从代码块开始,到定义完变量之后,这一小段是 TDZ,
- 引申:在 es6 中
typeof
不是绝对安全了
//多看代码,加深理解var c = 1;function test() {console.log(c);if(true){//这个c只是在if中有效let c = 10;}}test()//1
//跟上一个对比var c = 1;function test() {console.log(c);if(true){//这里有变量提升var c = 10;}}test()//undefined
//这个要注意一下var a = 1;function test() {console.log(a);//条件是falseif(false){/*先进去if中探索一下是否有 var 声明,然后再去判断语句*//*这个if在刚开始还是进去的,遇到var也还会提升,只是语句在执行的时候,没有进入if*/var a = 10;}}test();//undefined
- 这里有个情况
let x;//这把{x}当作了代码块,解决这个问题的话,整体加圆括号{x} = {x:1}console.log(x);//Uncaught SyntaxError: Unexpected token '='
//解决方法let x;//{x} = {x:1}({x} = {x:1});console.log(x);//1
const 静态变量 (常量*)
有如下属性
- 不允许重复声明
- 声明的时候赋值
- 声明之后不允许修改
- 跟
let
的作用域一个德行,都是代码块里有效
实质
- const 实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址不得改动
- 对于 简单类型 的数据(数值,字符串,布尔值),存在 栈 中,值就保存在变量指向的那个内存地址。
- 对于 复杂对象(主要是对象和数组),变量指向的内存地址存在 堆 中,保存的是指向,指向的数据怎么变,它管不到
引申
- 栈:大小固定,自动分配,能由系统自动释放掉
- 堆:可变大小,不能自动释放掉
对象冻结
用到了 Object.freeze();
方法
const obj = Object.freeze({name:"张三"});
- 建议前面写上
const
,因为如果你这样,之后也能改变指向,如果你用了const
,就改变不了了
//用var,声明不变的量,也不安全var obj = Object.freeze({name:"张三"});obj = {};console.log(obj);//{}
//使用const声明const obj = Object.freeze({name:"张三"});obj = {};console.log(obj);//Uncaught TypeError: Assignment to constant variable.
- 冻结之后,如果想要修改内容的话,是不会报错的,但是并不能修改内容(以为对象冻结住了)
- 如果想要修改内容的话,就需要解冻。
const obj = Object.freeze({name:"张三"});obj["name"] = "小子";console.log(obj);//{name: "张三"}
解构赋值
起步
可迭代的数据都可以解构赋值(数字就不行了)
- 简单的解构赋值如下
let [a,b,c] = [1,2,3];console.log(a);console.log(b);console.log(c);//1//2//3
- 快速互换两个值:比方说
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log("a,b", a, b); // a,b 2 1
- 也可以用来当作函数的实参、形参,而且 解构赋值 有个好处,可以传
""
,undefined
,null
,false
这些东西。
//例子1:普通给默认值的方法//如果你传的值是undefined等,他是走默认值0的,而我们希望走的是undefinedfunction test_bad(val) {val = val || 0;console.log(val);}test_bad("");test_bad(undefined);test_bad(null);test_bad(false);//0//0//0//0
//例子1的对比,优化//如果你传来的不是严格的 undefined,那么就会走默认值function test_good([a,b,c = 0,d = 4,e]) {console.log(a);console.log(b);console.log(c);console.log(d);console.log(e);}test_good([false,null,"",undefined,"undefined"]);//false//null////4//undefined
- 如果想要让obj2 拿到obj 的内容,修改obj2还不影响obj,那么可以解构obj (解构之后就变成了个新的对象),然后在赋值给obj2
let obj = {a: 1,b: 2,
};
// let obj2 = {...obj}
let obj2 = obj;
// 如果想要让obj2 拿到obj 的内容,修改obj2还不影响obj,那么可以解构obj,然后在赋值给obj2
obj2.a = 10;
console.log(obj);
…arr 展开运算符
先来一个例子,慢慢理解一下
...arr
一定要保证是在后面,因为它只能解析从某个地方到 数组尾部
//不能这样:let[...arr,a] = ["ar",2,3,4];let[a,...arr] = ["ar",2,3,4];console.log(a);console.log(arr);//ar//(3) [2, 3, 4]
- 如果没有值得话,就会生成一个空数组
let[a,b,...arr] = ["ar"];console.log(arr)//Array(0)
- 也可以遍历字符串
- 可以设置默认值,如果严格等于undefined,那么就走默认值(底层是
===
)
//严格等于 undefined,走默认的值let [a = 100,b = "poi"] = [undefined];console.log(a);console.log(b);//100//poi//不严格等于 undefined ,走赋值let [a = 100,b = "poi"] = ["undefined"];console.log(a);console.log(b);//undefined//poi
//再来一个引申var a = undefined;var b = "undefined";//0 == 1console.log(a == b);//两等都不行了,三等就更没戏了console.log(a === b);//false//false
- 还能承接传来的参数,这个叫做
rest
function test(...arr) {console.log(arr);}test(1,2,3,4)//(4) [1, 2, 3, 4]
…[] 数组拓展运算符
- 这个就相当于
rest
的逆运算,一个是聚合,一个是拆散,...[1,2,3]
会被拆成1 2 3
var f1 = (a,b,c,d) => {console.log(a);console.log(b);console.log(c);console.log(d);//1//2//3//4};f1(1,...[2,3,4]);
- 这个功能就很强大了,可以跟选择器结合使用
<body><div>1</div><div>2</div><div>3</div>
</body>
<script>console.log(...document.querySelectorAll("div"));
</script>
传参
- 而且与
rest
不同的是,可以不用放到最后
//1.解析的时候和rest不同的是,可以不用放到最后function f1(a,b,c,d,e) {console.log(a,b,c,d,e);}//[2,3,4]放到了参数们的中间,而rest必须放到后面才能正常使用arr1 = [1,...[2,3,4],5];//es5传参f1.apply(null,arr1);//1,2,3,4,5//es6f1(...arr1);//1,2,3,4,5
找最大值
var arr1_1 = [10,2,4654,789,56,6,131,32,];//es5的写法console.log(Math.max.apply(null,arr1_1));//4654//es6的写法console.log(Math.max(...arr1_1));//4654
与三目运算符结合
var x = 2;var arr2 = [...(x == 1?[1,2,3]:[4,5,6]),"x"];console.log(arr2);//(4) [4, 5, 6, "x"]
空
空的话,不会报错,控制台里就没有它的打印信息
var arr3 = [];console.log(...arr3);
模拟深复制
const a3 = [3,4,5];//2.模拟深复制const a4 = [...a3];console.log(a4);//(3) [3, 4, 5]
模拟 concat
var arr3_1 = [1,2,3];var arr3_2 = [4,5,6];console.log(arr3_1.concat(arr3_2));//(6) [1, 2, 3, 4, 5, 6]console.log([...arr3_1,...arr3_2]);//(6) [1, 2, 3, 4, 5, 6]
结构解析
- 对象解析当中根据
key
来解析 - let {匹配模式:变量}
let {c,a} = {b:"6666",a:"555"};console.log(a);console.log(c);//555//undefined
- 数组相当于一个特殊的对象,可以用 下标 当作 key 值去解析
/*数组的结构解析*/var arr = ["dsada","ewq",'zxcvc',16,18,"135"];let {1:fir,[arr.length-1]:last} = arr;console.log(fir);console.log(last);//ewq//135
详细步骤
//目的:我想解析shuaivar obj = {foo:['ufo',{sss:"shuai"}]};/*结构解析*//*第一步:等号左右类型要一样*/let {} = obj;/*第二步:添加匹配模式foo*/let {foo} = obj;/*第三步,这个时候b就代表了对象,数组的话就不需要匹配模式,随便一个符号占着茅坑找位置就行*/let {foo:[a,b]} = obj/*第四步:把b变成括号,然后再用匹配模式sss,来进入对象中*/let {foo:[a,{sss}]} = obj;/*第五步:你可以给sss赋值变量l,然后输出l就可以了*/let {foo:[a,{sss:l}]} = obj;console.log(l);
//觉得你行了?来试试这个,少年,解析girlvar sister = [{age:[18,{sex:"girl"}]}];
- 加深理解接着玩 ,console 也能解析
/*console是个对象,他有log方法,我把log方法解析出来*/let {log} = console;log("111");//111
/*对象 = 对象,把 math 对象中的属性承接出来,放到 PI 中,因为 PI 是属性值,所以打印就好* 如果是函数体的话就给参数调用*/const {PI} = Math;console.log(PI);3.141592653589793
//let {匹配模式:变量}//默认是let {foo:foo} = {foo:"cszsdad"};let {foo:fooValue} = {foo:"cszsdad"};console.log(fooValue);//cszsdad
- 结构解析也能分析继承的
Person.prototype.name = "lsl";function Person() {}var p = new Person();let {name:n} = p;console.log(n);//lsl
- 理解了之后自己玩了一个比较瑟琴的
//给你们答案,不唯一var sister = [{age:[18,{sex:"girl"}]}]; let [{age:[a,{sex:x}]}] = sister;console.log(x);
惰性求值
function f() {throw new Error("this is error");}/*惰性求值*//*如果有值得话,除了undefined,就一直不走默认的*/let [x = f()] = [1];console.log(x);//1
function f() {throw new Error("this is error");}//这样就走了默认的let [x = f()] = [undefined];/*let [x = f()] = [1];*/console.log(x);//Uncaught Error: this is error
模板字符串
- 优点:不需要我们拼接变量(原生的不是得用
+
来拼接成很长的句子嘛) - 符号:
``
(TAB上面的那个~) - 想在模板字符串中插入变量的话用
${}
- 还是函数调用的另一种形式
//函数调用,括号变成``也可以alert `4`;
//模板字符串的简单使用const obj = {name:18,age:"xiaopang",habit:"sing",};var str = `my name is ${obj.name} ,age is ${a}`;console.log(str);//my name is 18 ,age is xiaopang
- 如果你非要在模板字符串中打出
``
这个符号,那么可以用转义字符\
//转移字符var str1 = `\`\``;console.log(str1);//``
- 这个还可以插标签,可以进行变量的运算,注意写法、还可以插入方法,而且还会 解析换行,你怎样写,就会在页面上解析成相应的样子,包括换行,空格。
//综合应用var x = 5;var arr = [1,2,3,4,5];//插入标签,运算,arr.reverse()方法,对象引用$("#test").html(`<ul><li style="font-size: ${x + 40}px;">1</li><li>22\`\`</li><li>${arr.reverse()}</li><li>${obj.name + x}</li></ul>`)
- 如果当作实参的话,字符串里穿插变量,那么形参中可以接到如下的东西
var xx = 1;var yy = 2;var zz = 3;function show (a,b,c,d,e) {/*这个a是实参中所有字符串的字段,并放到数组中*/console.log(a);console.log(b);console.log(c);console.log(d);console.log(e);}show `this ${xx} is ${yy} a ${zz} iu`;//(4) ["this ", " is ", " a ", " iu", raw: Array(4)]//1//2//3//undefinedfunction show1 (a,...arr) {console.log(a);console.log(arr);}/*如果变量放到了第一个,前面没有字符串,那么a[0]会被解析成空字符串*/show1 `${xx} is ${yy} a ${zz} this`;//["", " is ", " a ", " this", raw: Array(4)]//(3) [1, 2, 3]//解释:/*最前面的和最后面的变量,在这里是${xx}和${zz}*///最前面的变量${xx},看它的前面,有字符串那么就拿,如果没有就会拿空//最后面的变量${zz},看他的后面,有字符串那么就拿,如果没有就会拿空
【前端17_JS】ES 6:Let 、Const、对象冻结、解构赋值、暂时性死区 TDZ、惰性求值、模板字符串相关推荐
- Vue学习笔记(三)Vue2三种slot插槽的概念与运用 | ES6 对象的解构赋值 | 基于Vue2使用axios发送请求实现GitHub案例 | 浏览器跨域问题与解决
文章目录 一.参考资料 二.运行环境 三.Vue2插槽 3.1 默认插槽 3.2 具名插槽 3.3 作用域插槽 ES6解构赋值概念 & 作用域插槽的解构赋值 3.4 动态插槽名 四.GitHu ...
- 【ES6】let命令、const命令、解构赋值
let命令 ES6 新增了let命令,用来声明变量.它的用法类似于var,但是也存在新的特性. let所声明的变量,只在let命令所在的代码块内有效,避免全局污染.(适用于for循环) {let a ...
- ES6 对象的解构赋值
对象的解构赋值 解构不仅可以用于数组,还可以用于对象. var { foo, bar } = { foo: "aaa", bar: "bbb" }; foo / ...
- 【ES6学习】对象的解构赋值
解构不仅可以用于数组,还可以用于对象. let { foo , bar } = { foo :"aaa ", bar :"bbb " } ; too // &q ...
- js 对象的解构赋值
2023.1.29今天我学习了对象的解构赋值. 解构不仅可以用于数组,还可以用于对象. let {foo,bar} = {foo : "aaa",bar : "bbb&q ...
- ECMAScript6学习笔记 ——let、const、变量解构赋值
let 不存在变量提升 通过let声明的变量仅在块级作用域内有效 不允许在同一个作用域内重复声明一个变量 防止值公用 var oUl = document.querySelectorAll('ul&g ...
- java对象赋值给数组_带你深入的理解数组和对象的解构赋值。
es6提供了一个非常好的特性,即变量的解构赋值.从而我们可以方便的从数组和对象中提取数据并将它们赋值给变量.这是非常必要的.先来看在这个新特性发布之前我们是如何从数组中提取数据的.如下: let nu ...
- 前端学习必备之ES6解构赋值的常见用法
1.解构赋值可以轻松获取对象或者数组中的数据 var jsonData = {data: "111",data2: ["test","test2&qu ...
- 【ES6】阮一峰ES6学习(一) let、const、解构赋值
let 和 const 命令 1. let 概念:块级作用域. 不存在变量提升:在声明变量前使用该变量,会报错. 暂时性死区:形成了封闭作用域,在代码块内,使用let声明变量之前,该变量都是不可用的. ...
最新文章
- SSIS--FOR循环容器
- Google X的机器人开始打工!进咖啡馆擦桌子:擦的很慢,但我们一直在做
- ASP.NET安全问题--ASP.NET中的授权问题(前篇)
- 深入理解java中的ArrayList和LinkedList
- android studio下的NDK开发详解
- 委托学习总结(一)浅谈对C#委托理解
- 根据BAPI_PO_CREATE1创建采购订单
- Google AdSense中文官方博客今天公布了AdSense内容广告与AdSense搜索广告的收入分成比例...
- 13 个开源备份解决方案
- NSTimer实现读秒、倒计时等周期性操作
- 一千五百个优雅的中国女孩的名字
- 潮流仿真分析matlab,基于MATLAB的电力系统潮流仿真与研究
- ArcGIS 地表TIN面数据的符号化
- 论文笔记——分布式深度学习框架下基于性能感知的DBS—SGD算法
- matlab二次求导函数,原来可以这样求导函数,再复杂的函数求导不再话下!
- NoteExpress免费版只7个引文样式#NoteExpress免费版新增引文样式
- 序列号 java_JAVA序列号的serialVersionUID
- 认识并行、并发、多线程
- 前端-超链接,相对路径
- iOS KeyChain使用