ECMA Script 6 学习笔记

博客分类: note 阅读次数: 🤔

ECMA Script 6 学习笔记

ECMA Script 6

目的

  当然是系统学习es6啦。。。并快速了解es6的新特性,并未过多深入。想通过二八定律先全面了解ES6的新特性。

es6简介

  简单总结下相关知识点。

es6是什么?

  ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准。本书中提到 ES6 的地方,一般是指 ES2015 标准,但有时也是泛指“下一代 JavaScript 语言”。

如何查看浏览器兼容性?

各大浏览器的最新版本,对 ES6 的支持可以查看。随着时间的推移,支持度已经越来越高了,超过 90%的 ES6 语法特性都实现了。

nodejs如何查看

Node 是 JavaScript 的服务器运行环境(runtime)。它对 ES6 的支持度更高。除了那些默认打开的功能,还有一些语法功能已经实现了,但是默认没有打开。使用下面的命令,可以查看 Node 已经实现的 ES6 特性。

 $ node --v8-options | grep harmony

上面命令的输出结果,会因为版本的不同而有所不同。

转码器

  考虑到有可能部分浏览器对es6兼容性可能存在问题,所以有时候需要将es6转成es5,去解决兼容性问题。

Babel 转码器

  Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而在现有环境执行。这意味着,你可以用 ES6 的方式编写程序,又不用担心现有环境是否支持。下面是一个例子。

    // 转码前
    input.map(item => item + 1);

    // 转码后
    input.map(function (item) {
    return item + 1;
    });

上面的原始代码用了箭头函数,Babel 将其转为普通函数,就能在不支持箭头函数的 JavaScript 环境执行了。

Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API,比如IteratorGeneratorSetMapsProxyReflectSymbolPromise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。

举例来说,ES6 在Array对象上新增了Array.from方法。Babel 就不会转码这个方法。

Traceur 转码器

  Google 公司的Traceur转码器,也可以将 ES6 代码转为 ES5 代码。

此处不展开深究,有兴趣的自行了解 Traceur Transcoding Demo

let 和 const 关键字

let 关键字

ES6 新增了let关键字,用来声明变量。它的用法类似于var,但是所声明的变量,只在let关键字所在的代码块内有效。

应用场景

for循环的计数器,就很合适使用let命令。

for (let i = 0; i < 10; i++) {
  // ...
}
console.log(i);
// ReferenceError: i is not defined

上面代码中,计数器i只在for循环体内有效,在循环体外引用就会报错。

ES6 的块级作用域

let 实际上为 JavaScript 新增了块级作用域。

    function f1() {
    let n = 5;
    if (true) {
        let n = 10;
    }
    console.log(n); // 5
    }

块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。

    // IIFE 写法
    (function () {
        var tmp = ...;
        ...
    }());

    // 块级作用域写法
    {
        let tmp = ...;
        ...
    }

const 关键字

const声明一个只读的常量。

  1. 一旦声明,常量的值就不能改变。
  2. 一旦声明变量,就必须立即初始化,不能留到以后赋值。
  3. const的作用域与let命令相同:只在声明所在的块级作用域内有效。
  4. const声明的常量,也与let一样不可重复声明。

应用场景

const PI = 3.1415;
console.log(PI) // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

变量的解构赋值

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

数组解构

下面是数组赋值并且交换值的例子

//ES6
let list = [ 1, 2, 3 ];
let [ a, , b ] = list ; // a=1 ,b=3
[ b, a ] = [ a, b ] ;//a=3,b=1   
//ES5
var list = [ 1, 2, 3 ];
var a = list[0], b = list[2];
var tmp = a; a = b; b = tmp;

对象的解构赋值

//ES6
let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo //aaa
bar //bbb
//ES5
var tmp = { foo: "aaa", bar: "bbb" };
var foo  = tmp.foo; //aaa
var bar = tmp.bar; //bbb

字符串的解构赋值

