ES6知识点归纳(二)——对象解构、数组解构、for of循环、新增的方法、剩余参数、扩展运算符

参考书籍:http://es6.ruanyifeng.com/
参考视频:https://www.bilibili.com/video/av47304735
全部篇章:
ES6知识点归纳(一)——var、let、const、箭头函数、函数参数的默认值、ES6模版字符串
ES6知识点归纳(二)——对象解构、数组解构、for of循环、新增的方法、剩余参数、扩展运算符
ES6知识点归纳(三)——Promise、Symbol、模块(Modules)、class继承、Iterator、Generator、Proxy、Set、WeakSet、Map、WeakMap


对象解构

  1. 简单用法
const Alfred = {
  name: "Alfred",
  age: 30,
  family: {
    mother: "one",
    father: "two",
    brother: "three"
  }
};
// const name = ""; 		//下方声明了name和age变量,所以在它不能声明一样的变量

const { name, age } = Alfred;
//先声明变量name和age,然后在Alfred中找和变量相同的同名属性,然后分别赋值
console.log(name, age);
  1. 如果还是想提前声明变量,可以使用大括号,见下方
const Alfred = {
  name: "Alfred",
  age: 30,
  family: {
    mother: "one",
    father: "two",
    brother: "three"
  }
};
let name = "";				//此处提前声明name
({ name, age } = Alfred);	//使用圆括号目的是让程序知道你这个是表达式而不是解构模式
console.log(name, age);
  1. 对象解构可以嵌套
const Alfred = {
  name: "Alfred",
  age: 30,
  family: {
    mother: "one",
    father: "two",
    brother: "three"
  }
};
const { father, mother, brother } = Alfred.family;
console.log(father, mother, brother);
  1. 如果提前使用了一个同名变量,就要重命名
const Alfred = {
  name: "Alfred",
  age: 30,
  family: {
    mother: "one",
    father: "two",
    brother: "three"
  }
};
const father = "Dad";
const { father: F, mother, brother: b } = Alfred.family; //此处声明了的是重命名之后的变量,是先声明了f变量,在Alfred.family中找到属性名是father的值,赋值给f

console.log(father, F); //Dad two

// console.log(brother);//如果想要打印brother,会报错,Uncaught ReferenceError: brother is not defined
  1. 如果要在对象中拿一个没有的变量,会返回 undefined
const Alfred = {
  name: "Alfred",
  age: 30,
  family: {
    mother: "one",
    father: "two",
    brother: "three"
  }
};
const father = "Dad";
const { father: F, mother, brother: b, sister } = Alfred.family;
console.log(sister); //undefined
  • 通常,如果没有这个值,可以给定一个默认值,只要对象里没有这个值(即等于 undefined),或对象里该值就是 undefined 时,才使用这个默认值,否则都不会使用(0,false,null 也不使用默认值)。
    const Alfred = {
      name: "Alfred",
      age: 30,
      family: {
        mother: "one",
        father: "two",
        brother: "three"
      }
    };
    const father = "Dad";
    const {
      father: F,
      mother,
      brother: b,
      sister = "have no sister"
    } = Alfred.family;
    console.log(sister); //have no sister
    
  • 这种使用默认值的场景在一些第三方库中非常常用

数组解构

  1. 简单用法
const numbers = ["one", "two", "three", "four"];

const [a,b]=numbers;//声明变量,可以获取相应位置的值
console.log(a,b);//one two

const [m,,n]=numbers;//想拿第一和三位置的值,就把中间的空出来
console.log(m,n);//one three

const [j,...k]=numbers;//想获取第一个和剩余的,使用Rest参数
console.log(j,k);//one  ["two", "three", "four"]

const [one,...two,three]=numbers;//rest参数必须是数组的最后一个
console.log(two);//报错
  1. 数组解构指定默认值
const details = ["Alfred", null];
const [singerOne, singerTwo = "Jw", singerThree = "Raymond"] = details;
console.log(singerOne, singerTwo, singerThree); //Alfred null Raymond

//数组中对应值为undefined,才使用默认值,为0,false,null不会使用默认值
  1. 常用场景
  • 交换变量的值
let a = 10;
let b = 20;
[a, b] = [b, a];
console.log(a, b); //20 10

for of循环

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols

  1. for of 循环可用于遍历可迭代对象
  2. 可迭代对象:部署了iterator(迭代器/遍历器)的接口,或定义了Symbol.iterator方法的数据结构
  3. 遍历器可用于定义数据结构的遍历方式,js 给很多内置的数据结构提供了内置的遍历器接口
  4. for of 循环不支持遍历对象
