ECMAScript

ECMAScript

ECMAScript 是编写脚本语言的标准,这意味着JavaScript遵循ECMAScript标准中的规范变化,因为它是JavaScript的蓝图。
ECMAScript 和 Javascript,本质上都跟一门语言有关,一个是语言本身的名字,一个是语言的约束条件 只不过发明JavaScript的那个人(Netscape公司),把东西交给了ECMA(European Computer Manufacturers Association),这个人规定一下他的标准,因为当时有java语言了,又想强调这个东西是让ECMA这个人定的规则,所以就这样一个神奇的东西诞生了,这个东西的名称就叫做ECMAScript。
javaScript = ECMAScript + DOM + BOM(自认为是一种广义的JavaScript)
ECMAScript说什么JavaScript就得做什么!

ECMAScript 2015(ES6)有哪些新特性

  • 块作用域
  • 箭头函数
  • 模板字符串
  • 加强的对象字面
  • 对象解构
  • Promise
  • 模块
  • Symbol
  • 代理(proxy)Set
  • 函数默认参数
  • rest 和展开

    var,letconst的区别

    var声明的变量会挂载在window上,而let和const声明的变量不会:
    1. var a = 100;
    2. console.log(a,window.a); // 100 100
    3. let b = 10;
    4. console.log(b,window.b); // 10 undefined
    5. const c = 1;
    6. console.log(c,window.c); // 1 undefined
    var声明变量存在变量提升,let和const不存在变量提升:
    1. console.log(a); // undefined ===> a已声明还没赋值,默认得到undefined值
    2. var a = 100;
    3. console.log(b); // 报错:b is not defined ===> 找不到b这个变量
    4. let b = 10;
    5. console.log(c); // 报错:c is not defined ===> 找不到c这个变量
    6. const c = 10;
    let和const声明形成块作用域 ```javascript if(1){ var a = 100; let b = 10; } console.log(a); // 100 console.log(b) // 报错:b is not defined ===> 找不到b这个变量

if(1){ var a = 100; const c = 1; } console.log(a); // 100 console.log(c) // 报错:c is not defined ===> 找不到c这个变量

  1. 同一作用域下letconst不能声明同名变量,而var可以
  2. ```javascript
  3. var a = 100;
  4. console.log(a); // 100
  5. var a = 10;
  6. console.log(a); // 10
  7. -------------------------------------
  8. let a = 100;
  9. let a = 10;
  10. // 控制台报错:Identifier 'a' has already been declared ===> 标识符a已经被声明了。

暂存死区

  1. var a = 100;
  2. if(1){
  3. a = 10;
  4. //在当前块作用域中存在a使用let/const声明的情况下,给a赋值10时,只会在当前作用域找变量a,
  5. // 而这时,还未到声明时候,所以控制台Error:a is not defined
  6. let a = 1;
  7. }

const

  1. /*
  2. * 1、一旦声明必须赋值,不能使用null占位。
  3. *
  4. * 2、声明后不能再修改
  5. *
  6. * 3、如果声明的是复合类型数据,可以修改其属性
  7. *
  8. * */
  9. const a = 100;
  10. const list = [];
  11. list[0] = 10;
  12. console.log(list); // [10]
  13. const obj = {a:100};
  14. obj.name = 'apple';
  15. obj.a = 10000;
  16. console.log(obj); // {a:10000,name:'apple'}

箭头函数

箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或new.target。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数。

  1. //ES5 Version
  2. var getCurrentDate = function (){
  3. return new Date();
  4. }
  5. //ES6 Version
  6. const getCurrentDate = () => new Date();

在本例中,ES5 版本中有function(){}声明和return关键字,这两个关键字分别是创建函数和返回值所需要的。在箭头函数版本中,只需要()括号,不需要 return 语句,因为如果只有一个表达式或值需要返回,箭头函数就会有一个隐式的返回。

  1. //ES5 Version
  2. function greet(name) {
  3. return 'Hello ' + name + '!';
  4. }
  5. //ES6 Version
  6. const greet = (name) => `Hello ${name}`;
  7. const greet2 = name => `Hello ${name}`;

还可以在箭头函数中使用与函数表达式和函数声明相同的参数。如果在一个箭头函数中有一个参数,则可以省略括号。

  1. const getArgs = () => arguments
  2. const getArgs2 = (...rest) => rest

箭头函数不能访问arguments对象。所以调用第一个getArgs函数会抛出一个错误。相反,可以使用rest参数来获得在箭头函数中传递的所有参数。

  1. const data = {
  2. result: 0,
  3. nums: [1, 2, 3, 4, 5],
  4. computeResult() {
  5. // 这里的“this”指的是“data”对象
  6. const addAll = () => {
  7. return this.nums.reduce((total, cur) => total + cur, 0)
  8. };
  9. this.result = addAll();
  10. }
  11. };

箭头函数没有自己的this值。它捕获词法作用域函数的this值,在此示例中,addAll函数将复制computeResult 方法中的this值,如果在全局作用域声明箭头函数,则this值为 window 对象。

类(class)是在 JS 中编写构造函数的新方法。它是使用构造函数的语法糖,在底层中使用仍然是原型和基于原型的继承。

  1. //ES5 Version
  2. function Person(firstName, lastName, age, address){
  3. this.firstName = firstName;
  4. this.lastName = lastName;
  5. this.age = age;
  6. this.address = address;
  7. }
  8. Person.self = function(){
  9. return this;
  10. }
  11. Person.prototype.toString = function(){
  12. return "[object Person]";
  13. }
  14. Person.prototype.getFullName = function (){
  15. return this.firstName + " " + this.lastName;
  16. }
  17. //ES6 Version
  18. class Person {
  19. constructor(firstName, lastName, age, address){
  20. this.lastName = lastName;
  21. this.firstName = firstName;
  22. this.age = age;
  23. this.address = address;
  24. }
  25. static self() {
  26. return this;
  27. }
  28. toString(){
  29. return "[object Person]";
  30. }
  31. getFullName(){
  32. return `${this.firstName} ${this.lastName}`;
  33. }
  34. }

