9.15 ES6-变量-常量-块级作用域-解构赋值-箭头函数
变量Let
ES5作用域: 全局作用域,函数作用域(局部作用域) ES6新增 let: 定义变量
-
定义块级作用域 {}
-
在同一块级作用域不能重复声明
const: 定义常量
-
声明必须赋值
-
不允许更改
块级作用域
花括号包括起来的就是块,就是块语法,大家比较常见的可能是if(){},for(){}这都是语法块,块级作用域 特点1: 同一个代码块中不允许声明同名的变量
let a = 10;
var b = 100;
let a = 100;
console.log(a);
注意2: let声明的是一个变量,变量是可读可改的,能修改
let a=200;
a = 'hello'
console.log(a) // hello
注意3: let 声明的变量, 不存在 声明前置
console.log(c);// 报错
let c = 5;
console.log(c);
注意4: 通过 let 声明的变量只在 let 命令所在的代码块内有效
ES 6中变量的作用域: 块级作用域 ----- {}
if(true){let a=12
}
alert(a);// 报错,a只在上面的语法块中才有用
案例:块级作用域怎么用
<script>
window.onload=function(){var aBtn=document.getElementsByTagName('input');for(var i=0;i<aBtn.length;i++){aBtn[i].index=i; // 存储i下标值aBtn[i].onclick=function(){console.log(i); // 每次打印出来的都是3console.log(this.index); // 0,1,2}}
}
</script>
<input type="button" value="按钮1"/>
<input type="button" value="按钮2"/>
<input type="button" value="按钮3"/>
<script>
for(let i=0;i<aBtn.length;i++){aBtn[i].onclick=function(){console.log(i); // 0,1,2}
}
</script>
暂时性死区: 在代码块内, 使用 let 声明变量之前, 该变量是不可用的
常量const
const 用于声明一个只读的常量
注意一:同一个代码块中不允许声明同名的变量
const a=100;
const a=200; // 报错,不能重复定义
console.log(a);
注意二:const声明的是一个常量,常量只读不改
const PIM = 3.14;
// PIM = 3;// 报错
console.log(PIM);
注意三:块级作用域,只在花括号里面有效
if(true){const a=12
}
alert(a);//报错
注意四: 如果 const 保存的是数组/对象/函数等 空间的地址时, 只能保证 所保存的地址不变, 地址中的值, 无法控制.
let numArr = [9, 5, 2, 7];// [9,5,2,7]
const arrP = numArr;
numArr[0] = 99;
console.log(arrP);// [99,5,2,7]
console.log(numArr); // [99,5,2,7]
面试题:let,const,var的区别
![[2dfb7dec-5e46-4b03-b2eb-9293ab676441.png]]
解构赋值【拆解架构,重新赋值】
ES 6允许按照一定的模式, 从数组和对象中提取值, 然后对变量进行赋值. 解构赋值分为数组的解构赋值、对象的解构赋值、字符串的解构赋值、数值和布尔值的解构赋值、函数参数的解构赋值、函数的参数的解构赋值
解构赋值的本质: 模式匹配. 只要 = 两侧的模式相同, 左侧的变量就可以被赋予对应的值.
数组的结构
- 原始方法的解构赋值
let arr=[1,2,3];
let a=arr[0];
let b=arr[1];
let c=arr[2];
console.log(a,b,c)
- 使用解构赋值
// 方法一
{let [a,b,c]=[1,2,3];console.log(a,b,c)
}
// 方法二
{let a,b,c;[a,b,c]=[1,2,3];console.log(a,b,c)
}
// 错误示范
let [a,b,c,d];
[a, b, c, d] = [9, 5, 2, 7];
console.log(a, b, c, d);
- 不完全解构
let arr = [4, 7, 9, 3];
let [num1,num2] = arr;
let [,num1,num2] = arr;
let [num1,num2,...num3] = arr;
let [num1, , , num2] = arr;
console.log(num1, num2);
- 解构失败
let [aName] = [];
console.log(aName);// undefined
- 不定长度的解构赋值
let color = ['red','green','blue','pink','black','white'];
let [col1,...col2] = color;
console.log(col1,col2);
对象的解构赋值
注意:对象的解构赋值与数组有一个重要的不同, 数组的元素是按顺序排列的, 变量的取值由先后位置决定, 而对象的属性没有次序, 只要键名匹配成功即可完成赋值
- 变量名与键名一致(对象的字面量表示法)
let {brand, price} = {brand: '宝马', price: 740};
let {price,brand}={brand:'宝马',price:250};
console.log(brand, price);
- 变量名与键名不一致
let {brand: a, price: b} = {brand: '宝马', price: 740};
console.log(a, b);
- 同一个对象给六个变量赋值
let dataObj = {codeNum: '200',codeMsg: 'ok',data: [{name: '刘德华', age: 60},{name: '刘德华', age: 60}]
};
let {codeNum, data, data: listObj, data: [dataPer], data:[{name, age}]} = dataObj;
注意:已经声明过的变量, 用于解构赋值时要特别小心. {} 很容易被系统识别
字符串的解构赋值
字符串能够使用解构赋值的原因是: 字符串时特殊的数组(字符串能够被转换成一个类似数组的对象)
let [a, b, c, d, e] = "Hello";
console.log(a, b, c, d, e);
解构赋值的用途
- 交换变量的值
let a = 3, b = 5;
[a, b] = [b, a];
console.log(a, b);
- 从函数内部返回多个值
let {dataObj} = {code: 200, msg: 'ok', dataObj: ['jack','rose','bob','小明']};
console.log(dataObj);
- 可以迅速提取一个对象中的方法;
let {floor, random, sin} = Math;
console.log('======');
console.log(Math.floor(Math.random() * 256)); // 原来的操作
console.log(floor(random() * 256)); // 现在的操作
箭头函数
箭头函数也称为也称为胖箭头函数; 箭头函数的基本语法:()=>{}
定义箭头函数
- 通过事件直接调用匿名函数
window.onload=function(){alert('abc');
}
window.onload=()=>{alert('abc')
}
- 通过赋值的方式创建函数
let show=function(){alert('abc');
}
let show=()=>{alert('abc');
}
show();
- 可以传参的箭头函数
let show=function(a,b){alert(a+b);
}
show(12,6);
let show=(a,b)=>{alert(a+b);
}
show(12,6);
案例:给下面数组排序
let arr=[12,5,3,67,23,99,14,25];// 正序排序
// 普通方法
arr.sort(function(a,b){return a-b;
});
// 改写为箭头函数
arr.sort((a,b)=>{return a-b
);
alert(arr);
但是这里面几个注意事项: A. 如果只有一个参数,()可以省 B. 如果只有一条语句,{}可以省 C. 只有一条语句的时候,并且使用return进行返回,不仅{}可以省略,return也可以省略 D.在箭头函数中不能使用arguments,使用展开运算符 |
注意一:如果只有一个参数,()可以省
// 求一个数的平方是多少
let show=function(a){alert(a*2)
}
// 简写成箭头函数
let show=(a)=>{alert(a*2)
}
// 强调:只有一个参数,就可以省略(),强调一下,只有一个多了不行,少了也不行
let show=a=>{alert(a*2)
}
show(12);
注意二:如果只有一条语句,{}可以省略
let show=a=>alert(a*2) // 意思很明白:进去是a,吐出来是2*2
show(12);
注意三:如果只有一条语句,并且是用return进行返回,不仅{}可以省略,return也可以省略
let show=a=>(a*2) // 意思很明白:进去是a,吐出来是2*2
alert(show(12));
案例:添加一个函数,功能2秒钟之后改变页面的背景颜色
注意四:不能使用arguments
function gets(){console.log(arguments);
}
let gets=()=>{console.log(arguments);
}
gets(12,34,23,4);
箭头函数使用注意事项: 函数体内 this 是定义时所在的对象, 不再是使用时所在的对象(此时 this 变成一个静态的值了)
箭头函数的默认值
- 参数的默认值不是传值, 而是每次都会重新计算
let x = 100;
function fun2(a = x + 1) {console.log(a);
}
fun2();// 101
x = 1000;
fun2();// 1001
- 一般设置默认值的参数应该是函数的尾参数
function fun3(a, b = 3) {console.log(a, b);
}
fun3(5);
获取剩余(rest)参数 【…args 】,等同于ES5中的arguments
ES5中的arguments和ES6中rest剩余参数的区别是:argument中是伪数组,rest中是真数组
function total(...args){// ES5:// console.log(arguments) //伪数组// args: 真数组console.log(args instanceof Array);console.log(args);
}
其实就是展开运算符 + 变量名
show=(a,b,...args)=>{alert(a);alert(b);alert(args)
}
show(12,15,23,43,11);
注意:…args 必须是最后一个行参 箭头函数没有arguments,如果箭头函数的外层又普通函数,那么arguments会获取外层普通函数的实参
函数的两个属性
ES6里面提供了函数的两个属性,分别是:length和name
length: 获取数组中参数的长度 但是,如果参数指定了默认值,函数的length属性将返回没有指定默认值的参数个数
function fun(a, b,c,d) {
}
console.log(fun.length);
Name: 函数的name属性,返回该函数的函数名
function fun1() {
}
console.log(fun1.name);
注意一:使用匿名函数表达式的方法定义的函数,它的name属性值就是变量的名字
let fun2 = function(argument){
}
console.log(fun2.name) //fun2
注意二:函数声明的优先级高于变量名
let superFun3 = function fun3(argument){
}
console.log(superFun3.name) //fun3
// 调用的时候变量名的优先级高
箭头函数的this指向
- 箭头函数的this指向
箭头函数的this指向 是 父级程序的this指向 如果没有父级程序 或者 父级程序没有指向 箭头函数的this指向是window
<button>登陆</button>
<script>var btn = document.querySelector('button');// 1. 匿名函数绑定的事件处理函数 this指向默认是事件源 也就是div标签对象btn.addEventListener('click' , function(){console.log(this); // btn元素本身})// 2. 箭头函数的this指向,是父级程序的this指向,下面的箭头函数没有父级程序,所以this指向是windowbtn.addEventListener('click' , ()=>{console.log(this); // window对象})
</script>
- 对象中定义的函数 和箭头函
var obj={name:18,sayhi:()=>{console.log(this);},eat:function(){console.log(this);}
}
obj.sayhi();
obj.eat();
- 在箭头函数中不能通过函数【call/apply/bind】方法,修改this指向
call:函数调用.call(参数1,参数2,参数3…)
参数1:要改变的指向 之后的参数2,参数3…是原始函数需要的数据
apply:函数调用.apply(参数1,[参数2,参数3…])
参数1:要改变的this指向 之后的所有参数以数组的形式赋值 原始函数需要的数据
总结:call和apply执行程序的原理、结果都完全一致,只是给原始函数赋值参数的语法形式不同
bind:bind(参数1,参数2,参数3…)
参数1:新的this指向 之后所有的参数 参数2,参数3…都是原始函数需要的参数数据
var obj = {name: 18,sayhi: () => {console.log(this);},eat: function () {console.log(this);}
}
obj.sayhi();
obj.sayhi.call(111);
obj.eat();
obj.eat.call(111);
总结:箭头函数没有this,它的this取决于作用域链上的this,它不可以通过 bind 等方法改变this 指向。
不能通过new关键字调用
javascript函数有两个内部方法:Call和Construct.
当通过new调出函数时,执行Construct方法,创建一个实例对象,然后再执行函数体,将this绑定到实例上。
当直接调用的时候,执行Call方法,直接执行函数体。 箭头函数并没有Construct方法,不能被用作构造函数,如果通过new的方式调用,会直接报错。
let foo1 = () => {};
let foo2 = new foo1(); //TypeError: foo1 is not a constructor
is not a constructor
没有原型
由于不能使用new调用函数,所以也没有构建原型的需求,于是箭头函数也不存在prototype这个属性。
let foo = () => {};
console.log(foo.prototype); //undefined
总结:
-
没有this,捕捉其所在的上下文的this值,作为自己的this
-
不能绑定arguments, 用rest参数 … 解决
-
箭头函数没有原型属性