ES6详解

一 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 = "
  • id:" + id + "

    name:" + name + "

"
; //这么写比较麻烦 oBox.innerHTML = htmlTel;

ES6引入了模板字符串解决这个问题

const oBox = document.querySelector('.box');
//将文本用反单引号整个括起来
let htmlTel = `
  • id:${id}

    name:${name}

`
; 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();

输出:
ES6详解_第1张图片
可以发现,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);			

(本文未完结,从草稿箱里翻出来的,索性发了)

你可能感兴趣的:(es6,前端,javascript)