Array.prototype.sayhi = function() {
  return this[0];
};
const fruits = ["apple", "banana", "orange", "pear"];
fruits.hi = "hi";

// for (let i = 0; i < fruits.length; i++) {
//   console.log(fruits[i]);
// }
// 繁琐,可读性不高

// fruits.forEach(fruit=>{
//   console.log(fruit);
// })
//数组提供的forEach()方法,缺点是不能终止或者跳过,在forEach里面用break和continue都会报错

// for (let fruit in fruits) {
//   console.log(fruits[fruit]);
// }
//for in 循环的变量fruit,循环的是属性名
//for in遍历的是对象上所有的的可枚举属性,即使属性加在它的原型上也可以遍历到

for (let fruit of fruits) {
  if (fruit === "banana") {
    break;
    //continue;
  }
  console.log(fruit);
}
//for of循环中的变量fruit循环的是属性值,同时也不会遍历数组上的非数字属性,同时支持循环终止和跳过
  1. 定义一个数组 fruits,在控制台输入fruits.entries();,可看到它的遍历器接口
const fruits = ["apple", "banana", "orange", "pear"];

for (let fruit of fruits.entries()) {
  console.log(fruit);
  //可同时获取到元素的索引值和元素值
}

因此可以改写成

const fruits = ["apple", "banana", "orange", "pear"];

for (let [index, fruit] of fruits.entries()) {
  console.log(`${fruit} ranks ${index + 1} in my favorite fruits`);
}
  1. 用于其他数据结构的一些场景
  • 遍历 arguments 对象来计算数组的和(注意:arguments 对象的原型是 Object)

    function sum() {
      let total = 0;
      for (let num of arguments) {
        total += num;
      }
      console.log(total);
      return total;
    }
    sum(1, 2, 3, 4, 5);
    
  • 应用于字符串

    let name = "Alfred";
    for (let char of name) {
      console.log(char);
    }
    
  • 用于获取 NodeList,我们经常需要获取一些 dom 集合,用于操作里面的元素

    <div>
      <ul>
        <li>one</li>
        <li>two</li>
        <li>three</li>
        <li>four</li>
        <li>five</li>
      </ul>
    </div>
    
    .completed {
      text-decoration: line-through;
    }
    
    const list = document.querySelectorAll("li");
    // console.log(list);
    for (let li of list) {
      li.addEventListener("click", function() {
        this.classList.toggle("completed");
      });
    }
    

ES6 新增的字符串函数

.startsWith()

  • 是否(从第 n 位开始)以’xx’字符串开头
  • 区分大小写
const num = "881208Alfred";
console.log(num.startsWith("88")); //true,是否以'88'开头

console.log(num.startsWith("1208", 1)); //false
console.log(num.startsWith("1208", 2)); //true,从第三位开始是不是'1208'

console.log(num.startsWith("A", 6)); //true
console.log(num.startsWith("a", 6)); //false

.endsWith()

  • 是否以’xx’字符串结尾
  • 使用与 startsWith 相似
  • 区分大小写
console.log(num.endsWith("ed")); //true,是否以'es'结尾
console.log(num.endsWith("1208", 6)); //true,注意6是1208中8的下标后一位

console.log(num.endsWith("A", 7)); //true
console.log(num.endsWith("a", 7)); //false

.includes()

  • 'xx’字符串是否包含在原字符串里
const sentence = "Alfred loves his father";
console.log(sentence.indexOf("is") !== -1); //ES5,is字符串存在在sentence内
console.log(sentence.includes("is")); //ES6,true
console.log(sentence.includes("is", 14)); //true,从下标为14位及之后是否存在is
console.log(sentence.includes("is", 15)); //false

.repeat()

  • 让某字符串重复 n 次
const sentence = "Alfred loves his father";
const sentence2 = "I love programing";
const title = `${"哈".repeat(3)} ${sentence} ${"喽".repeat(3)}`;
console.log(title); //哈哈哈 Alfred loves his father 喽喽喽

//字符串右对齐
function padder(string, length = 25) {
  return `${" ".repeat(Math.max(length - string.length, 0))}${string}`;
}
console.log(padder(sentence));
console.log(padder(sentence2));

ES6 为数组提供的新方法

Array.from()

  1. Array.from()用于把一个类数组对象/可遍历对象转换为一个数组
    • 类数组对象是拥有 length 属性的对象
    • 可遍历对象即可迭代对象(for of 处有相关描述)
  2. from()不是数组原型上的方法
const num = [];
num.from(); //报错

Array.from(num); //正确调用

简单运用:

<ul>
  <li>one</li>
  <li>two</li>
  <li>three</li>
