04-ES6

let和const命令

ES6中新增了let命令,用来声明变量,用法类似与var

let和var的不同:

1、不存在变量提升

console.log(a); //Cannot access 'a' before initialization

let a = 100;

2、同一个作用域不能重复定义同一个名称

var c = 20;

let c = 30;

console.log(c);//Identifier 'c' has already been declared

3、有严格的作用域

function fn() {

var a = "a";

if (true) {

var a = "b";

}

console.log(a);//b

}

fn();

function fn() {

var a = "a";

//ES6中引入了块级作用域,var a 和let a不在一个作用域中

if (true) {

let a = "b";

}

console.log(a);//a

}

fn();

4、块级作用域的重要性

//for循环的i会提升为全局变量

for (var i = 0; i < 5; i++) {}

console.log(i); //5

for (let i = 0; i < 5; i++) {} //i的作用域范围只能在for循环的过程中

console.log(i); //i is not defined

const的使用

const 声明一个只读的常量。一旦声明,常量的值就不能改变。

保持let的不存在变量提升,同一个作用域内不能重复定义同一个名称,有着严格的作用域;

常量obj储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把obj指向另一个地址, 但对象本身是可变的,所以依然可以为其添加新属性

const x = 10;//如果声明的是常量,则不能修改

x = 100; //Assignment to constant variable.

console.log(x);

const y;//Missing initializer in const declaration const声明变量时,需要立即初始化

console.log(y);

//const声明引用类型,可以对值进行修改

const arr = [1,2,3,4];

arr[0] = 100;

console.log(arr);

const obj = {};

obj.id = 1;

console.log(obj);

解构

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)

解构是ES6的新特性, 比ES5代码简洁,清晰,减少代码量

数组解构

左边模式匹配,定义变量,右边是定义的数组或者对象

let [a, b, c] = [1, 2, 3];

let [a2, b2, c2, d2] = ["red", "blue", "green"];

let [x, [y1, y2], z] = [1, [2, 3], 4];

let arr = [100, 200];

var x = arr[0] || 1;

//默认值写法

let [x = 1] = arr; //arr[0]存在在解构成x,如果不存在,则赋值为1

//当值是undefined的时候,才会触发默认值机制

let [x = 1] = [undefined, undefined];

console.log(x);//1

var [y = 1, z] = [100, null];

console.log(y,z);//100 null

//默认值如果是表达式【函数】,值在用到的时候,才会执行,惰性求值

var [y = 1, z = f()] = [100, 200];

console.log(y,z);//100,200

对象解构

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对 象的属性没有次序,变量必须与属性同名,才能取到正确的值

对象解构的写法:let { id, name } = { id: 1, name: "jack" };

如果没有对应的属性名,则返回undefined

//id:_id 别名

let { id:_id, name:_name } = { id: 1, name: "jack" };

//i为undefined,则返回1

let { id: _id, name: _name, i = 1 } = { id: 1, name: "jack" };

let { x = 10 } = {};

console.log(x);//10

let { x:a = 10 } = {};

console.log(x);//x is not defined,x是匹配模式,真正的变量是a

//解构用于方法入参

const fn = ({ count, num }) => num + count;

var obj = { count: 100, num: 99 };

let sumcount = fn(obj);

console.log(sumcount);

//累加&解构

let obj = { id: 1, msg: "error", arr: [5, 6, 7, 8] };

const sum = ({ id, arr }) =>

arr.reduce((total, current) => total + current, id);

console.log(sum(obj));

如果要将一个已经声明的变量用于解构赋值,必须非常小心

//报错的原因:因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在 行首,避免 JavaScript 将其解释为代码块,才能解决这个问题

let x;

{x} = {x:1};//编译错误

console.log(x);

正确写法:

let x;

({x} = {x: 1});

将整个解构赋值语句,放在一个圆括号里面,就可以正确执行

函数参数解构

//数组参数解构

function sum([x = 0, y = 0]=[]) {

return x + y;

}

函数参数 [x = 0, y = 0] = [] 表示:

  • 参数是一个数组,默认值为空数组 []
  • 如果传入的数组没有第一个元素,x默认为0
  • 如果传入的数组没有第二个元素,y默认为0

sum();//0+0=0

sum([1]);//1+0=1;

sum([1,2]);

//对象参数解构

