全面掌握ECMAScript新特性——ES6数组、函数、对象(二)

数组的扩展

ES6对数组进行了很多的扩展,具体如下

扩展运算符

扩展运算符是三个点(…),将一个数组转为用逗号分隔的参数序列,通常用在函数参数中。
假如我们需要一个求和函数,并且支持传入任意数量的值。

function sum(...params) {
  let sum = arr.reduce(function (prev, cur) {
    return prev + cur;
  });
  return sum;
}

let arr = [1, 2, 3, 4, 5];

console.log(sum(arr)); //输出 15

Array.from()

Array.from()方法从一个类似数组或可迭代对象创建一个新的浅拷贝的数组实例,通常有以下四种实用场景。

//一、克隆一个数组
let num = [1, 2, 3];
let newNum = Array.from(num);
console.log(newNum, num === newNum);  //[1, 2, 3] false

//二、使用指定值,初始化一个数组
//给定长度为10,默认值是数组2和对象{key:1}
let length = 4;
let defaultValue = 2;
let defaultObj = { key: 1 };
let arrValue = Array.from({ length }, (item,index) => defaultValue);
let arrObj = Array.from({ length }, (item,index) => defaultObj);
console.log(arrValue); // [2, 2, 2, 2]
console.log(JSON.stringify(arrObj)); //[{"key":1},{"key":1},{"key":1},{"key":1}]

//三、生成值范围数组
function range(end) {
  return Array.from({ length: end }, (item, index) => index);
}

let arr = range(4);
console.log(arr); // [0, 1, 2, 3]

//四、数组去重,结合set使用
let arr = [1, 1, 2, 3, 3];
let set = new Set(arr);
console.log(Array.from(set));

创建数组

如何创建一个数组,有下面几种常用方式

//一、数组字面量
const arr1 = [];

//二、构造函数
const arr2 = Array(3);  //[null,null,null]
const arr3 = Array("3");  //["3"]

//这时想要用构造函数创建一个数字为7的数组,发现上面方式是无法满足的,而ES6提供了Array.of()能满足我们的需求
const arr3 = Array.of(7);  //[7]

数组查找


find()方法返回数组中满足提供的测试函数的第一个元素的值,若没有找到对应元素返回undefined
findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引,若没有找到对应元素则返回-1。


假如我们想要在一个成绩数组中,找到达到及格分数的最低分。

const score = [34, 23, 66, 12, 90, 88, 77, 40];

const passMin = score.find((value) => value > 60);
console.log(passMin); //66

const pass = score.findIndex((value) => value > 60);
console.log(pass); //2

数组遍历

ES6新增 for…of 数组遍历方式

const score = [34, 23, 66, 12,];

for (let value of score) {
  console.log(value); //  34, 23, 66, 12
}

函数的扩展


ES6对函数进行了很多的扩展,具体如下

函数参数设置默认值

ES6允许为函数的参数设置默认值,即可以直接写在参数定义的后面。

//参数b设置了默认值为2,在方法调用的时候并没有传值,所以b直接使用默认值
function sum(a, b = 2) {
  return a + b;
}

console.log(sum(1)); //3

Rest参数

ES6引入reset参数,形式为…变量名,可以用来获取传递给函数的多余参数。

function sum(a, ...values) {
  console.log(a, values); //1   [2, 3, 4, 5]
}

sum(1, 2, 3, 4, 5);

name和length属性

name属性返回函数名,length属性返回没有指定默认值的参数个数。

function sum(a, b, c, d = 1) {
  console.log(a, values); //1   [2, 3, 4, 5]
}

console.log(sum.name);  //sum
console.log(sum.length);  //3

箭头函数

ES6允许使用箭头(=>)的方式定义函数,有下面几种箭头函数实现形式。
想要实现一个加法函数,ES5的形式如下

function sum(a, b) {
  return a + b;
}

而如果使用箭头函数实现的话,则如下

sumArrow = (a, b) => {
  return a + b;
};

上面是箭头函数的基本变现形式,不同的场景还有不同的实现形式。

//对于上面的sumArrow函

//一、如果只有一个参数,可以省略括号
sumArrow = a => {
  return a;
};

二、如果返回值是表达式,可以省略return{}
sumArrow = a => a;

三、如果返回值是字面量对象,一定要用小括号包起来
sumArrow = () => ({ a: 1, b: 2 });


箭头函数与普通函数除了实现方式不同外,还有个不同的点就是对this的处理方式。

//普通函数
let math = {
  name: "mathName",
  sum: function (a, b) {
    console.log(this.name); //math
    return a + b;
  },
};

math.sum();


//箭头函数
globalThis.name = "globalName";
let math = {
  name: "mathName",
  sum: (a, b) => {
    console.log(this.name); //globalName
    return a + b;
  },
};

math.sum();

从上面示例可以看到,箭头函数和普通函数最终打印的this.name不一致。对于普通函数,this指向的是调用sum方法的math对象,所以this.name打印的是“mathName”。而对于箭头函数,this指向的是定义sum方法的全局对象,所以this.name打印的是“globalName”。


