一些比较有用的es6特性和语法总结

318 阅读5分钟

1. Object.entries()和Object.fromEntries()

  1. Object.entries() 将对象的属性和值 (键和值) 用数组的形式表现出来。即返回包含对象自身可枚举属性的键值对组成的数组

  2. Object.fromEntries() 相当于 Object.entries() 方法的逆操作,将键值对形式的数组转换成对象

const user = {
    name: 'andy凌云',
    age: 18
};
const toArr = Object.entries(user);
console.log(toArr); // [['name', 'andy凌云'], ['age', 18]]
const toObj = Object.fromEntries(toArr);
console.log(toObj); // { "name": "andy凌云", "age": 18 }

2. 缓存递归

递归(英語:Recursion),又译为递回,在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。通俗的点说呢,就是 方法自己调用自己。 递归思想就是:把问题分解成规模更小,但和原问题有着相同解法的问题。在实际开发过程中,递归有非常多的运用,比如深复制、斐波那契数列、阶乘、求和等等。使用递归,如果不进行缓存优化,超过了最大调用栈就会导致爆栈报错。

// 阶乘
function factorial (n: number): number {
    if (n == 1) return n;
    return n * factorial(n - 1)
}
console.log(factorial(5)) // 5 * 4 * 3 * 2 * 1 = 120
// 斐波那契数列
function fibonacci (n: number): (number | Function) {
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci(5)) // 1 1 2 3 5

缓存代理:

function memozie(fn) {
   const cache = {};
   return function() {
      let key = [].slice.call(arguments);
      if (cache[key]) {
         return cache[key]
      } else {
         let res = fn.apply(null, arguments);
         cache[key] = res;
         return res;
      }
   }
}

function fib(n) {
   return n < 2 ? n : fib(n - 1) * n;
}

const fib2 = memozie(fib);

3. 尾递归优化

function sum(n, result = 1) {
    if (n <= 1) return result;
  return sum(n - 1, result + n);
}
sum(10000);

4. js 可选链操作符(javascript-optional-chaining)使用

可选链操作符(  ?.  )允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为空(null 或者 undefined) 的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined。 如果不能直接使用, 可通过babel编译器使用

  • 语法
obj?.prop
obj?.[expr]
func?.(args)
obj?.['prop' + 'Name']
  • 使用介绍 如果我有个对象obj。 现在要访问它的深层属性 baz
const obj = {
  foo: {
    bar: {
      baz: 42,
      fun: ()=>{}
    },
  },
};

// 不使用?.
let baz = obj && obj.foo && obj.foo.bar && obj.foo.bar.baz;

// 使用?.
let baz = obj?.foo?.bar?.baz; // 结果:42
  • 可选链不能用于赋值
let object = {};
object?.property = 1; // Uncaught SyntacError: Invalid left-hand side in assignment
  • 使用空值合并操作符(??) 空值合并操作符(??)是一个逻辑操作符, 当左侧的操作数为null或者undefined时, 返回其右侧操作数,否则返回左侧操作数
let customer = {
  name: "Carl",
  details: { age: 82 }
};
let customerCity = customer?.city ?? "暗之城";
console.log(customerCity); // “暗之城”
  • 如果项目不支持, 安装OC插件 大多数现代浏览器已支持可选链接,为了安全并向后兼容,请使用转换器。如果你使用的是 Babel,请安装 OC 插件...
npm i @babel/plugin-proposal-optional-chaining

并将其添加到你的.babelrc文件中

{
    "plugin":[
        "@babel/plugin-proposal-optional-chaining",
    ]
}
  • eslint 安装babel编译器后,就可以使用?.操作符了。但是如果你使用eslint的话,你就需要安装babel-eslint来识别这种新语法。
yarn add babel-eslint --dev

然后添加 .eslintrc文件

{
  "parser": "babel-eslint",
  "rules": {
    "strict": 0
  }
}
  • 在vscode中使用 vscode的js验证器目前并不能识别?.操作符, 所以会有错误警告:

解决错误警告: 安装vscode扩展eslint, 在扩展商店搜索并安装eslint 修改vscode配置(.vscoe/settings.json):

{
  "eslint.alwaysShowStatus": true,
  "eslint.autoFixOnSave": true,
  "javascript.validate.enable": false, // 主要是这个,关闭vscode的js验证器
  "[javascript]": {
    "editor.formatOnSave": false,
  },
  "[javascriptreact]": {
  "editor.formatOnSave": false,
  },
}

注意: 可选链操作只能在js中使用, 在template模板中需要使用函数方法进行替代操作, 直接使用?.语法会报错

  • 解决在template模板使用可选链操作符的办法:
