ECMAScript 6常用知识点及实例整理,包含(ECMAScript 7/8/9)

提示:文章篇幅较长,涉及知识点较多,建议收藏后观看。

目录

let 和 const

解构赋值

箭头函数的使用

模板字符串

函数默认参数

展开运算符

对象字面量 与 class

Promise

数组新增方法

对象新增方法

指数函数的中缀形式


let 和 const

let 和 const 的特点:

  1. 不会被提升
  2. 重复声明报错
  3. 不绑定全局作用域(块级作用域)

临时死区:(TDZ) let 和 const 声明的变量不会被提升到作用域顶部,如果在声明之前访问这些变量,会导致报错:

var value = "global";
// 例子1
(function() {
    console.log(value);
    let value = 'local';
}());

// 例子2
{
    console.log(value);
    const value = 'local';
};
// 两个例子中,结果并不会打印 "global",而是报错 Uncaught ReferenceError: value is not defined,就是因为 TDZ 的缘故。

解构赋值

解构赋值语法是一个Javascript表达式,这使得可以将数据从数组或对象提取到不同的变量中

const person = {
  name: 'little bear',
  age: 18,
  sex: '男'
}
let { name,age,sex } = person
//数组
let nbaStars=['yaoming','kobe','james','paul']
let [chinaStar,...usaStar] = nbaStars
let [,,,myidol] = nbaStars
console.log(usaStar,chinaStar,myidol)
//["kobe", "james", "paul"] "yaoming" "paul"

箭头函数的使用

// es5
var fn = function(a, b) {
    return a + b;
}
// es6 箭头函数写法,当函数直接被return时,可以省略函数体的括号
const fn = (a, b) => a + b;

// es5
var foo = function() {
    var a = 20;
    var b = 30;
    return a + b;
}
// es6
const foo = () => {
   const a = 20;
   const b = 30;
   return a + b;
}

# 使用箭头函数需要注意以下几点:

  • 箭头函数可以替换函数表达式,但是不能替换函数声明;
  • 箭头函数中,没有this。如果你在箭头函数中使用了this,那么该this一定就是外层的this;
  • 在ES6中,会默认采用严格模式,因此this也不会自动指向window对象;
  • 箭头函数本身并没有this;
  • 箭头函数中无法访问arguments对象。

模板字符串

使用 `` 将整个字符串包裹起来,而在其中使用 ${} 来包裹一个变量或者一个表达式。

// es6
const a = 20;
const b = 30;
const string = `${a}+${b}=${a+b}`;

// es5
var a = 20;
var b = 30;
var string = a + "+" + b + "=" + (a + b);

函数默认参数

function add(x = 20, y = 30) {
    return x + y;
}
console.log(add());

展开运算符

在ES6中用...来表示展开运算符,它可以将数组方法或者对象进行展开。

数组展开:
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 10, 20, 30];
// 这样,arr2 就变成了[1, 2, 3, 10, 20, 30];

对象展开:
const obj1 = {
  a: 1,
  b: 2,
  c: 3
}
const obj2 = {
  ...obj1,
  d: 4,
  e: 5,
  f: 6
}

// 结果类似于 const obj2 = Object.assign({}, obj1, {d: 4})