重写方法并从另一个类继承。

  1. //ES5 Version
  2. Employee.prototype = Object.create(Person.prototype);
  3. function Employee(firstName, lastName, age, address, jobTitle, yearStarted) {
  4. Person.call(this, firstName, lastName, age, address);
  5. this.jobTitle = jobTitle;
  6. this.yearStarted = yearStarted;
  7. }
  8. Employee.prototype.describe = function () {
  9. return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`;
  10. }
  11. Employee.prototype.toString = function () {
  12. return "[object Employee]";
  13. }
  14. //ES6 Version
  15. class Employee extends Person { //Inherits from "Person" class
  16. constructor(firstName, lastName, age, address, jobTitle, yearStarted) {
  17. super(firstName, lastName, age, address);
  18. this.jobTitle = jobTitle;
  19. this.yearStarted = yearStarted;
  20. }
  21. describe() {
  22. return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`;
  23. }
  24. toString() { // Overriding the "toString" method of "Person"
  25. return "[object Employee]";
  26. }
  27. }

所以要怎么知道它在内部使用原型?

  1. class Something {
  2. }
  3. function AnotherSomething(){
  4. }
  5. const as = new AnotherSomething();
  6. const s = new Something();
  7. console.log(typeof Something); // "function"
  8. console.log(typeof AnotherSomething); // "function"
  9. console.log(as.toString()); // "[object Object]"
  10. console.log(as.toString()); // "[object Object]"
  11. console.log(as.toString === Object.prototype.toString); // true
  12. console.log(s.toString === Object.prototype.toString); // true

模板字符串

模板字符串是在 JS 中创建字符串的一种新方法。可以通过使用反引号使模板字符串化。

  1. //ES5 Version
  2. var greet = 'Hi I\'m Mark';
  3. //ES6 Version
  4. let greet = `Hi I'm Mark`;

在 ES5 中需要使用一些转义字符来达到多行的效果,在模板字符串不需要这么麻烦:

  1. //ES5 Version
  2. var lastWords = '\n'
  3. + ' I \n'
  4. + ' Am \n'
  5. + 'Iron Man \n';
  6. //ES6 Version
  7. let lastWords = `
  8. I
  9. Am
  10. Iron Man
  11. `;

在ES5版本中,要添加\n以在字符串中添加新行。在模板字符串中,不需要这样做。

  1. //ES5 Version
  2. function greet(name) {
  3. return 'Hello ' + name + '!';
  4. }
  5. //ES6 Version
  6. function greet(name) {
  7. return `Hello ${name} !`;
  8. }

在 ES5 版本中,如果需要在字符串中添加表达式或值,则需要使用+运算符。在模板字符串s中,可以使用${expr}嵌入一个表达式,这使其比 ES5 版本更整洁。

对象解构

对象析构是从对象或数组中获取或提取值的一种新的、更简洁的方法。假设有如下的对象:

  1. const employee = {
  2. firstName: "Marko",
  3. lastName: "Polo",
  4. position: "Software Developer",
  5. yearHired: 2017
  6. };

从对象获取属性,早期方法是创建一个与对象属性同名的变量。这种方法很麻烦,因为要为每个属性创建一个新变量。假设有一个大对象,它有很多属性和方法,用这种方法提取属性会很麻烦。

  1. var firstName = employee.firstName;
  2. var lastName = employee.lastName;
  3. var position = employee.position;
  4. var yearHired = employee.yearHired;

使用解构方式语法就变得简洁多了:

  1. { firstName, lastName, position, yearHired } = employee;

还可以为属性取别名:

  1. let { firstName: fName, lastName: lName, position, yearHired } = employee;

当然如果属性值为 undefined 时,还可以指定默认值:

  1. let { firstName = "Mark", lastName: lName, position, yearHired } = employee;

Set对象

Set 对象允许存储任何类型的唯一值,无论是原始值或者是对象引用。
可以使用Set构造函数创建Set实例。

  1. const set1 = new Set();
  2. const set2 = new Set(["a","b","c","d","d","e"]);

可以使用add方法向Set实例中添加一个新值,因为add方法返回Set对象,可以以链式的方式再次使用add。如果一个值已经存在于Set对象中,那么它将不再被添加。

  1. set2.add("f");
  2. set2.add("g").add("h").add("i").add("j").add("k").add("k");
  3. // 后一个“k”不会被添加到set对象中,因为它已经存在了

可以使用has方法检查Set实例中是否存在特定的值。

  1. set2.has("a") // true
  2. set2.has("z") // true

可以使用size属性获得Set实例的长度。

  1. set2.size // returns 10

可以使用clear方法删除 Set 中的数据。

  1. set2.clear();

可以使用Set对象来删除数组中重复的元素。

  1. const numbers = [1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 5];
  2. const uniqueNums = [...new Set(numbers)]; // [1,2,3,4,5,6,7,8]

另外还有WeakSet, 与 Set 类似,也是不重复的值的集合。但是 WeakSet 的成员只能是对象,而不能是其他类型的值。WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet对该对象的引用。

  • Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
  • WeakMap 结构与 Map 结构类似,也是用于生成键值对的集合。但是 WeakMap 只接受对象作为键名( null 除外),不接受其他类型的值作为键名。而且 WeakMap 的键名所指向的对象,不计入垃圾回收机制。

    Proxy

    Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”,即对编程语言进行编程。
    Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。