一 let 和 const
-
ES6中可以使用let和const声明变量,用法类似于var
-
const声明的为常量,不可修改(但声明对象,对象中的属性可以修改),由于这个特性,它需要在声明的同时就赋值,否则报错
-
实际开发中建议用const,当知道变量值需要被修改的情况下使用let
1.1 块级作用域
暂时性死区: 在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为暂时性死区(temporal dead zone,简称 TDZ)
- let声明的变量,只在let命令所在的代码块内有效
{
let a = 10;
var b = 20;
}
console.log(a); //a is not defined
console.log(b); //20
1.2 不存在变量提升
-
var命令会发生变量提升现象,即变量可以在声明之前使用,值为undefined
-
ES6 中let命令改变了语法行为,它所声明的变量一定在声明后使用,否则报错
//var的情况
console.log(c); //输出undefined
var c = 30;
//let的情况
console.log(c); // 报错ReferenceError
let c = 30;
1.3 不允许重复声明
- let不允许在相同作用域内,重复声明同一个变量
let c = 10;
let c = 30;
console.log(c); //报错
function func(arg) {
let arg; //报错
}
1.4 块级作用域的作用
- 防止外层变量覆盖内层变量
function fc(a){
console.log(a);
if(1===2){ //全真关系
var a = 'hello 猫';
}
}
var a = 10;
fc(a); //输出10
- 防止用来计数的循环遍历泄露为全局变量
var arr = [];
for(var i = 0; i < 10; i++){
arr[i] = function(){
return i;
}
}
console.log(arr[5]()); //希望输出5,但是输出10,这是因为循环结束后,i并没有消失,而用于变量提升,泄露成了全局变量。
解决循环计数问题
//解决方式一:使用闭包
var arr = []
for(var i = 0; i < 10; i++){
arr[i] = (function(n){
return function(){
return n;
}
})(i)
}
//解决方式二:使用let声明i
var arr = []
for(let i = 0; i < 10; i++){
arr[i] = function () {
return i;
}
}
二 运算符
2.1 模板运算符
ES6之前输出模板通常这么写
const oBox = document.querySelector('.box');
// 模板字符串
let id = 1,
name = '做一只猫';
let htmlTel = "<ul><li><p>id:" + id + "</p><p>name:" + name + "</p></li></ul>"; //这么写比较麻烦
oBox.innerHTML = htmlTel;
ES6引入了模板字符串解决这个问题
const oBox = document.querySelector('.box');
//将文本用反单引号整个括起来
let htmlTel = `<ul>
<li>
<p>id:${id}</p>
<p>name:${name}</p>
</li>
</ul>`;
oBox.innerHTML = htmlTel;
2.2 剩余运算符 / 剩余参数
剩余运算符: 将多个独立的项合并到一个数组中
ES5传统写法:
let book = {
title : 'ES6笔记汇集',
author: '做一只猫'
}
function pick(obj){
let result = Object.create(null);
for(let i = 0; i < aruguments.length; i++){
result[arguments[i]] = obj[keys[arguments[i]];
//console.log(arguments[i]);
}
return result;
};
let bookData = pick(book, 'author', 'year');
console.log(bookData);
ES6提供了剩余参数的写法
function pick(obj,...keys){
let result = Object.create(null);
for(let i = 0; i < keys.length; i++){
result[keys[i]] = obj[keys[i]];
}
return result;
};
let bookData = pick(book, 'author', 'year');
console.log(bookData);
这么看起来可能感觉这个剩余参数好像只是方便了点,但其实本质有很大区别,可以写一个函数调用看一下
function check(...args){
console.log(args);
console.log(arguments);
};
check('a','b','c');
返回结果:
可以看到,剩余参数返回的是一个数组,而arguments返回的是一个伪数组。
2.3 扩展运算符
扩展运算符: 将一个数组进行分割,并将各个项作为参数传递给函数
例: 找出数组中的最大值
const arr = [10, 20, 50, 60, 100];
//ES5写法:
console.log(Math.max.apply(null,arr));
//ES6写法:
//...将arr数组作分隔,并传回作为函数参数
consoloe.log(Math.max(...arr));
三 箭头函数
3.1 箭头函数的基本运用
//1常规写法(省略了function)
let add = (a, b) =>{
return a + b;
}
//2 小括号()代替return
let add = val => val; //只有一个参数,一个返回值时不需要加小括号
let add = (val1, val2) => (val1 + val2);
let fn = () => 'hello world' + 123; //串起来也是一个字符串,所以返回值还是只有一个
//返回对象
let po = id => {
return{
id: id,
name: '做一只猫'
}
}
//简便写法:
let po = id => ({id: id,name: '做一只猫'})
3.2 箭头函数的注意事项
3.2.1 箭头函数没有this指向,其内部的this只能通过查找作用域链的方法来确定作用域,即一旦使用箭头函数,当前不存在作用域
指向问题
let test = {
id: 123,
//构造函数
init: function () {
document.addEventListener('click', function () {
console.log(this);
this.sayHi();
})
},
saiHi: function () {
console.log('hi');
}
}
test.init();
输出:
可以发现,this指向的是document对象,所以无法调用test作用域中的saiHi()
ES5处理方法
let test = {
id: 123,
//构造函数
init: function () {
document.addEventListener('click', function () {
console.log(this);
this.sayHi();
}.bind(this),false)
},
saiHi: function () {
console.log('hi');
}
}
test.init();
用箭头函数改进
let test = {
id: 123,
//构造函数
init: function () {
document.addEventListener('click', () => {
console.log(this);
this.sayHi();
})
},
saiHi: function () {
console.log('hi');
}
}
test.init();
这是因为箭头函数没有this指向,作用域链向上,找到init作为其作用域,所以init指向的this就是test
3.2.2 构造函数不能使用箭头函数
let test = {
id: 123,
//构造函数
init: ()=>{
document.addEventListener('click', () => {
console.log(this);
this.sayHi();
})
},
saiHi: function () {
console.log('hi');
}
}
test.init();
输出:
由于使用箭头函数,此时init向上寻找作用域,找到window,this指向Window
3.2.3 箭头函数内部不存在arguments
let getVal = (a, b) => {
console.log(arguments);
return a + b;
}
console.log(getVal(1, 3));
输出:
因为此时this指向Window
3.2.4 箭头函数内部不能使用new关键字来实例化对象
因为function函数是一个对象,而箭头函数不是一个对象,只相当于一个语法槽
let Person = () => {};
let p = new Person();
输出:
四 解构赋值
- 解构赋值是对赋值运算符的一种扩展
- 通常对针对数组和对象进行操作
- 优点:代码书写简洁且易读性高
4.1 数组解构
在以前,为变量赋值,只能直接指定值
let a = 1;
let b = 2;
let c = 3;
ES6允许我们这样写:
let [a,b,c] = [1,2,3];
//这样就可以把a, c, c分别拿出来用了
如果解构不成功,变量的值就等于undefined,如下 aimer的值都会等于undefined
let [aimer] = [];
let [bar, aiemr] = [1];
4.2 对象解构
对象解构
let node = {
type: 'identifier',
name: '做一只猫'
}
//之前的写法
let type = node.type;
let name = node.name;
//ES6写法
let {type, name} = node;
console.log(type, name); //输出 identifier 做一只猫
对象的解构赋值时,可以对属性忽略和使用剩余运算符
let obj = {
a:{
name:'张三'
},
b:[],
c:'hello world'
}
//可忽略 忽略b,c属性
let {a} = obj;
//剩余运算符 使用此法将其它属性展开到一个对象中存储
let {a,...res} = obj;
console.log(a,res);
4.3 解构函数参数 / 赋默认值
let {a, b = 10} = {a: 20};
//函数参数解构赋值
//本例中函数参数为一个数组
function add([x, y]){
return x + y;
}
add([1, 2]); //解构数组,分别赋给x1, y2,再调用x + y,最终输出结果为3
//默认值作参数
function addCart(n, num = 0){
return n + num;
}
addCart(10); //输出10
addCart(10, 20); //输出30
4.4 用途
4.4.1 交换变量的值
let x = 1;
let y = 2;
let [x, y] = [y, x];
上面代码交换变量x和y的值,这样的写法不仅简洁,而且易读,语义非常清晰。
4.4.2 从函数返回多个值
函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回,而有了解构赋值,取出这些值就非常方便。
// 返回一个数组
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
// 返回一个对象
function example() {
return {
foo: 1,
bar: 2
};
}
let {foo, bar} = example();
4.4.3 为函数参数解构赋值
解构赋值可以方便地将一组参数与变量名对应起来
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
4.4.4 提取JSON数据
解构赋值对提取 JSON 对象中的数据,尤其有用
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
//对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。
//这里data起了一个别名为number,真正被赋值的是后者,而不是前者
console.log(id, status, number); // 输出42, "OK", [867, 5309]
4.4.5 输入模块的指定方法
加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。
const {ajax} = require('xxx')
ajax()
五 函数的扩展
5.1
let man{
name: name,
age: age
}
//ES6中,键值对一样可以简写为:
let man{
name,
age
}
//函数返回对象简写
function(x, y){
return{x, y}; //本来是x: x,
}
//函数简写
let cart = {
wheel: 4,
//省去function
set(newVal){
if(newVal < this.wheel){
//抛出错误
throw new Error('轮子太少');
}
this.wheel = newVal;
}
get(){
return this.wheel;
}
}
cart.set(3);
(本文未完结,从草稿箱里翻出来的,索性发了)