你不知道的ES6新特性

1,326 阅读5分钟

ECMAScript 6 目前基本成为业界标准,它的普及速度比 ES5 要快很多,主要原因是现代浏览器对 ES6 的支持相当迅速,尤其是 Chrome 和 Firefox 浏览器,已经支持 ES6 中绝大多数的特性。

第一章 let、const 和 block 变量声明作用域

1.1 let 允许创建块级作用域,ES6 推荐在函数中使用 let 定义变量,而非 var:

var a = 2;
{
  let a = 3;
  console.log(a); // 3
}
console.log(a); // 2

同样在块级作用域有效的另一个变量声明方式是 const,它可以声明一个常量。ES6 中,const 声明的常量类似于指针,它指向某个引用,也就是说这个「常量」并非一成不变的,如:

{
  const ARR = [5,6];
  ARR.push(7);
  console.log(ARR); // [5,6,7]
  ARR = 10; // TypeError
}

1.2 有几个点需要注意:

1.2.1 let 关键词声明的变量不具备变量提升(hoisting)特性

function test () {
    console.log(a);  //undefined
    var a = 123; 
};
等同于==>
                    function test(){
                        var a;
                        console.log(a)
                        a = 123
                    }
使用var 定义变量时,js会提前把你定义的变量名在函数执行前声明,但却不赋值。
因此在test函数中console.log(a) 会出现 undefined 的结果

1.2.2经典变量声明提升面试题

console.log(v1);
var v1 = 100;
function foo() {
    console.log(v1);
    var v1 = 200;
    console.log(v1);
}
foo();
console.log(v1);
// undefined  undefined 200  100

1.2.3 函数提升:具名函数的声明有两种方式

1.2.1 函数声明式  
function bar () {}

1.2.2 函数字面量式
var foo = function () {}

函数字面量式的声明合变量提升的结果是一样的,函数只是一个具体的值; 但是函数声明式的提升现象和变量提升略有不同,函数声明式会提升到作用域最前边

1.2.4 函数式声明与字面量声明有什么区别呢?

(I)函数式声明
console.log(foo)  =>//function foo(){console.log("test")}
function foo(){
    console.log("test")
}
(Ⅱ) 字面量声明
console.log(foo)  =>//undefined
var foo = function(){
    console.log('test')
}

1.3 请看题

1.3.1

foo(); //1
var foo;
function foo () {
    console.log(1);
}
 

1.3.2

foo = function () {
    console.log(2);
}
foo(); //2

1.4 敲黑板啦!!! => 画重点 =>关于变量提升问题的总结

1.4.1 所有的声明都会提升到作用域的最顶上去。

1.4.2 同一个变量只会声明一次,其他的会被忽略掉或者覆盖掉。

1.4.3 函数声明的优先级高于变量声明的优先级,并且函数声明和函数定义的部分一起被提升。

1.5let 和 const 声明只在最靠近的一个块中(花括号内)有效

function(){
    let str = "hello world"
    consloe.log(str) // hello world
}
console.log(str)//undefined
const 等同

1.6当使用常量 const 声明时,请使用大写变量,如:CAPITAL_CASING

1.7const 在声明时必须被赋值

const a = '100';
console.log(a)//100;
const b;
console.log(b)//报错
使用const声明变量或函数时必须被赋值

第二章 箭头函数(Arrow Functions)()=>

2.1 ES6 中,箭头函数就是函数的一种简写形式,使用括号包裹参数,跟随一个 =>,紧接着是函数体

2.1.1 例如:

a => a * a
等同于
function(a){
    return a * a
}



2.1.2例如:如果参数不是一个,就需要用括号 () 括起来:

(a,b) => a+b


// 无参数:
() => 3.14


// 可变参数:
(x, y, ...rest) => {
    var i, sum = x + y;
    for (i=0; i<rest.length; i++) {
        sum += rest[i];
    }
    return sum;
}

2.1.3如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:

// SyntaxError:
x => { foo: x }
因为和函数体的{ ... }有语法冲突,所以要改为:

// ok:
x => ({ foo: x })

在此说明一下 ES6扩展运算符 " ... "的作用

var obj ={a:1,b:2,c:3}
console.log(...obj) // {a:1,b:2,c:3}

2.2 this指向问题

2.2.1this 总是绑定总是指向对象自身

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = function () {
            return new Date().getFullYear() - this.birth; // this指向window或undefined
        };
        return fn();
    }
};

2.2.2现在,箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj:


var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
        return fn();
    }
};
obj.getAge(); // 25

温馨提示:在使用剪头函数时之前 用 that = this;方法就不需要了

2.2.3由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略:

var obj = {
    birth: 1990,
    getAge: function (year) {
        var b = this.birth; // 1990
        var fn = (y) => y - this.birth; // this.birth仍是1990
        return fn.call({birth:2000}, year);
    }
};
obj.getAge(2015); // 25

第三章函数参数默认值

ES6 中允许你对函数参数设置默认值:

let foo = (a, b=0.7) => a + a * b;
foo(10); // 17

第四章模板语法和分隔符

4.1 ES6 中有一种十分简洁的方法组装一堆字符串和变量。

4.1.1 ${ 变量名 } 用来渲染一个变量
4.1.2 ` 作为分隔符
let user = 'Jack';
例如:
console.log(`Hi ${user}!`); // Hi Jack!

第五章 for...of VS for...in

5.1 for...of 用于遍历一个迭代器,如数组:

let nicknames = ['di', 'boo', 'punkeye'];
nicknames.size = 3;
for (let nickname of nicknames) {
  console.log(nickname);
}
// 结果: di, boo, punkeye

5.2for...in 用来遍历对象中的属性:

let nicknames = ['di', 'boo', 'punkeye'];
nicknames.size = 3;
for (let nickname in nicknames) {
  console.log(nickname);
}
Result: 0, 1, 2, size

第六章类 Class

6.1ES6 中有 class 语法。值得注意是,这里的 class 不是新的对象继承模型,它只是原型链的语法糖表现形式。 函数中使用 static 关键词定义构造函数的的方法和属性:

class Task {
  constructor() {
    console.log("task instantiated!");
  }
 
  showId() {
    console.log(23);
  }
 
  static loadAll() {
    console.log("Loading all tasks..");
  }
}
 
console.log(typeof Task); // function
let task = new Task(); // "task instantiated!"
task.showId(); // 23
Task.loadAll(); // "Loading all tasks.."

类中的继承和超集:

class Car { constructor() { console.log("Creating a new car"); } }

class Porsche extends Car {
  constructor() {
    super();
    console.log("Creating Porsche");
  }
}
 
let c = new Porsche();
// Creating a new car
// Creating Porsche

extends 允许一个子类继承父类,需要注意的是,子类的constructor 函数中需要执行 super() 函数。

当然,你也可以在子类方法中调用父类的方法,如super.parentMethodName()。

在 这里 阅读更多关于类的介绍。

有几点值得注意的是:

类的声明不会提升(hoisting),如果你要使用某个 Class,那你必须在使用之前定义它,否则会抛出一个 ReferenceError 的错误 在类中定义函数不需要使用 function 关键词