function fn2({ x = 1, y = 2 } = {}) {

console.log(x + y);

}

var obj = { x: 10, y: 20 };

fn2(obj);

扩展

字符串扩展

includes(): 返回布尔值,表示是否找到了参数字符串。

startsWith(): 返回布尔值,表示参数字符串是否在原字符串的头部。

endsWith(): 返回布尔值,表示参数字符串是否在原字符串的尾部

repeat(): 返回一个新字符串,表示将原字符串重复n次。

padStart(): 用于头部补全

padEnd(): 用于尾部补全

数值扩展

Number.parseInt("100");

Number.parseFloat("100.01");

//用来判断数字是否是一个整数,返回bool

Number.isInteger(100.01);

Math.ceil() 返回大于或等于一个给定数字的最小整数,ES5

Math.floor() 返回小于或等于一个给定数字的最大整数,ES5

Math.round() 返回一个数字四舍五入后最接近的整数,ES5

//ES6

Math.trunc() 用于去除一个数的小数部分,返回整数部分

Math.sign() 方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数 值

//运算符:**,指数运算符

2**3 = 8

数组扩展

//用于将一组值,转换为数组

var v = Array.of(); //[]

var v = Array.of(1, 2, 3); //[1,2,3]
//ES6

var v = Array.of(); //[]

var v = Array.of(1, 2, 3); //[1,2,3]

//创建指定长度的数组,ES5

var v = new Array(3);//参数是数字,则是数组长度

console.log(v.length);

//创建一个数组,数组内的元素是字符3,ES5

var v1 = new Array("3");

console.log(v1);

//find()用于找出第一个符合条件的数组成员

//find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组

var arr = [3, 4, 7, 9];

var a = arr.find((value, index, arr) => {

return value > 5;

});

//findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,

// 如果所有成员都不符合条件,则返回-1

var arr = [3, 4, 7, 9];

var a = arr.find(function (item, index, arr) {

//返回第一个符合条件的数组成员的位置

return item > 5;

});

//用于将一个固定值替换数组的元素

var arr = ["blue", "Orange", "red", "green"];

arr.fill("abc", 2, 4); //["blue", "Orange", "abc", "abc"]

//方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的 includes 方法类似

1, 2, 3\].includes(2); // true \[(1, 2, 3)\].includes(4); // false var arr = \["blue", "Orange", "red", "green"\]; arr.includes("blue"); //true //用于将嵌套的数组"拉平",变成一维的数组 var v = \[1, 2, \[3, 4\], 5, \[6, 7, 8\]\].flat(); //\[1, 2, 3, 4, 5, 6, 7, 8

对象扩展

//对象属性2种定义方式

var o = {};

o.name = "xp";

let v = "age";

o[v] = 20; //这种定义v指的是变量

console.log(o);

//对象属性定义方式

let age = "age1";

o = {

age\]: 22, }; console.log(o); //链判断运算符 let firstName = message.body.user.firstName; //可以这样写,但是不规范,没有对数据的存在进行校验 firstName = (message \&\& message.body \&\& message.body.user \&\& message.body.user.firstName) \|\| 'default'; //这样的层层判断非常麻烦,引入了"链判断运算符" ?.,简化上面的写法 firstName = message?.body?.user?.firstName \|\| "default"; //空值合并运算符 let info = "aaaa"; let b = info ?? "bbbb";//如果info为null或者undefined,则取很后面的值

函数扩展

函数默认参数

javascript 复制代码
  /****************ES5*************** */
  function fun(x, y) {
    y = y || 20;
    console.log(y);
  }
  fun(123);

  /****************ES6********************* */
  function fun(x, y = 10) {
    console.log(y);
  }
  fun(234);

rest参数

javascript 复制代码
  /****************arguments******************* */
  //方法的参数是动态的,使用arguments参数集合,类似与数组
  function fn() {
    console.log(arguments); //类似数组
  }
  fn(1, 2, 3);

  ////rest动态参数
  function fn(...values) {
    console.log(values);
    let filterNum = values.filter((value, index, values) => {
      return value > 20;
    });
    console.log(filterNum); //[ 222, 333 ]
  }
  fn(11, 222, 333, 13); //结果是一个标准的数组

 //报错
 function fun(a,...b,c){}
 fun(1,2,3,4)

箭头函数

