ES6相关介绍

发布于 2023-06-18 分类: 教程

ECMAScript相关介绍

  1. 什么是ECMA ECMA(European Computer Manufacturers Association)中文名称为欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准,1994 年后该组织改名为Ecma 国际

  2. 什么是ECMAScript ECMAScript 是E尺码国际通过ECMA-262标准化的脚本程序设计语言。ECMAScript定义了一套脚本语言的标准,规定了语法、类型、语句、关键字、保留字、操作符、对象等方面的规范。JavaScript是ECMAScript的一种实现,同时还包括了浏览器和Node.js等环境提供的API和对象。由于ECMAScript是一种标准化的语言,所以不同的JavaScript实现都应该遵循ECMAScript标准,以确保代码的可移植性和互操作性。

ECMAScript 6 新特性

1. let 关键字

let 关键字用来声明变量,使用let声明的变量有以下特点:

2. cosnt 关键字

const 关键字用来声明常量,从const声明有以下特点:

注意:对象属性修改和元素变化不会发出const错误 应用场景:声明对象类型使用const,非对象类型声明选择let

const arr = [1, 2, 3, 4];
arr.push(5, 6);
console.log(arr); // 不报错

const obj = {
uanme: 'rick',
age: 20;
}
obj.age = 11; // 只要不改变地址,就不报错

3. 变量的解构赋值

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

// 以下是一个使用数组解构赋值案例:
const arr = [1, 2, 3];
const [a, b, c] = arr;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
// 以下是一个使用对象解构赋值案例:
const obj = { x: 1, y: 2, z: 3 };
const { x, y, z } = obj;
console.log(x); // 1
console.log(y); // 2
console.log(z); // 3

4. 模板字符串

模板字符串是增强版的字符串,用反引号来标识,特点:

应用场景:当遇到字符串与变量拼接的情况使用模板字符串

let name = 'jack';
console.log(`hello, ${name}`);

let ul = 
`
  <ul>
   <li>1</li>
   <li>2</li>
   <li>3</li>
  </ul>
`

5. 简化对象写法

在 ES6 中,我们可以使用简化对象写法来定义对象。这种写法可以让我们更加简洁地定义对象,避免了重复书写属性名和属性值

应用场景:以后就用简写就行

const name = 'John';
const age = 30;

const person = {
  name,
  age
};

console.log(person); // { name: 'John', age: 30 }

// 在上面的代码中,我们定义了一个 `person` 对象,使用了简化对象写法。我们只需要写出属性名,然后将变量名赋值给属性名即可。这样就可以定义一个具有 `name` 和 `age` 属性的对象。

6. 箭头函数

ES6允许使用 => 定义函数

注意:

person.sayName(); //在这个例子中,箭头函数sayName被定义在person对象内部,因此它的this指向是person对象所在的作用域下的this值,即全局的this值。因此,当我们调用person.sayName()时,它会输出undefined。

// 用普通函数定义 const person = { name: ‘Alice’, sayName: function() { console.log(this.name); } };

person.sayName(); //在这个例子中,sayName方法使用普通函数来定义,因此它的this指向是动态的,即指向调用该方法的对象,也就是person对象。因此,当我们调用person.sayName()时,它会输出Alice。