</ul>
const todos = document.getElementsByTagName("li");
const num = todos.map(todo => todo.innerHTML); //todos.map is not a function
console.log(num);

//因为todo不是数组,只是类数组对象,所以没有map方法

要改成

const todos = document.getElementsByTagName("li");
const num = Array.from(todos); //将类数组对象转换为数组
const nums = num.map(todo => todo.innerHTML);
console.log(nums);
  1. Array.from()可传入第二个参数,是一个函数,相当于数组的 map 方法,会对转化成数组的每个元素执行相对应的函数
const todos = document.getElementsByTagName("li");
const nums = Array.from(todos, todo => todo.innerHTML);
console.log(nums);
  1. 可将函数里的 arguments 这个类数组对象转换为数组
function sum() {
  return arguments.reduce((prev, curr) => prev + curr, 0);
}
console.log(sum(1, 2)); //报错

改成

function sum() {
  return Array.from(arguments).reduce((prev, curr) => prev + curr);
}
console.log(sum(1, 2)); //3

Array.of()

  1. Array.of()用于弥补 Array 这个构造函数的不足
console.log(new Array(1)); //length为1的空数组
console.log(new Array(7)); //length为7的空数组
console.log(new Array(1, 2)); //[1,2]

console.log(Array.of(2)); //[2]
console.log(Array.of(1, 2)); //[1,2]

//Array.of()解决了Array构造函数因传参个数不同而造成的的不一致
  1. of()不是数组原型上的方法
const num = [];
num.of(); //报错

ES6 中数组的新方法

.find()

  1. 用于寻找数组里的某个满足条件的元素
  2. 接受一个函数作为参数
    • 函数可接受三个参数,后两个为可选inventory.find(element,index,array)
  3. 当找到一个符合要求的元素就立刻返回
const inventory = [
  { name: "apple", quantity: 1 },
  { name: "banana", quantity: 2 },
  { name: "pear", quantity: 3 }
];

const bananas = inventory.find(fruit => {
  console.log(fruit); //可见,执行到第一个满足条件的元素处就停止执行了
  if (fruit.name === "banana") {
    return true;
  }
  return false;
});
console.log(bananas);

简化为:

const inventory = [
  { name: "apple", quantity: 1 },
  { name: "banana", quantity: 2 },
  { name: "pear", quantity: 3 }
];

const bananas = inventory.find(fruit => fruit.name === "banana"); //{name: "banana", quantity: 2}
console.log(bananas);

.findIndex()

  1. 找到数组中某个元素的索引
  2. 接受一个函数作为参数
    • 函数可接受三个参数,后两个为可选inventory.findIndex(element,index,array)
  3. 返回第一个找到的元素的索引
const inventory = [
  { name: "apple", quantity: 1 },
  { name: "banana", quantity: 2 },
  { name: "banana", quantity: 3 }
];

const bananaIndex = inventory.findIndex(fruit => fruit.name === "banana");
console.log(bananaIndex); //1

.some()

  1. 接受一个函数作为参数,返回布尔值
  2. 若数组中某个元素满足了测试函数,就返回 true 并且停止执行
const inventory = [
  { name: "apple", quantity: 1 },
  { name: "banana", quantity: 0 },
  { name: "pear", quantity: 3 }
];

const isEnough = inventory.some(fruit => fruit.quantity > 0); //水果是否还有库存?
console.log(isEnough); //true

.every()

  1. 接受一个函数作为参数,返回布尔值
  2. 只有当所有元素都满足测试函数,才会返回 true,否则,遇到第一个条件是 false 的元素就会立即返回并停止执行
const inventory = [
  { name: "apple", quantity: 1 },
  { name: "banana", quantity: 0 },
  { name: "pear", quantity: 3 }
];

const isAllEnough = inventory.every(fruit => fruit.quantity > 0);
console.log(isAllEnough); //false

剩余参数

  1. 剩余参数只能用于参数的最后一个,不能是中间
  2. 还可用于解构
    直接看一些例子来理解用法吧
function sum(...numbers) {
  console.log(numbers); //数组[1,2,3]
  console.log(arguments); //类数组对象

  return numbers.reduce((prev, curr) => prev + curr, 0);
}
console.log(sum(1, 2, 3)); //6
console.log(sum(1, 2, 3, 4)); //10
function converCurrency(rate, ...amounts) {
  return amounts.map(amount => amount * rate);
}
const amounts = converCurrency(0.8, 12, 34, 656, 23);
console.log(amounts);

扩展运算符

  1. 剩余参数是把很多参数整合成数组,而扩展运算符则是把一个可遍历对象的每个元素扩展为一个新的参数序列。
