目录
声明与表达式
1、let与const
(1)let命令
(2)const命令
(3)注意要点
2、解构赋值
(1)概述
(2)解构模型
(3)数组模型的结构(Array)
(4)对象模型的结构(Object)
2039年
h5制定
修饰自定义的标识符: let const var function
笔试题——var let const
var let const 的相同点:
三者都可以声明变量
var let const 的区别:
1.变量提升
var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined
let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错
2.块级作用域
var不存在块级作用域
let和const存在块级作用域
3.重复声明
var允许重复声明变量
let和const在同一作用域不允许重复声明变量
4.修改声明的变量
var和let可以
const声明一个只读的常量。一旦声明,常量的值就不能改变,但对于对象和数据这种引用类型,内存地址不能修改,可以修改里面的值。
ES6新增加了两个重要的 JavaScript 关键字: let 和 const。
let 声明的变量只在 let 命令所在的代码块内有效(块级作用域、局部作用),ES6 推荐在函数中使用 let 定义变量,而非 var。
const 声明一个只读的常量,一旦声明,常量的值就不能改变。
基本用法:
//{}括起来的代码块
{
let a = 0;
console.log(a); // 0
}
console.log(a); // 报错 ReferenceError: a is not defined
代码块内有效:
(es5代码块没有作用域) ES6中代码块中let有作用域 不同作用域去取变量会报错
{
let a = 0;
var b = 1;
}
console.log(b); // 1
console.log(a); // ReferenceError: a is not defined 报错
不能重复声明
同一个作用域内,定义重复变量,会报错:a已经被定义了
let不可以重复声明,但是可以重复赋值。
var a = 1;
var a = 2;
console.log(a); // 2
let b = 3;
let b = 4;
console.log(b); // Identifier 'a' has already been declared 报错:a已经被定义了
var i=1
let i=1
console.log(i) //Uncaught SyntaxError: Identifier 'i' has already been declared
for循环计数器很适合用let
for (var i = 0; i < 10; i++) {
setTimeout(function(){
console.log(i);
})
}
// 输出十个 10
for (let j = 0; j < 10; j++) {
setTimeout(function(){
console.log(j);
})
}
// 输出 0~9
变量 i 是用 var 声明的,在全局范围内有效,所以全局中只有一个变量 i, 每次循环时,setTimeout 定时器里面的 i 指的是全局变量 i ,而循环里的十个 setTimeout 是在循环结束后才执行,所以此时的 i 都是 10。
变量 j 是用 let 声明的,当前的 j 只在本轮循环中有效,每次循环的 j 其实都是一个新的变量,所以 setTimeout 定时器里面的 j 其实是不同的变量,即最后输出0~9。(若每次循环的变量 j 都是重新声明的,如何知道前一个循环的值?这是因为 JavaScript 引擎内部会记住前一个循环的值)。
不存在变量提升
console.log(a); //undefined
var a = "banana";
console.log(b); //ReferenceError: b is not defined
let b = "apple";
变量 a 用 var 声明存在变量提升,所以当脚本开始运行的时候,a 已经存在了,但是还没有赋值,所以会输出 undefined。
变量 b 用 let 声明不存在变量提升,在声明变量 b 之前,b 不存在,所以会报错。
与let不同: 不能重新赋值
const a=1; a=100; 会报错,不能重新赋值
const 声明一个只读变量,声明之后不允许改变。意味着,一旦声明必须初始化,否则会报错。
const a; 会报错: 没有初始化
(初始化:第一次赋值,var b只是声明,没有赋值,所以要 b = 2才是初始化)
//对象是引用数据,没有改变存储空间就可以
const obj = {
name:"karen"
}
obj.age=20
console.log(obj) //{name: 'karen', age: 20}
基本用法:
const PI = "3.1415926";
console.log(PI); // 3.1415926
const MY_AGE; // SyntaxError: Missing initializer in const declaration
暂时性死区:
var PI = "a";
if (true) {
console.log(PI); // ReferenceError: PI is not defined
const PI = "3.1415926";
} //因为里面有const,就把大括号看成一个函数了,让其有作用域了,就没有去外面找PI
ES6 明确规定,代码块内如果存在 let 或者 const,代码块会对这些命令声明的变量从块的开始就形成一个封闭作用域。代码块内,在声明变量 PI 之前使用它会报错。
let 和const 关键词声明的变量不具备变量提升(hoisting)特性
let 和 const 声明只在最靠近的一个块中(花括号内)有效
当使用常量 const 声明时,请使用大写变量(也不是必须),如:CAPITAL_CASING
const 在声明时必须被赋值
const 如何做到变量在声明初始化之后不允许改变的?使用 const 声明复杂类型对象时要慎重。
{
const ARR = [5,6];
ARR.push(7);
console.log(ARR); // [5,6,7]
ARR = 10; // TypeError
}
严格模式下函数不会隐式提升,变量会提升==> 所以 尽量不在if里面声明变量函数,但是可以用let
//非严格模式下:
笔试题——let、提前声明、if、赋值
//脚本运行初 在全局作用域先扫描关键字var a; //1 console.log(a) //und if(false) { //写true也为und 无论if成立与否,下面的var a是要提升的,false的话就是下面a不赋值 var a=0 } //2 console.log(a); //und console.log(b); //报错 Uncaught ReferenceError: b is not defined if(true){ var a=0; let b=0; } //3 if(true){ var a=0; let b=0; } console.log(a); //0 console.log(b); //报错 Uncaught ReferenceError: b is not defined
解构赋值是对赋值运算符的扩展。
是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。
声明标识符,按照某种数据模型 解析并赋值给声明的标识符(变量)
解构有默认值
在解构中,有下面两部分参与:
解构的源,解构赋值表达式的右边部分。
解构的目标,解构赋值表达式的左边部分。
基本
let [a, b, c] = [1, 2, 3]; console.log(a, b, c); //1 2 3
可嵌套
let [a, [[b], c]] = [1, [[2], 3]]; console.log(a, b, c); //1 2 3
可忽略
let [a, , b] = [1, 2, 3]; console.log(a, b); //1 3
不完全解构
let [a = 1, b] = []; // a = 1, b = undefined
剩余运算符
let [a, ...b] = [1, 2, 3]; console.log(a, b); //a = 1, b = [2,3]
字符串
在数组的解构中,解构的目标若为可遍历对象,皆可进行解构赋值。可遍历对象即实现 Iterator 接口的数据。
let [a, b, c, d, e] = 'hello'; console.log(a, b, c, d, e); //h e l l o
解构默认值
let [a = 2] = [undefined]; // a = 2
当解构模式有匹配结果,且匹配结果是 undefined 时,会触发默认值作为返回结果。
let [a = 3, b = a] = []; // a = 3, b = 3 let [a = 3, b = a] = [1]; // a = 1, b = 1 let [a = 3, b = a] = [1, 2]; // a = 1, b = 2
1. a 与 b 匹配结果为 undefined ,触发默认值:a = 3; b = a =3
2. a 正常解构赋值,匹配结果:a = 1,b 匹配结果 undefined ,触发默认值:b = a =1
3. a 与 b 正常解构赋值,匹配结果:a = 1,b = 2
笔试题:
function fn(fm = function fg(a) { console.log(a, b) //Uncaught ReferenceError: b is not defined }) { // console.log(a) var b = 100 fm() } fn()
基本
let { foo, bar } = { bar: 'bbb' , foo: 'aaa'}; // foo = 'aaa' // bar = 'bbb' let { baz : foo } = { baz : 'ddd' }; // foo = 'ddd'
可嵌套可忽略
let obj = {p: ['hello', {y: 'world'}] }; let {p: [x, { y }] } = obj; // x = 'hello' // y = 'world' let obj = {p: ['hello', {y: 'world'}] }; let {p: [x, { }] } = obj; // x = 'hello'
不完全解构
let obj = {p: [{y: 'world'}] }; let {p: [{ y }, x ] } = obj; // x = undefined // y = 'world'
剩余运算符
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}; // a = 10 // b = 20 // rest = {c: 30, d: 40}
解构默认值
let {a = 10, b = 5} = {a: 3}; // a = 3; b = 5; let {a: aa = 10, b: bb = 5} = {a: 3}; // aa = 3; bb = 5;
var obj={age:200,name:"karen"}
var {age,name}=obj
//隐式代码
// var age=obj.age
// var name=obj.name
console.log(age) //200
var arr=[100,200]
var [a,b]=arr
//var a=arr[0]
//arr b=arr[1]
//如果报错:什么属性,函数有问题,真正的问题是调用的问题
var {x1:{x2},x3}=obj3
// var x1=obj3.x1
// var x2=obj3.x1.x2 //报错 因为obj.x1是undef,然后用undef.x2就会报错
// var x3=obj3.x3
function fn({x,y}) {
//{x,y}=obj
console.log(x)
console.log(x)
}
var obj={x:100,y:200}
fn(obj)
let [a,{son:[{age,s2:{son:[x1,y1]}}]}]=obj
// let y1=obj[1].son[0].s2.son[1]
let [pwd,setpwd] =fn()
setpwd(pwd)
//根据这两行代码就知道:fn()返回值是数组,arr[1]是一个函数,就可以设计为:
function fn(){
return [1,function(arg){}]
}
var arr=[1,2,3,5]
var {a,b,length}=arr
console.log(length) //4
let arr[0].age=90; //错误,因为这是赋值,赋值应该写在右边
let [{age}]=80; //这个是可以的
let obj={a:20}
let {a=10}=obj
//隐式操作:let a=10; a=obj.a;
console.log(a) //20
let obj={}
let {a=10}=obj
//隐式操作:let a=10; a=obj.a;
console.log(a) //10
// undefined是ES6的一个bug
// let obj={a:undefined}
// let obj={a:0}
let obj={a:null}
let {a=10}=obj //这个是默认值。下面会先取自己的值,然后取默认值
//隐式操作:let a=10; a=obj.a;
console.log(a) //10 0 null
重点:
let arr1=[x=100,y=200] //解析声明变量名字叫arr1 值是数组(初始化) 数组第一个值是一个赋值表达式:表达100 同理:200 let [a=10,b=20]=arr1 //声明了两个变量:let a=10,let b=20 //然后执行解构: //if(arr1[0]!=undefined){a=arr1[0]}; //if(arr1[0=1]!=undefined){b=arr1[1]} console.log(a,b,x,y) //100 200 100 200
解构赋值只会声明最小层的变量,外面的不会声明,去打印外层会报错
//s1是里面的,所以let声明的是s1,sons没有声明,所以报错 let obj={name:"karen",age:22,sons:[{name:"jack",age:1}]} let {name,sons:[s1]}=obj console.log(name) //karen console.log(s1) //{name: 'jack', age: 1} console.log(sons) //Uncaught ReferenceError: sons is not defined
let不能修饰两个相同的变量,所以报错
let obj={name:"karen",age:22,sons:[{name:"jack",age:1}]} let {name,sons:[{age,name}]}=obj console.log(age) //Uncaught SyntaxError: Identifier 'name' has already been declared console.log(name)