//ES6
const [a,b,c,d,e] = 'hello';
a //h
b //e
c //l
d //l
e //o
/*
类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。
 (然而个人觉得貌似没啥用啊,至少这个应用场景会很少,先了解下即可)
*/
let {length : len} = 'hello';
len // 5
 //ES5
 var hello ='hello';
 var a,b,c,d,e;
 a=hello[0]; 
 b=hello[1];
 c=hello[2];
 d=hello[3];
 e=hello[4];
 a //h
 b //e
 c //l
 d //l
 e //o
 /*
    对应ES6 获取数组长度
 */
 var len = hello.length;
 len //5

函数参数的解构赋值

//ES6
function f ([ name, val ]) {
    console.log(name, val)
}
function g ({ name: n, val: v }) {
    console.log(n, v)
}
function h ({ name, val }) {
    console.log(name, val)
}
f([ "bar", 42 ])
g({ name: "foo", val:  7 })
h({ name: "bar", val: 42 })
 //ES5
function f (arg) {
    var name = arg[0];
    var val  = arg[1];
    console.log(name, val);
};
function g (arg) {
    var n = arg.name;
    var v = arg.val;
    console.log(n, v);
};
function h (arg) {
    var name = arg.name;
    var val  = arg.val;
    console.log(name, val);
};
f([ "bar", 42 ]);
g({ name: "foo", val:  7 });
h({ name: "bar", val: 42 });

应用场景

交换变量值

let x = 1;
let y = 2;

[x, y] = [y, x];

函数返回多个返回值

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。

// 返回一个数组

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一个对象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();

函数参数的定义

解构赋值可以方便地将一组参数与变量名对应起来。 56

// 参数是一组有次序的值  实际应用场景很少用
function f([x, y, z]) { ... }
f([1, 2, 3]);

// 参数是一组无次序的值 实际应用场景非常有用
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});

提取 JSON 数据

let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};

let { id, status, data: number } = jsonData; //非常有用,rn+redux项目就是这样获取数据绑定视图层展示的

console.log(id, status, number);
// 42, "OK", [867, 5309]

函数参数的默认值

//ES6
function test (_params='default value',_async=true,_callback=function(){}){

}
//ES5
function test(_params,_async,_callback){
    if(_params===''|| _params===null|| _params===undefined) _params='default value';
    if(_async===''|| _async===null|| _async===undefined) _async=true;
    if(_callback===''||_callback===null||_callback===undefined) _callback=function(){};
}

New Built-In Methods(ES6的新支持函数)

Object Property Assignment (浅拷贝)

Object.assign方法用于对象的合并,将源对象( source )的所有可枚举属性,复制到目标对象( target )。

注意:

  1. 如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。(克隆对象)
  2. Object.assign() 只是一级属性复制,比浅拷贝多深拷贝了一层而已。用的时候,还是要注意这个问题的。
//ES6
let dest = { quux: 0 }
let src1 = { foo: 1, bar: 2 }
let src2 = { foo: 3, baz: 4 }
Object.assign(dest, src1, src2)
//dest.quux === 0
//dest.foo  === 3
//dest.bar  === 2
//dest.baz  === 4

//ES5
var dest = { quux: 0 };
var src1 = { foo: 1, bar: 2 };
var src2 = { foo: 3, baz: 4 };
Object.keys(src1).forEach(function(k) {
    dest[k] = src1[k];
});
Object.keys(src2).forEach(function(k) {
    dest[k] = src2[k];
});
//dest.quux === 0;
//dest.foo  === 3;
//dest.bar  === 2;
//dest.baz  === 4;

Array Element Finding (数组查找)

数组查找新增函数

//ES6
[ 1, 3, 4, 2 ].find(x => x > 3) // 4
[ 1, 3, 4, 2 ].findIndex(x => x > 3) // 2

//ES5
[ 1, 3, 4, 2 ].filter(function (x) { return x > 3; })[0]; // 4
// no equivalent in ES5

String Repeating (字符串重复)

感觉没啥应用场景,暂时想不到,join倒是以前常用,将数组拼接的html模板join成字符串。

//ES6
" ".repeat(4 * depth)
"foo".repeat(3)

//ES5 
//能想到这种方式做字符串拷贝的也是 6666666
Array((4 * depth) + 1).join(" ");
Array(3 + 1).join("foo");