* **箭头函数不能作为构造函数实例化**
```js
// 箭头函数,不能被用作构造函数来创建实例化对象。这是因为箭头函数没有自己的 this 值,它的 this 值是继承自它所在的上下文
const Person = (name) => {
  this.name = name;
};

const john = new Person('John'); // TypeError: Person is not a constructor

function Person(name) {
  this.name = name;
}



// 普通函数
const john = new Person('John');
console.log(john.name); // "John"

function traditionalFunction() {
  console.log(arguments);
}

const arrowFunction = () => {
  console.log(arguments);
}

traditionalFunction(1, 2, 3); // 输出 [1, 2, 3]
arrowFunction(1, 2, 3); // 报错:arguments is not defined

// 在这个例子中,我们定义了一个传统函数 `traditionalFunction` 和一个箭头函数 `arrowFunction`,并且在它们内部分别打印了 `arguments` 对象。当我们调用 `traditionalFunction` 时,它会输出 `[1, 2, 3]`,因为 `arguments` 对象存在并包含了传入的参数。但是,当我们调用 `arrowFunction` 时,它会抛出一个错误,因为 `arguments` 对象不存在


// 因此,如果我们需要在箭头函数中获取参数,我们可以使用剩余参数语法 `...args` 来代替 `arguments` 对象。
const arrowFunction = (...args) => {
  console.log(args);
}

arrowFunction(1, 2, 3); // 输出 [1, 2, 3]

7. 剩余参数rest

JavaScript 的剩余参数语法(rest parameter syntax)用三个点(…)表示,用于将函数的多个参数收集成一个数组

例如,以下函数的参数列表中使用了剩余参数语法:

function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}

console.log(sum(1, 2, 3)); // 6
console.log(sum(4, 5, 6, 7)); // 22

在这个例子中,sum 函数的参数列表中使用了剩余参数语法,将传入函数的所有参数收集成一个名为 numbers 的数组。函数内部使用 reduce 方法对数组中的所有元素求和,并返回求和结果

需要注意的是,剩余参数语法只能用于函数的最后一个参数

当我们在定义一个函数时,可以使用剩余参数语法来表示函数可以接受任意数量的参数。但是需要注意的是,剩余参数语法只能用于函数的最后一个参数

举个例子,假设我们要定义一个函数,用于计算任意数量的数字的平均值。我们可以使用剩余参数语法来实现:

function average(...numbers) {
  let sum = 0;
  for (let number of numbers) {
    sum += number;
  }
  return sum / numbers.length;
}

在这个例子中,...numbers表示可以接受任意数量的参数,并将它们存储在一个数组中。我们可以像这样调用这个函数:

console.log(average(1, 2, 3)); // 输出 2
console.log(average(4, 5, 6, 7)); // 输出 5.5

需要注意的是,剩余参数语法只能用于函数的最后一个参数。例如,下面这个函数定义是错误的:

function example(...numbers, x) {
  // 错误的函数定义,剩余参数语法不能用于函数的最后一个参数之前
}

8. 函数参数默认值设定

ES6允许给函数参数设置默认值,当调用函数时不给实参,则使用参数默认值,有默认值的形参一般要靠后

let add = (x, y, z=3) => x + y +z;
console.log(add(1, 2)); // 6

9. Spread扩展运算符

JS中的扩展运算符(spread operator)是三个点(…),它可以将一个数组或对象“展开”成多个独立的值。下面是一些扩展运算符的使用示例:

  1. 将数组展开成函数参数:
const arr = [1, 2, 3];
console.log(...arr); // 1 2 3

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

console.log(sum(...arr)); // 6
  1. 合并数组:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [...arr1, ...arr2];

console.log(arr3); // [1, 2, 3, 4, 5, 6]
  1. 复制数组:
const arr1 = [1, 2, 3];
const arr2 = [...arr1];

console.log(arr2); // [1, 2, 3]
  1. 将对象展开成另一个对象:
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };

console.log(obj2); // { a: 1, b: 2, c: 3 }
  1. 复制对象:
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1 };

console.log(obj2); // { a: 1, b: 2 }

10. Symbol

JavaScript 中的 Symbol 是一种基本数据类型,用于创建唯一且不可变的值,通常用作对象属性的键名。Symbol 值可以通过 Symbol() 函数进行创建,如下所示:

const mySymbol = Symbol();

Symbol 值可以作为对象的属性键名,如下所示:

const mySymbol = Symbol();
const myObj = {};
myObj[mySymbol] = 'Hello World';
console.log(myObj[mySymbol]); // 输出 'Hello World'

由于每个 Symbol 值都是唯一的,因此它们可以用于创建私有属性或方法,以避免命名冲突。例如,我们可以使用 Symbol 值作为对象的私有属性,如下所示:

const mySymbol = Symbol('myPrivateProperty');
class MyClass {
  constructor() {
    this[mySymbol] = 'This is a private property';
  }
  getPrivateProperty() {
    return this[mySymbol];
  }
}
const myObj = new MyClass();
console.log(myObj.getPrivateProperty()); // 输出 'This is a private property'
console.log(myObj[mySymbol]); // 输出 undefined,因为 mySymbol 是私有属性,无法直接访问

除了使用 Symbol() 函数创建 Symbol 值外,还可以使用 Symbol.for() 函数创建全局共享的 Symbol 值。例如,我们可以使用 Symbol.for() 函数创建一个全局共享的 Symbol 值,并将其作为对象的属性键名,如下所示:

const myGlobalSymbol = Symbol.for('myGlobalSymbol');
const myObj = {};
myObj[myGlobalSymbol] = 'Hello World';
console.log(myObj[myGlobalSymbol]); // 输出 'Hello World'

注意,使用 Symbol.for() 函数创建的 Symbol 值会被添加到全局符号注册表中,可以在不同的代码文件中共享和访问

11. 迭代器

在 JavaScript 中,Symbol 是一种新的原始数据类型,它可以用来创建唯一的标识符,这些标识符可以用于对象的属性名或者其他需要唯一标识符的场合。而迭代器(Iterator)是一种对象,它提供了一种访问集合(如数组、对象和字符串等)中元素的方式,可以逐个访问集合中的元素,而不需要了解集合的内部实现。Symbol 和迭代器之间的关系是,迭代器使用 Symbol.iterator 属性来定义自己的迭代器方法,该方法返回一个迭代器对象,该对象包含一个 next() 方法,用于迭代集合中的元素。

举个例子,假设我们有一个数组,我们可以使用 Symbol.iterator 属性来定义一个迭代器方法,该方法返回一个迭代器对象,我们可以使用该对象的 next() 方法来逐个访问数组中的元素。下面是一个简单的例子:

const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();

console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

在上面的例子中,我们首先获取了数组的迭代器对象,然后使用该对象的 next() 方法来逐个访问数组中的元素,直到所有元素都被访问完毕。每次调用 next() 方法时,都会返回一个包含当前元素值和是否遍历完成的对象。当遍历完成时,done 属性为 true,value 属性为 undefined

需要注意的是,Symbol.iterator 属性只能在可迭代对象上使用,即实现了 @@iterator 方法的对象。常见的可迭代对象包括数组、Set、Map、字符串等

除了数组,ES6 还为许多内置集合类型(如 Set、Map 等)和自定义对象提供了迭代器支持。我们可以使用 for…of 循环来遍历这些集合类型中的元素,例如:

const mySet = new Set([1, 2, 3]);
for (const value of mySet) {
  console.log(value);
}
// Output: 1 2 3

const myMap = new Map([['a', 1], ['b', 2], ['c', 3]]);
for (const [key, value] of myMap) {
  console.log(key, value);
}
// Output: a 1 b 2 c 3

在这些例子中,我们使用 for…of 循环来遍历集合类型中的元素。由于这些集合类型都实现了迭代器,因此我们可以直接使用 for…of 循环来遍历它们中的元素,而不需要手动调用 next() 方法

工作原理
  1. 创建一个指针对象,指向当前数据解构的起始位置
  2. 第一次调用对象的next方法,指针自动指向数据解构的第一个对象
  3. 接下来不断调用next对象,指针一直往后移动,直到指向最后一个成员
  4. 每调用next方法,返回一个包含value和done的属性的对象

应用场景:需要自定义遍历数据的时候,要想到迭代器

自定义遍历数据

在 JavaScript 中,我们可以使用自定义迭代器来遍历数据。自定义迭代器是一个对象,它定义了一个 next() 方法,当调用 next() 方法时,它返回一个包含 value 和 done 属性的对象,value 属性表示当前迭代到的值,done 属性为 true 表示迭代结束,为 false 表示还有更多的值需要迭代

下面是一个简单的例子,展示了如何使用自定义迭代器来遍历一个数组:

const myArray = [1, 2, 3];

const myIterator = {
  [Symbol.iterator]: function() {
    let index = 0;
    return {
      next: function() {
        if (index < myArray.length) {
          return { value: myArray[index++], done: false };
        } else {
          return { done: true };
        }
      }
    };
  }
};

for (let value of myIterator) {
  console.log(value); // 1 2 3
}

在这个例子中,我们定义了一个名为 myIterator 的对象,它包含一个 Symbol.iterator 方法,该方法返回一个包含 next() 方法的对象。next() 方法返回一个包含当前迭代到的值和是否迭代结束的对象。我们可以使用 for…of 循环来遍历 myIterator 对象,每次迭代时都会调用 next() 方法,直到 done 属性为 true 为止

回调函数

回调函数是 JavaScript 中常见的一种编程模式,通常用于异步编程。一个回调函数就是一个函数,它作为参数传递给另一个函数,并且在该函数执行完毕后被调用。

以下是一个简单的例子,演示了如何使用回调函数来处理异步操作:

function fetchData(callback) {
  setTimeout(() => {
    const data = { name: "John", age: 30 };
    callback(data);
  }, 2000);
}

function displayData(data) {
  console.log(`Name: ${data.name}, Age: ${data.age}`);
}

fetchData(displayData);

这段代码的执行顺序和流程如下:

  1. 首先,调用 fetchData 函数,并将 displayData 函数作为参数传递给它。

  2. 在 fetchData 函数中,使用 setTimeout 函数模拟了一个异步操作,它会在 2000 毫秒后执行一个回调函数。

  3. 在回调函数中,创建了一个包含 name 和 age 属性的对象,并将其作为参数传递给回调函数 callback。

  4. fetchData 函数执行完毕后,控制权被返回到调用它的地方,即主程序。

  5. 在主程序中,fetchData 函数的返回值为 undefined,因为它没有显式返回任何值。

  6. 2000 毫秒后,setTimeout 函数执行回调函数。回调函数中调用了 displayData 函数,并将包含 name 和 age 属性的对象作为参数传递给它。

  7. displayData 函数被调用,它会在控制台中输出 Name: John, Age: 30。

因此,整个程序的输出结果是 Name: John, Age: 30。

12. Promise

Promise的定义和使用

Promise是ES6引入的异步编程的新解决方案,语法上Promise是一个构造函数,用来封装一部操作并可以获取其成功或失败的结果

一个Promise必然处于以下三种状态之一 :

Promise的使用 :

当我们需要处理异步操作时,Promise 是一种非常有用的工具。Promise 是一个对象,它代表了一个异步操作的最终完成或失败,并且可以在完成或失败后返回一个值

下面是一个使用 Promise 的例子:

const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    const randomNum = Math.random();
    if (randomNum > 0.5) {
      resolve(randomNum);
    } else {
      reject('Random number is too low');
    }
  }, 1000);
});

promise.then((result) => {
  console.log(`The random number is ${result}`);
}).catch((error) => {
  console.log(`Error: ${error}`);
});

在这个例子中,我们创建了一个 Promise 对象,并传入一个函数作为参数。这个函数接受两个参数:resolve 和 reject。当异步操作成功时,我们调用 resolve 函数并传入结果值。如果异步操作失败,则调用 reject 函数并传入错误信息

接着,我们使用 then 方法来处理 Promise 对象的成功情况,并使用 catch 方法来处理 Promise 对象的失败情况。在 then 方法中,我们可以访问异步操作的结果值,并进行一些处理。在 catch 方法中,我们可以访问异步操作的错误信息,并进行一些处理

在 JavaScript 中,我们可以使用 Promise 对象来封装 Ajax 请求。下面是一个简单的示例:

function ajax(url) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onload = function() {
      if (xhr.status === 200) {
        resolve(xhr.response);
      } else {
        reject(Error(xhr.statusText));
      }
    };
    xhr.onerror = function() {
      reject(Error('Network Error'));
    };
    xhr.send();
  });
}

// 调用示例
ajax('https://jsonplaceholder.typicode.com/posts')
  .then(function(response) {
    console.log('成功获取到数据:', response);
  })
  .catch(function(error) {
    console.log('获取数据失败:', error);
  });
  

在上面的示例中,我们定义了一个名为 ajax 的函数,它接受一个 URL 参数,并返回一个 Promise 对象。在 Promise 构造函数中,我们使用 XMLHttpRequest 对象来发送 Ajax 请求,并在请求成功或失败时调用 resolve 或 reject 方法来改变 Promise 的状态。在 then 方法中,我们定义了成功获取数据后的回调函数,而在 catch 方法中,我们定义了获取数据失败后的回调函数