console.log([..."Alfred"]); //["A", "l", "f", "r", "e", "d"]
  1. 来看一个例子:想在把两个数组连接起来,并在两个数组之间添加一个 Raymond
const actor = ["Jhon", "Thomas"];
const singers = ["Greyson", "Alfred"];

//ES5方法
// let members = [];
// members = members.concat(actor);
// members.push("Raymond");
// members = members.concat(singers);
// console.log(members);

//ES6方法
const members = [...actor, "Raymond", ...singers];
console.log(members);
  1. 再来看一种情况
const actor = ["Jhon", "Thomas"];
const singers = ["Greyson", "Alfred"];

const members = [...actor, "Raymond", ...singers];
const currentMembers = members;
currentMembers[0] = "nobody";
console.log(currentMembers);
console.log(members);
//["nobody", "Thomas", "Raymond", "Greyson", "Alfred"]
//此时members和currentMembers的第一个元素均改变了,因为currentMembers中保存的是指向members的索引。

ES5 中常见解决方法:

const actor = ["Jhon", "Thomas"];
const singers = ["Greyson", "Alfred"];

const members = [...actor, "Raymond", ...singers];
const currentMembers = [].concat(members);
currentMembers[0] = "nobody";

运用扩展运算符解决:

const actor = ["Jhon", "Thomas"];
const singers = ["Greyson", "Alfred"];

const members = [...actor, "Raymond", ...singers];
const currentMembers = [...members];
currentMembers[0] = "nobody";

其他运用场景

  1. 代替Array.from
//因document.getElementsByTagName("li")的原型不是数组,因此没有map方法
// const todos = Array.from(document.getElementsByTagName("li"));
//除了使用Array.from,还可以用扩展运算符
const todos = [...document.getElementsByTagName("li")];
const nums = todos.map(todo => todo.innerHTML);
console.log(nums);
  1. 扩展对象的属性
const favorites = {
  color: ["blue", "yellow"],
  fruits: ["banana", "apple"]
};
const shoppingList = ["milk", "sweets", ...favorites.fruits];
console.log(shoppingList); //["milk", "sweets", "banana", "apple"]
  1. 数组中删除对象元素
//想要删除数组中id为2的对象
const todos = [
  { id: 1, name: "Raymond" },
  { id: 2, name: "Alfred" },
  { id: 3, name: "Greyson" }
];
const deleteIndex = todos.findIndex(todo => todo.id === 2);
// const newTodos=[todos.slice(0,deleteIndex),todos.slice(deleteIndex+1)];
// 因为todos.slice(0,deleteIndex)和todos.slice(deleteIndex+1)是两个数组,而我们一般希望能以对象的方式重新保存到数组里,因此可用扩展运算符

const newTodos = [
  ...todos.slice(0, deleteIndex),
  ...todos.slice(deleteIndex + 1)
]; //将原来数组里的每一项直接放进新的数组
console.log(newTodos);
  1. 在函数中的应用
//将singers的元素push到actor中
const actors = ["Jhon", "Thomas"];
const singers = ["Greyson", "Alfred"];

//ES5
// actors.push(singers);//这样写,最后actors成了二维数组,并不是我们想要的效果
actors.push.apply(actors, singers);

//ES6
actors.push(...singers);
console.log(actors);
  • 减轻我们一个一个传入参数的痛苦
const dateFields = [2019, 9, 1, 20, 20];
const date = new Date(...dateFields);
console.log(date); //注意月份是从0开始算的

对象字面量的改进

  • 简化书写
  1. 当对象内的属性名和对象外的变量名一样时,对象内可简化书写
const name = "Raymond";
const age = 1;
const birthday = "2018-01-01";

//ES5
const Raymond = {
  name: name,
  age: age,
  birthday: birthday
};

//ES6
const raymond = {
  name,
  age,
  birthday
};

//需要导出方法时也一样
// module.exports={
//     gatName,
//     getAge
// }
  1. 在对象内定义方法时可以简写
//ES5
const Raymond = {
  name: name,
  age: age,
  birthday: birthday,
  greet: function() {
    alert("Hello");
  }
};

//ES6
const raymond = {
  name,
  age,
  birthday,
  greet() {
    alert("Hello");
  }
};
  1. ES6 提供了计算属性
let id = 0;
const userIds = {
  [`user-${++id}`]: id,
  [`user-${++id}`]: id,
  [`user-${++id}`]: id
};
console.log(userIds);
const keys = ["name", "age", "birthday"];
const values = ["Raymond", "2", "2017-01-01"];
const Raymond = {
  [keys.shift()]: values.shift(),
  [keys.shift()]: values.shift(),
  [keys.shift()]: values.shift()
};
console.log(Raymond);
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值