export const chaining = {
    install(vue) {
        const optionalChaining = (obj, ...rest) => {
            let tmp = obj;
            for (let key in rest) {
                let name = rest[key];
                tmp = tmp?.[name];
            }
            return tmp || "";
        }
        // 添加实例方法
        vue.prototype.$$ = optionalChaining;
    }
}

// 在main.js中引入
import chaining from "@/plugins/chaining"; 
Vue.use(chaining)
// 在template中使用
{{$$(obj, 'first', 'second') }}
  • 使用?. 可以进行删除和都操作, 但是不能进行赋值操作
  • 参考连接 知乎

mdn-可选链操作符

5. reduce方法

reduce()  方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。 语法: arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue]) reducer 函数接收4个参数:

  1. Accumulator (acc) (累计器) 累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue
  2. Current Value (cur) (当前值) 数组中正在处理的元素
  3. Current Index (idx) (当前索引) 如果提供了initialValue,则起始索引号为0,否则从索引1起始
  4. Source Array (src) (源数组)

您的 reducer 函数的返回值分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值

initialValue可选: 作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错

注意: 如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始

reduce的一些用法

// 1. 求和, 结果为6
let sum = [0, 1, 2, 3].reduce(function(accumulator, currentValue) {
  return accumulator + currentValue;
}, 0);

// 2. 求数组对象里的值, 结果为10
let arr = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }];
let res = arr.reduce((acc, cur) => {
  return acc + cur.x
}, 0);  // 10

// 3. 二位数组转一维  [0,1,2,3,4,5];
let arr = [[0, 1], [2, 3], [4, 5]];
let res = arr.reduce((a, b) => {
  return a.concat(b)
}, []);

// 4. 将多维数组转化为一维, 结果为 [0, 1, 2, 3, 4, 5, 6, 7]
let arr = [[0, 1], [2, 3], [4, [5, 6, 7]]]
const newArr = function(arr) {
  return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? newArr(cur) : cur), [])
}


// 5. 计算数组中每个元素出现的次数,  结果: {Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];

let countedNames = names.reduce(function(allNames, name) {
  if (name in allNames) {
    allNames[name]++;
  }
  else {
    allNames[name] = 1;
  }
  return allNames;
}, {});

// 6. 使用扩展运算符和initialValue绑定包含在对象数组中的数组

// friends - 对象数组
// where object field "books" - list of favorite books
let friends = [{
  name: 'Anna',
  books: ['Bible', 'Harry Potter'],
  age: 21
}, {
  name: 'Bob',
  books: ['War and peace', 'Romeo and Juliet'],
  age: 26
}, {
  name: 'Alice',
  books: ['The Lord of the Rings', 'The Shining'],
  age: 18
}];

// allbooks - list which will contain all friends' books +
// additional list contained in initialValue
let allbooks = friends.reduce(function(prev, curr) {
  return [...prev, ...curr.books];
}, ['Alphabet']);

// allbooks = [
//   'Alphabet', 'Bible', 'Harry Potter', 'War and peace',
//   'Romeo and Juliet', 'The Lord of the Rings',
//   'The Shining'
// ]

// 7. 数组去重, 结果: [1, 2, 3, 4]
let arr = [1, 2, 3, 4, 4, 1]
let newArr = arr.reduce((pre, cur) => {
  if (!pre.includes(cur)) {
    return pre.concat(cur)
  } else {
    return pre
  }
}, [])

// 8. 求数组中最大值 结果: 342
const a = [23,123,342,12];
const max = a.reduce(function(pre,cur){return pre>cur?pre:cur;}); 

// 9. 生成"老大、老二、老三和老四"
const objArr = [{name: '老大'}, {name: '老二'}, {name: '老三'}, {name: '老四'}];
const res = objArr.reduce((pre, cur) => {
  if (index === 0) {
    return cur.name;
  }
  else if (index === (arr.length - 1)) {
    return pre + '和' + cur.name;
  }
  else {
    return pre + '、' + cur.name;
  }
}, '');

// 10. 数组转对象。 按照id生成。
var streams = [{name: '技术', id: 1}, {name: '设计', id: 2}];
var obj = streams.reduce((accumulator, cur) => {accumulator[cur.id] = cur; return accumulator;}, {});

// 11. 求各科成绩的平均值  结果: 88.5
var result = [
  { subject: 'math', score: 88 },
  { subject: 'chinese', score: 95 },
  { subject: 'english', score: 80 }
];
var dis = {
    math: 0.5,
    chinese: 0.3,
    english: 0.2
};
var res = result.reduce((accumulator, cur) => dis[cur.subject] * cur.score + accumulator, 0);