对象字面量 与 class

  1. 当属性与值的变量同名时
    const name = 'Jane';
    const age = 20
    
    // es6
    const person = {
      name,
      age
    }
    
    // es5
    var person = {
      name: name,
      age: age
    };

     

  2. 除了属性之外,对象字面量写法中的方法也可以有简写方式。
    // es6
    const person = {
      name,
      age,
      getName() { // 只要不使用箭头函数,this就还是我们熟悉的this
        return this.name
      }
    }
    
    // es5
    var person = {
      name: name,
      age: age,
      getName: function getName() {
        return this.name;
      }
    };

     

  3. 在对象字面量中可以使用中括号作为属性,表示属性名也能是一个变量了。
    const name = 'Jane';
    const age = 20
    
    const person = {
      [name]: true,
      [age]: true
    }

     

  4. ES6为我们创建对象提供了新的语法糖,这就是Class语法。
    // ES5
    // 构造函数
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    
    // 原型方法
    Person.prototype.getName = function() {
      return this.name
    }
    
    // ES6
    class Person {
      constructor(name, age) {  // 构造函数
        this.name = name;
        this.age = age;
      }
    
      getName() {  // 原型方法
        return this.name
      }
    }
    babel会将ES6的写法编译成为利用Object.defineProperty实现的方式,包括get,set等。
    

     

  5. 除此之外,我们还需要特别注意在实际使用中的几种写法方式的不同,在下面的例子注释中,我说明了他们分别对应的ES5中的含义。
    class Person {
      constructor(name, age) {  // 构造函数
        this.name = name;
        this.age = age;
      }
    
      getName() {   // 这种写法表示将方法添加到原型中
        return this.name
      }
    
      static a = 20;  // 等同于 Person.a = 20
    
      c = 20;   // 表示在构造函数中添加属性 在构造函数中等同于 this.c = 20
    
    // 箭头函数的写法表示在构造函数中添加方法,在构造函数中等同于this.getAge = function() {}
      getAge = () => this.age   
    }
    
    继承 extends
    相比ES5,ES6的继承就要简单很多:
    class Person {
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
    
      getName() {
        return this.name
      }
    }
    
    // Student类继承Person类
    class Student extends Person {
      constructor(name, age, gender, classes) {
        super(name, age);
        this.gender = gender;
        this.classes = classes;
      }
    
      getGender() {
        return this.gender;
      }
    }

     

  6. 我们只需要一个extends关键字,就可以实现继承了,不用像ES5那样去担心构造函数继承和原型继承,除此之外,我们还需要关注一个叫做super的方法。
    /* 在继承的构造函数中,我们必须如上面的例子那么调用一次super方法,
        它表示构造函数的继承,与ES5中利用call/apply继承构造函数是一样的功能。 */
    // 构造函数中
    // es6
    super(name, age);
    
    // es5
    Person.call(this);

     

Promise

在ajax的原生实现中,利用了onreadystatechange事件,当该事件触发并且符合一定条件时,才能拿到我们想要的数据,之后我们才能开始处理数据。这样做看上去并没有什么麻烦,但是如果这个时候,我们还需要做另外一个ajax请求,这个新的ajax请求的其中一个参数,得从上一个ajax请求中获取,这个时候我们就不得不如下这样做:

var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';
var result;

var XHR = new XMLHttpRequest();
XHR.open('GET', url, true);
XHR.send();

XHR.onreadystatechange = function() {
    if (XHR.readyState == 4 && XHR.status == 200) {
        result = XHR.response;
        console.log(result);

        // 伪代码
        var url2 = 'http:xxx.yyy.com/zzz?ddd=' + result.someParams;
        var XHR2 = new XMLHttpRequest();
        XHR2.open('GET', url, true);
        XHR2.send();
        XHR2.onreadystatechange = function() {
            ...
        }
    }
}

当出现第三个ajax(甚至更多)仍然依赖上一个请求的时候,我们的代码就变成了一场灾难。这场灾难,往往也被称为回调地狱。

因此我们需要一个叫做Promise的东西,来解决这个问题。

当然,除了回调地狱之外,还有一个非常重要的需求:为了我们的代码更加具有可读性和可维护性,我们需要将数据请求与数据处理明确的区分开来。

Promise对象有三种状态,他们分别是:

  • pending: 等待中,或者进行中,表示还没有得到结果
  • resolved(Fulfilled): 已经完成,表示得到了我们想要的结果,可以继续往下执行
  • rejected: 也表示得到结果,但是由于结果并非我们所愿,因此拒绝执行
new Promise(function(resolve, reject) {
    if(true) { resolve() };
    if(false) { reject() };
})

Promise.all:

Promise.all接收一个Promise对象组成的数组作为参数,当这个数组所有的Promise对象状态都变成resolved或者rejected的时候,它才会去调用then方法。

var url = '...';
var url1 = '...';

function renderAll() {
    return Promise.all([getJSON(url), getJSON(url1)]);
}
renderAll().then(function(value) {
    console.log(value);
})

Promise.race:

与Promise.all相似的是,Promise.race都是以一个Promise对象组成的数组作为参数,不同的是,只要当数组中的其中一个Promsie状态变成resolved或者rejected时,就可以调用.then方法了。

function renderRace() {
    return Promise.race([getJSON(url), getJSON(url1)]);
}

renderRace().then(function(value) {
    console.log(value);
})

数组新增方法

1. Array.prototype.includes

    includes是一个 Array 上很有用的函数,用于快速查找数组中是否包含某个元素。(包括 NaN,所以和 indexOf 不一样)。