在后续的开发过程中,我们将会经常使用到箭头函数,在使用的过程中,我们需要有以下几点注意

  1. 箭头函数中this指向定义时所在的对象,而不是调用时所在的对象
  2. 不可以当作构造函数
  3. 不可以使用yield命令,不能作用generator函数

解构赋值


解构赋值是一种表达式,可以将属性和值从对象和数组中取出,赋值给其他变量。

如何使用

对象解构赋值

假如我们拿到一个对象,需要获取指定的属性值。则解构赋值让我们无需通过调用属性的方式赋值,而是通过指定一个与对象结构相同模板的方式,获取想要的属性值。

const people = {
  name: "ES6",
  age: 27,
  sex: "male",
};

//如果通过调用属性赋值,则需要这么做
let name = people.name;
let age = people.age;
let sex = people.sex;

console.log(name, age, sex); //ES6 27 male

//而使用解构赋值的方式,代码会更加的清晰简单
const { name, age } = People;

console.log(name, age); //ES6 27 male

除了上面这种基本用法,还有其他使用方式

const people = {
  name: "ES6",
  age: 27,
  sex: "male",
};

// 一、属性顺序不需保持一致,名称相同即可
const { age, name, sex } = people;
console.log(name, age, sex);  //ES6 27 male

//二、取值时,重新定义变量名
const { age: newAge, name: newName, sex: newSex } = people;
console.log(name, age, sex); //Uncaught ReferenceError: age is not defined
console.log(newName, newAge, newSex); //ES6 27 male

//三、赋值过程中设置默认值
const { nickName = "昵称", age } = people;
console.log(nickName, age); //昵称 27

//四、reset运算符。只获取想要的属性,其他属性都放在新的变量里。
const { name, ...peopleParams } = people;
console.log(name, peopleParams); //ES6 {age: 27, sex: "male"}

//五、嵌套对象取值
const people = {
  name: "ES6",
  address: {
    province: "江苏",
  },
};
const { address: { province }} = people;
console.log(province); //江苏


数组解构赋值

假如我们拿到一个数组,需要获取指定的元素值。

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

console.log(a, b, c);	//1 2 3

除了上面这种基本用法,还有其他使用方式

//一、待解构的除了是数组,还可以是任意可遍历的对象
const [a, b, c] = new Set([1, 2, 3]);
console.log(a, b, c); //1 2 3

//二、被赋值的变量还可以是对象的属性,不局限于单纯的变量
const num = {};
[num.a, num.b, num.c] = [1, 2, 3];

console.log(num); //{a: 1, b: 2, c: 3}

//三、解构赋值在循环体中的应用
const num = {
  a: 10,
  b: 20,
  c: 30,
};
for (const [key, value] of Object.entries(num)) {
  console.log(key, value); //a 10    b 20    c 30
}

//四、跳过赋值元素
const [a, , c] = [1, 2, 3];	//存在空位的数组叫稀疏数组
console.log(a, c);  //1 3

//五、rest 参数
const [a,...other] = [1, 2, 3];
console.log(a, other);  //1    [2, 3]

//六、赋值过程中设置默认值
const [a, , , d = 10] = [1, 2, 3];
console.log(d); //10



字符串解构赋值

字符串解构赋值可以当成数组解构赋值

const [a, b, c, d] = "ECMAScript2015";

console.log(a, b, c, d); //E C M A

对象的扩展


ES6对对象进行了很多的扩展,具体如下

属性的简洁表示法

从ES6开始,如果对象的属性名和属性值相同,则有简写的方式。

let province = "江苏";
const address = {
  province, //等同于 province: province
  city: "南京",
};

属性名表达式

从ES6开始,可以使用变量或表达式定义对象的属性。

let key = "province";
const address = {
  [key]: "省份",
  city: "南京",
};

console.log(address); //{province: "省份", city: "南京"}

Object.is()

判断两个值是否是同一个值。在Object.is()之前,有“”和“=”两种方式判断值是否相等,但这两个方式都有一定缺陷,如下

//== 在判断相等前会对不是同一类型的变量进行强制转换,最终导致“”与false相等
console.log("" == false);	//true

//=== 会将-0与+0视为相等,而将Number.NaN与NaN视为不相等
console.log(-0 === +0);	//true
console.log(Number.NaN === NaN);	//false

所以,需要一种运算,在所有场景下,只要两个值是一样的,那么就应该相等,在实际项目开发过程中,推荐使用Object.is()来判断值相等。

console.log(Object.is(-0, +0)); //false
console.log(Object.is(Number.NaN, NaN)); //true

let a = { value: 1 };
let b = { value: 1 };
console.log(Object.is(a, b)); //false  对象都是同一个引用才相等

Object.assign()


用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,它将返回目标对象。


语法:

Object.assign(target, …sources)
参数说明:
target:目标对象
sources:源对象
返回值:合并后的目标对象

const target = { a: 1,};
const source = { b: "B", c: "C" };

const assignObj = Object.assign(target, source);

console.log(assignObj); //{a: 1, b: "B", c: "C"}  