String Searching (字符串查找)

Es6 提供了新的函数进行字符串查找,第二个参数为字符串出现的index

//ES6
"hello".startsWith("ello", 1) // true
"hello".endsWith("hell", 4)   // true
"hello".includes("ell")       // true
"hello".includes("ell", 1)    // true
"hello".includes("ell", 2)    // false

//ES5 
"hello".indexOf("ello") === 1;    // true
"hello".indexOf("hell") === (4 - "hell".length); // true
"hello".indexOf("ell") !== -1;    // true
"hello".indexOf("ell", 1) !== -1; // true
"hello".indexOf("ell", 2) !== -1; // false

Number Type Checking (数值校验)

//ES6
Number.isNaN(42) === false
Number.isNaN(NaN) === true

Number.isFinite(Infinity) === false
Number.isFinite(-Infinity) === false
Number.isFinite(NaN) === false
Number.isFinite(123) === true

//ES5 
var isNaN = function (n) {
    return n !== n;
};
var isFinite = function (v) {
    return (typeof v === "number" && !isNaN(v) && v !== Infinity && v !== -Infinity);
};
isNaN(42) === false;
isNaN(NaN) === true;

isFinite(Infinity) === false;
isFinite(-Infinity) === false;
isFinite(NaN) === false;
isFinite(123) === true;

Number Safety Checking (数值范围校验)

校验数值是否在一个安全的范围内

//ES6
Number.isSafeInteger(42) === true
Number.isSafeInteger(9007199254740992) === false

//ES5 
function isSafeInteger (n) {
    return (
           typeof n === 'number'
        && Math.round(n) === n
        && -(Math.pow(2, 53) - 1) <= n
        && n <= (Math.pow(2, 53) - 1)
    );
}
isSafeInteger(42) === true;
isSafeInteger(9007199254740992) === false;

Number Comparison (数值比较)

ES6的Number对象新增了一个常量Number.EPSILON。这个值很小。引入这么小的一个常量的目的在于,为浮点数计算设置一个误差范围。因为浮点数的计算是不精确的。如果误差小于Number.EPSILON,我们就可以认为得到了正确的结果。

// 举个例子吧:
0.1+0.2;      //0.30000000000000004
0.1+0.2-0.3;     //5.551115123125783e-17
(0.1+0.2-0.3).toFixed(20);    //"0.00000000000000005551"
// 那么我们再来看看0.1+0.2-0.3的值是否小于Number.EPSILON,如果小于,返回true,那我们便可以认为结果正确
(0.1+0.2-0.3).toFixed(20)<Number.EPSILON;   // true

//当然我觉得不如这样好了 囧
Number.parseFloat((0.1+0.2).toFixed(2))===0.3

Number Truncation

方法会将数字的小数部分去掉,只保留整数部分。

//ES6
console.log(Math.trunc(42.7)) // 42
console.log(Math.trunc( 0.1)) // 0
console.log(Math.trunc(-0.1)) // -0


//ES5 
function mathTrunc (x) {
    return (x < 0 ? Math.ceil(x) : Math.floor(x));
}
console.log(mathTrunc(42.7)) // 42
console.log(mathTrunc( 0.1)) // 0
console.log(mathTrunc(-0.1)) // -0

Number Sign Determination (确定数字符号)

此函数共有5种返回值, 分别是 1, -1, 0, -0, NaN. 代表的各是正数, 负数, 正零, 负零, NaN。

//ES6
console.log(Math.sign(7))   // 1
console.log(Math.sign(0))   // 0
console.log(Math.sign(-0))  // -0
console.log(Math.sign(-7))  // -1
console.log(Math.sign(NaN)) // NaN

//ES5
function mathSign (x) {
    return ((x === 0 || isNaN(x)) ? x : (x > 0 ? 1 : -1));
}
console.log(mathSign(7))   // 1
console.log(mathSign(0))   // 0
console.log(mathSign(-0))  // -0
console.log(mathSign(-7))  // -1
console.log(mathSign(NaN)) // NaN

参考