ES6学习笔记
一、let 和const关键字
1.2 .0 let关键字的使用
-
let命令 基本语法
let a =10; { let b = 100;//b只在当前代码块中有效 }
-
不存在变量的提升
console.log(a)// a is not function let a=19; console.log(b);//undefined var b =10;
- a在未声明之前就是用了,var存在全局作用于,所以b只是没有被赋值,结果为undefined;但是let声明的变量,提前使用就是会报错
-
暂时性死区( TDZ)
var tmp = 123; if (true) { //TDZ开始 tmp = 'abc'; // ReferenceError let tmp;//TDZ结束 }
- 虽然tmp在外层使用了var声明,但是if语句里,tmp使用了let声明绑定了tmp,但是tmp=“abc”,还未在let声明tmp是就进行赋值操作,所以报错了。
function bar(x = y, y = 2) { return [x, y]; } bar(); // 报错
- 调用
bar
函数之所以报错(某些实现可能不报错),是因为参数x
默认值等于另一个参数y
,而此时y
还没有声明,属于“死区”。如果y
的默认值是x
,就不会报错,因为此时x
已经声明了
-
不允许重复声明
// 报错 function func() { let a = 10; var a = 1; } // 报错 function func() { let a = 10; let a = 1; }
1.2.1 块级作用域
-
ES5存在全局作用域和函数作用域
var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = 'hello world'; } } f(); // undefined
- (内层变量覆盖外层变量)外部全局tmp变量,但是又因为函数f()中,有声明了tmp,导致函数内部tmp覆盖了外部temp变量,至于输出undefined,是因为if 判断false不走输出语句,但是前面输出语句有tmp,声明了没赋值,所以值就是undefined啦
var s = 'hello'; for (var i = 0; i < s.length; i++) { console.log(s[i]); } console.log(i); // 5
- (计数的循环变量泄露为全局变量)循环结束了,但是i的值还存在。
-
ES6块级作用域
function f1() { let n = 5; if (true) { let n = 10; } console.log(n); // 5 }
- n =5 和 n= 10是处于两块不同作用于的变量,n之所以输出5是因为这个n是和 let n= 5同处于一块作用域
-
ES6块级作用域和函数声明
- 块级作用域中声明函数,类似于用let声明变量,只在当前块中有效
function f() { console.log('I am outside!'); } (function () { if (false) { // 重复声明一次函数f function f() { console.log('I am inside!'); } } f();//ES5中 结果为:I am inside! }());
- ES5实际执行过程(f函数会被提升到自调用函数作用域的最前面)
// ES5 环境 function f() { console.log('I am outside!'); } (function () { //注意和上面代码if function位置 function f() { console.log('I am inside!'); } if (false) { } f(); }());
- ES6中执行(函数f存在if判断这个作用域中,所以仅限于此作用域有用,但是因为false所以,相当于没有声明函数)
// 浏览器的 ES6 环境 function f() { console.log('I am outside!'); } (function () { if (false) { // 重复声明一次函数f function f() { console.log('I am inside!'); } } f(); }()); // Uncaught TypeError: f is not a function
-
特别注意:(浏览器兼容性问题)—>为了减轻因此产生的不兼容问题;浏览器的实现可以不遵守上面的规定,有自己的行为。以下,只针对ES6有用
-
允许在块级作用域声明函数
-
函数声明类似于var ,即会将函数提升到作用域的头部
-
// 块级作用域内部的函数声明语句,建议不要使用 { let a = 'secret'; function f() { return a; } } // 块级作用域内部,优先使用函数表达式 { let a = 'secret'; let f = function () { return a; }; }
-
1.2.3 const关键字的使用
-
1.const基本语法(
const
声明一个只读的常量。一旦声明,常量的值就不能改变。)const PI = 3.1415; PI // 3.1415 PI = 3; // TypeError: Assignment to constant variable.
-
2、const本质(
const
实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。) -
3、const定义的数组,可以对其进行读写操作,但是如果将新数组赋值给它就会报错
const a = []; a.push('Hello'); // 可执行 a.length = 0; // 可执行 a = ['Dave']; // 报错
1.2.4 顶层对象的属性
-
在浏览器中指的是window对象,在node中指的是global;ES5中顶层对象和全局属性都是等价的
window.a = 1; a // 1 a = 2; window.a // 2
-
ES6改进
var a = 1; // 如果在 Node 的 REPL 环境,可以写成 global.a // 或者采用通用方法,写成 this.a window.a // 1 let b = 1; window.b // undefined
- 上面代码中,全局变量
a
由var
命令声明,所以它是顶层对象的属性;全局变量b
由let
命令声明,所以它不是顶层对象的属性,返回undefined
- 上面代码中,全局变量
二、变量的解构赋值
2.1.0 解构的含义
-
解构的数组案例
-
从数组和对象中提取值,对变量进行赋值,这被称为解构
//以前写法 let a= 10; let b =20; //ES6写法 可以从数组中提取值,按照对应位置,对变量赋值 let [a,b] =[10,20]
-
解构本质:写法属于“模式匹配”;只要等号两边的模式相同,左边的变量就会被赋予对应的值
<script> // 解构 let [a,b,c] = [1,2,4]; console.log(a); let [e,,d]=[,3,6]; console.log(e);//undefied 表示解构不成功 console.log(d); let[head,hand,...all] = [1,2,3,4] console.log(head); console.log(hand); console.log(all);//前面解构完剩下的元素 let[h,k,...para] = [1] console.log(h);//1 console.log(k);//undefind console.log(para);//[] </script>
-
不完全解构
let [a,[b],c]=[3,[6,8],0]; console.log(a);//3 console.log(b);//6 console.log(c);//0
-
注意:如果等号右边的是不可遍历的对象,就会报错
let [a,r,y]='哈哈哈'; let [m,n,o]=false; //浏览器控制台报错 变量的解构和赋值.html:42 Uncaught TypeError: false is not iterable
-
解构的默认值
let [foo = true] = []; foo // true let [x, y = 'b'] = ['a']; // x='a', y='b' let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
-
ES6中使用严格运算符` === 只有严格等于undefined默认值才会生效
let [x = 1] = [undefined]; x // 1 let [x = 1] = [null]; x // null
- 上面代码,一个数组等于null,是不严格等于
undefined
的,所以默认值不生效
- 上面代码,一个数组等于null,是不严格等于
-
解构的对象案例
let {foo,bar} ={foo:'小明',bar:99}; console.log(foo);//小明 console.log(bar);//99
-
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。例如:
let {bar}={brr:'1000'} console.log(bar);//undefined
-
-
对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。
// 例一 let { log, sin, cos } = Math; // 例二 const { log } = console; log('hello') // hello
-
对象的解构其实是下面代码的简写
let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' }; console.log(foo)//aaa
let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; baz // "aaa" foo // error: foo is not defined
-
上面代码中,
foo
是匹配的模式,baz
才是变量。真正被赋值的是变量baz
,而不是模式foo
。 -
上面代码有三次解构赋值,分别是对
loc
、start
、line
三个属性的解构赋值。注意,最后一次对line
属性的解构赋值之中,只有line
是变量,loc
和start
都是模式,不是变量。
-
sole.log(foo)//aaa
```js
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined
-
上面代码中,
foo
是匹配的模式,baz
才是变量。真正被赋值的是变量baz
,而不是模式foo
。[外链图片转存中…(img-XLK8lfui-1633656564135)] -
上面代码有三次解构赋值,分别是对
loc
、start
、line
三个属性的解构赋值。注意,最后一次对line
属性的解构赋值之中,只有line
是变量,loc
和start
都是模式,不是变量。