//其他应用
//一、如果目标对象与源对象属性具有相同值,则源对象属性值会覆盖目标对象属性值
const target = { a: 1,b: 2};
const source = { b: "B", c: "C" };
const assignObj = Object.assign(target, source);
console.log(assignObj); //{a: 1, b: "B", c: "C"}  	//目标对象的b属性值被覆盖

//二、源对象可以有多个值
const target = { a: 1 };
const source1 = { b: "B", c: "C" };
const source2 = { d: "D", e: "E" };
const assignObj = Object.assign(target, source1, source2);
console.log(assignObj); //{a: 1, b: "B", c: "C", d: "D", e: "E"}

对象遍历

假如我们想要循环遍历一个对象的键与值,则可以使用下面几种方式进行遍历

const score = {
  name: "mango",
  age: "25",
  score: 80,
};

//for...in
for (let key in score) {
  console.log(key, score[key]); // 分别输出:name mango 、 age 25 、score 80
}

//Object.keys()用来获取所有key组成的数组
Object.keys(scoreObj).forEach(key => {
  console.log(key, scoreObj[key]) //分别输出:name mango 、 age 25 、score 80
})

//Object.getOwnPropertyNames()用来获取所有key组成的数组
Object.getOwnPropertyNames(scoreObj).forEach(key => {
  console.log(key, scoreObj[key]) //分别输出:name mango 、 age 25 、score 80
})

//Reflect.ownKeys()用来获取所有key组成的数组
Reflect.ownKeys(scoreObj).forEach(key => {
  console.log(key, scoreObj[key]) //分别输出:name mango 、 age 25 、score 80
})

Class

JavaScript是一种基于对象的语言,我们遇到的所有东西几乎都是对象,但ES6之前是没有class的,而在ES6版本中正式引入了class,让JavaScript成为了一种真正的面向对象语言,我们可以像下面这样在JavaScript中进行面向对象编程。

//通过class关键字定义类
class People{
  
  //类的构造函数
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  //实例方法
  getName() {
    return this.name;
  }

  //静态方法
  static say() {
    console.log("Hello ES6");
  }
}

//继承
class Student extends People {
  constructor(name, age) {
    super(name, age);
  }
}

//对象创建与调用
let student = new Student("mango", "27");
student.getName();
Student.say();

通过上面的代码,我们具体说明下JavaScript中进行面向对象编程。

类的声明

通过class关键字声明类,支持构造函数construct做对象初始化。

class People{
  
  constructor() {
    //初始化
  }
}

属性

Class对象中有两种对象属性,分别是实例属性和静态属性。实例属性必须定义在类的方法里,而静态属性必须定义在类的外面。

class People{
  constructor() {
    //定义实例属性
    this.name = "";
    this.age = 0;
  }
}

People.desc="类描述";	//定义的静态属性

//访问
People people=new People();
console.log(people.name);

console.log(People.name);

类中定义的属性,默认都是可读可写的,但是如果这时候我们想指定属性不可被修改该如何实现呢?那么便要用到set和get了,set和get可以定义一个属性,但是如果只有get而没有set,则属性不可以进行修改。

class People {

  get sex() {
    return "男";
  }
}

let people = new People();
console.log(people.sex);
people.sex="女" //Uncaught TypeError: Cannot set property sex of #<People> which has only a getter

方法

Class对象中有三种方法,分别是构造方法、实例方法还有静态方法。

class People {
  //构造方法
  constructor(name, age) {
    this.nameA = name;
    this.age = age;
  }

  //实例方法
  getName() {
    return this.nameA;
  }

  //静态方法
  static say() {
    console.log("Hello " + People.desc);
  }
}

People.desc = "类描述";

let people = new People("mango", "27");
let name = people.getName();
console.log(name); //mango
People.say(); //Hello 类描述

继承

继承是面向对象语言很重要的一大特征,ES6新加入了extends和super关键字来实现继承。

class People {
  constructor(name) {
    this.name = name;
  }

  getName() {
    return this.name;
  }
}

//继承
class Student extends People {
  constructor(name, age) {
    super(name, age);
  }
}

//Student类继承了People类,student对象中super调用了父类的构造函数,并传递了name参数,因为继承的特性,student也拥有了父类的getName()方法
let student = new Student("ES6");
console.log(student.getName());


通过以上对class的学习,我们得知道其实class并不是新引入的数据类型,其实class只是一种语法糖,它的实质完全可以看作构造函数的另一种写法。

class People {
  constructor(name) {
    this.name = name;
  }

  getName() {
    return this.name;
  }
}
console.log(typeof People); //function
console.log(People.prototype);  //{constructor: ƒ, getName: ƒ}

更多文章内容,请关注公众号【方塘HCI】


参考资料
【1】ECMAScript简介
【2】MDN web docs
【3】ECMAScript2015~2020语法全解析
【4】阮一峰 ECMAScript6(ES6)标准入门教程 第三版
【5】JavaScript深入之词法作用域和动态作用域
【6】Array.from() 五个超好用的用途

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值