javascript 复制代码
  var f = (n1, n2) => n1 + n2;
  //定义一个方法,返回一个对象
  var f = function (n1, n2) {
    return { n1, n2 };
  };
  //箭头函数写法---写法错误
  var f = (n1, n2) => {
    n1, n2;
  };
  //正确写法
  var f = (n1, n2) => {
    return { n1, n2 };
  };
  var a = f(1, 2);
  console.log(a); //{ n1: 1, n2: 2 }

  //正确写法,返回对象,需要使用()把对象包起来
  var f = (n1, n2) => ({ n1, n2 });
  var a = f(1, 2);
  console.log(a); //{ n1: 1, n2: 2 }

  ///方法入参解构
  let f = ({ x = 0, y = 0 } = {}) => {
    return [x, y];
  };
  f({ x: 3, y: 3 });
箭头函数的坑

1、箭头函数不能当成构造函数,也就是不能使用new关键字

javascript 复制代码
  //箭头函数不能当成构造函数,也就是不能使用new关键字
  var p_fn = (name, age) => {
    this.name = name;
    this.age = age;
  };
  var pfn = new p_fn("aaa", 30); //p_fn is not a constructor

2、箭头函数没有原型对象

3、不可以使用arguments对象 该对象在函数体内不存在 替代 rest

javascript 复制代码
  var f = () => {
    console.log(arguments[2]);
  };
  f(); //Uncaught ReferenceError: arguments is not defined

  //使用rest代替
  var f = (...rest) => {
    console.log(rest);
  };
  f(1, 2, 3, 4);

  function fn3() {
    console.log(arguments[1]);
  }
  fn3(1, 2, 3, 4); //2

4、this指向 由于箭头函数不绑定this,它会捕获其所在上下文的this的值,作为自己的this值

javascript 复制代码
  let x = "x";
  let y = "y";
  let obj = {
    x: "x2",
    y: "y2",
    getX: function () {
      console.log(this.x);
    },
    getY: () => {
      console.log(this); //this指向Window
      console.log(this.y);
    },
  };
  obj.getX(); //this指向obj
  obj.getY(); //undefined
  //箭头函数中this指向:
  //箭头函数中没有this,但是箭头函数会捕获所在(定义的位置)上下文的this的值。
  //这里的getY在obj对象中,obj对象定义在Window里。

尽量不要在对象的方法里写箭头函数【不确定就在箭头函数中打印this】

扩展运算符

扩展运算符是三个点...

它好比rest参数的逆运算。

扩展运算符将一个数组转为用逗号分隔的参数序列。

该运算符主要用于函数调用。

javascript 复制代码
  //合并两个数组
  let arr2 = [1, 2, 3];
  let arr3 = [4, 5];
  let arr4 = [...arr2, ...arr3];
  console.log(arr4);

  function sum(x, y) {
    return x + y;
  }
  const item = [1, 2];
  sum(...item);

/***************************************************/
  //第一种写法
  var a = [];
  function f(x, y) {
    a.push(...y);
  }
  f(a, [1, 2, 3, 4]);
  console.log(a); //[ 1, 2, 3, 4 ]

  //第二种写法
  var a = [];
  function f(x, ...y) {//这的...y是可变参数,会将参数变成数组,也就是[[1, 2, 3, 4]]
    a.push(...y);//这的...y是扩展运算符,会将[[1, 2, 3, 4]]分解成[ 1, 2, 3, 4 ]
  }
  f(a, [1, 2, 3, 4]);
  console.log(a); //[[ 1, 2, 3, 4 ]]

/**********************扩展************************ */
    let array = [
        { id: 1, name: "a" },
        { id: 3, name: "a" },
        { id: 10, name: "a" },
        { id: 4, name: "a" },
        { id: 27, name: "a" },
        { id: 50, name: "a50" },
    ];
    //求id最大的对象?
    let maxId = Math.max(...array.map((v) => v.id));
    console.log(maxId);

扩展运算符可以和解构结合起来使用

javascript 复制代码
  let [first, ...rest] = [1, 2, 3, 4, 5];
  console.log(first);//1
  console.log(rest);//[ 2, 3, 4, 5 ]

扩展运算符在对象中的使用

javascript 复制代码
  let o1 = { id: 1 };
  let o2 = { name: "o2" };
  let o3 = { ...o1, ...o2 };
  console.log(o3);//{ id: 1, name: 'o2' }