2. 字符串追加

    提供了两个字符串追加的方法 String.prototype.padStart 和 String.prototype.padEnd,方便我们将一个新的字符串追加到某个字符串的头尾。

'someString'.padStart(numberOfCharcters [,stringForPadding]);
'5'.padStart(10) // '          5'
'5'.padStart(10, '=*') //'=*=*=*=*=5'
'5'.padEnd(10) // '5         '
'5'.padEnd(10, '=*') //'5=*=*=*=*='

Object.entries(cars).map(([name, count]) => {
    console.log(`${name.padEnd(20, '-')} Count:${count.toString().padStart(3, '0')}`)
})
/*
?ambulance--------- Count:003
?car--------------- Count:007
?trucks------------ Count:004
*/

3. Array.prototype.flat()  ( ES9 )

    Array.prototype.flat() 递归地将嵌套数组拼合到指定深度。默认值为 1,如果要全深度则使用 Infinity 。此方法不会修改原始数组,但会创建一个新数组:

const arr1 = [1, 2, [3, 4]];
arr1.flat();  // [1, 2, 3, 4]
const arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat(2);  // [1, 2, 3, 4, 5, 6]
 
const arr3 = [1, 2, [3, 4, [5, 6, [7, 8]]]];
arr3.flat(Infinity); // [1, 2, 3, 4, 5, 6, 7, 8]
flat() 方法会移除数组中的空项:
const arr4 = [1, 2, , 4, 5];
arr4.flat(); // [1, 2, 4, 5]

4. Array.prototype.flatMap()  (ES9)

    flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 Array.prototype.map 和 深度值为 1的 Array.prototype.flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。

const arr1 = [1, 2, 3];
 
arr1.map(x => [x * 4]); // [[4], [8], [12]]
 
arr1.flatMap(x => [x * 4]); // [4, 8, 12]

更好的示例:

const sentence = ["This is a", "regular", "sentence"];
 
sentence.map(x => x.split(" ")); 
// [["This","is","a"],["regular"],["sentence"]]
 
sentence.map(item => item.split(' ')).flat(Infinity)
// ["This","is","a","regular", "sentence"]

sentence.flatMap(x => x.split(" ")); 
// ["This","is","a","regular", "sentence"]
 
// 可以使用 归纳(reduce) 与 合并(concat)实现相同的功能
sentence.reduce((acc, x) => acc.concat(x.split(" ")), []);

对象新增方法

1.Object.values()

   Object.values()函数和 Object.keys()很相似,它返回一个对象中自己属性的所有值(通过原型链继承的不算)。

2. Object.entries()

    Object.entries()和 Object.keys 相关,不过 entries()函数会将 key 和 value 以数组的形式都返回。这样,使用循环或则将对象转为 Map 就很方便了。

let obj = { 'dsds': 2, 'fsdsg': 3, 'gththt': 4 }
console.log(Object.entries(obj))
/* 
(3) [Array(2), Array(2), Array(2)]
0: (2) ["dsds", 2]
1: (2) ["fsdsg", 3]
2: (2) ["gththt", 4]
*/

3.Object.fromEntries (ES9)

将键值对列表转换为 Object 的新方法。

它与已有 Object.entries() 正好相反,Object.entries()方法在将对象转换为数组时使用,它返回一个给定对象自身可枚举属性的键值对数组。

但现在您可以通过 Object.fromEntries 将操作的数组返回到对象中。

const obj = { prop1: 2, prop2: 10, prop3: 15 };
 
// 转化为键值对数组:
let array = Object.entries(obj); 
// [["prop1", 2], ["prop2", 10], ["prop3", 15]]
// 将所有对象属性的值平方:
array = array.map(([key, value]) => [key, value ** 2]); 
// [["prop1", 4], ["prop2", 100], ["prop3", 225]]

我们将转换后的数组 array 作为参数传入 Object.fromEntries ,将数组转换成了一个对象:

const newObj = Object.fromEntries(array); 
// {prop1: 4, prop2: 100, prop3: 225}

数函数的中缀形式

加/减法我们通常都是用其中缀形式,直观易懂。在 ECMAScript2016 中,我们可以使用**来替代 Math.pow。

 

如果你看到这里并且感觉对你有那么一点帮助的话,请点赞或评论鼓励一下我。

你可能感兴趣的:(js基础部分,学习笔记)