Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

29.ES6 笔记一 #30

Open
ccforward opened this issue Jul 5, 2016 · 0 comments
Open

29.ES6 笔记一 #30

ccforward opened this issue Jul 5, 2016 · 0 comments

Comments

@ccforward
Copy link
Owner

ccforward commented Jul 5, 2016

ES6 笔记一

思维导图

1. let const

1.1 let

  • 基本用法

    {
        let a = 10;
        var b= 1;
    }
    console.log(a) // error
    console.log(b) // 1

    let 很适合用在 for 循环中的计数器

  • 不存在变量提升

    console.log(foo); // ReferenceError
    let foo = 10;
    
    // typeof 将不再是一个百分百安全的操作
    typeof x ; // ReferenceError
    let x;
  • 暂时性死区 (TDZ temporal dead zone)
    只要块级作用域内存在 let 命令,它所声明的变量就 "绑定" 这个区域,不再受外部的影响

    var tmp = 123;
    if(true){
        // TDZ 开始
        tmp = 'abc';  // ReferenceError
        console.log(tmp);  // ReferenceError
        let tmp;  // TDZ 结束
    }
  • 不允许重复声明
    let 不允许在相同作用域内重复声明同一个变量

    // 报错
    function() {
        var a = 10;
        let a = 10;
    }
    
    // 报错
    function() {
        let b = 10;
        let b = 10;
    }
    
    // 报错
    function(arg) {
        let arg ;
    }
    
    // 不报错
    function(arg) {
        {
            let arg ;
        }
    }

1.2 块级作用域

  • 块级作用域的出现让广泛应用的 IIFE 不再必要了

    // IIFE 写法
    (function(){
        var tmp = '';
        ....
    })()
    
    // 块级作用域写法
    {
        let tmp = '';
        ....
    }
  • 块级作用域外部无法调用块级作用域内部的函数

    {
        let a = 'aaa';
        function f() {
            return a;
        }
    }
    f() // 报错

    这样来处理

    let f;
    {
        let a = 'aaa';
        f = function() {
        return a;
        }
    }
    f() // 'aaa'

1.3 const

声明常量

  • const一旦声明就必须立即初始化,不能留到以后赋值。

    const foo;
    // SyntaxError: missing = in const declaration
  • const 复合型变量
    变量名不指向数据,而是指向数据所在的地址。

    const foo = {};
    foo.prop = 123;
    
    foo.prop; // 123
    
    foo = {}; // 报错  read-only

真想冻结对象 可用 freeze 方法
const foo = Object.freeze({});

1.4 跨模块常量

const声明的常量只在当前代码块有效。如下方法来跨模块:

//constants.js 模块
export const A = 1;
export const B = 2;
export const C = 3;

// test1.js 模块
import * as constants from './constants';
console.log(constants.A); // 1
console.log(constants.B); // 2

// test2.js 模块
import {A, B} from './constants';
console.log(A); // 1
console.log(B); // 2

1.5 全局对象的属性

ES6中规定

  • var 和 function 声明的全局变量依旧是全局对象的属性
  • let const class 声明的全局变量不属于全局对象的属性
var a = 1;
window.a; // 1

let b = 1;
window.b; // undefined

2. 变量解构赋值 Destructuring

按照一定模式,从数组和对象中提取值,对变量进行赋值。

2.1 Array

  • 用法

    var [a, b, c] = [1, 2, 3];
    let [foo, [[bar], baz]] = [1, [[2], 3]];
    
    let [head, ...tail] = [1, 2, 3, 4, 5];
    // head 1
    // tail [2, 3, 4, 5]
    
    const [x, y, ...z] = ['a'];
    // x 'a'
    // y undefined
    // z []

结构不成功, 变量的值就是 undefind

  • 如果等号的右边不是 可遍历结构 ,那将会报错

    // 全部报错
    var [foo] = 1;
    var [foo] = false;
    let [foo] = NaN;
    let [foo] = undefined;
    let [foo] = null;
    let [foo] = {};

    因为上面等号右边的值, 幺妹转为对象后不具备 Iterator 接口(前5个),要么本身就不具备 Iterator 接口(最后一个)。

    Set 结构, 也可以使用数组的解构赋值

    let [x, y, z] = new Set(['a', 'b', 'c']);
  • 默认值
    ES6中使用 === 判断哪一个位置是否有值。所以,一个数组成员不严格等于 undefined ,默认值是不会生效的

    var [x = 1] = [undefined];
    // x 1
    
    var [x = 1] = [null];
    // x null
    // 因为 null !== undefined  --> true

2.2 对象

  • 和数组的不同点
    数组的元素是有次序的,变量的取值由他的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

    var {bar, foo} = { foo: "aaa", bar: "bbb"};
    foo // "aaa"
    bar // "bbb"
    
    var {baz} = {foo:"aaa", bar: "bbb"}
    baz // undefined
  • 如果变量名与属性名不一致

    var {foo: baz} = {foo: "aaa", bar: "bbb"};
    baz // "aaa"
    foo // error: foo is not define

    实际上,对象的解构赋值是以下形式的简写

    var {foo: foo, bar: bar} = {foo: "aaa", bar: "bbb"};

    真正赋值的是后者 不是前者

  • 其他

    var {foo: {bar}} = {baz: "baz"}
    // 报错

    此时 foo 的属性对应一个子对象。该子对象的bar属性结构时会报错。因为 foo 现在为undefined。

    var x;
    {x} = {x: 1}
    // SyntaxError:  syntax error

    对于已经声明的变量用于解构赋值必须很小心。因为上面的代码 js 引擎会把 {x} 理解成一个代码块,发生语法错误。正确的写法:

    ({x} = {x:1});
    • 圆括号与解构赋值的关系

      解构赋值允许等号左边的模式中不放置任何变量名。于是写出很古怪的表达式

      ({} = [true, false]);
      ({} = 'abc');
      ({} = []);

      上面的表达式毫无意义 但是语法是合法可以执行的。

    对象的解构赋值可以很方便的将现有对象的方法赋值到某个变量。
    let { log, sin, cos } = Math

2.3 String

字符串被转换成一个类似数组的对象

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "e"
d // "l"
e // "o"

类似数组的对象都有 length 属性,因此可以对这个属性解构赋值

let {length: len} = 'hello';
len // 5

2.4 Number & Boolean

解构赋值时,如果等号右边是数值或布尔值,则会 先转为对象

let {toString: s} = 123
s === Number.prototype.toString // true

let {toString: b} = true
b === Boolean.prototype.toString // true

上面代码中 数值 和 布尔值 的包装对象都有 toString 属性,因此 s 都能取到值。

解构赋值的规则是,只要等号右边的值不是对象,就现将其转为对象。 由于 undefined 和 null 无法转为对象,所以对他们进行解构赋值都会报错。

let {prop: x} = undefined; // TypeError
let {prop: y} = null; // TypeError

// 转为 ES5 的代码 一目了然
var x = undefined.prop;

var _ref = null;
var y = _ref.prop;

2.5 函数参数

function add([x,y]){
    return x + y;
}

add([1,2]) //3

上面的代码,函数的参数不是一个数组,而是通过解构得到的变量 x 和 y

function move({x=0, y=0} = {}){
    return [x, y];
}

move({x:3, y:8}) // [3, 8]
move({x:3}) // [3, 0]
move({}) // [0, 0]
move() // [0 ,0]

上面的代码,函数 move 的参数是一个对象,通过对这个对象进行解构,得到变量 x y 的值。 解构失败,则等于x y等于默认值。

function move({x, y} = {x:0, y:0}){
    return [x, y];
}

move({x:3, y:8}) // [3, 8]
move({x:3}) // [3, undefined]
move({}) // [undefined, undefined]
move() // [0 ,0]

上面的代码视为函数 move 的参数指定默认值,而不是为 x y 指定默认值,所以结果不同。

2.6 关于圆括号

一个式子是模式还是表达式,没有办法一开始就知道,必须解析到或解析不到等号才知道。

ES6的规则是,只要有可能导致解构歧义,就不得使用圆括号。

不使用圆括号

  1. 变量声明语句中,模式不能带有圆括号

    // 全部报错
    var [(1)] = [1];
    var {x: (c)} = {};
    var {o: ({p:p})} = {o: {p:2}}
  2. 函数参数中,模式不能带有圆括号
    函数参数也属于声明变量

  3. 不能将整个模式或嵌套模式的一层放在圆括号中

    // 全部报错
    ({p:a}) = {p: 1};
    ([a]) = [5];
    [({p: a}), {x: y}] = [{p: 1}, {x: 2}];

使用圆括号

只有一种情况:赋值语句的非模式部分可以使用后圆括号

  [(b)] = [1]; // 模式是取数组的第一个成员
  ({p: (a)} = {p: 1}); // 模式是p 而不是a
  ([parseInt.prop]) = [1]; // 同第一个

因为上面语句都是赋值语句,不是声明语句;他们的圆括号都不属于模式的一部分

2.7 用途

1) 变换变量的值

[x, y] = [y, x];  // 交换 x y 的值

babel转换后

"use strict";

var _ref = [y, x];
x = _ref[0];
y = _ref[1];
_ref;

2) 从函数返回多个值

函数只能返回一个值,想要多个就只能放在数组或对象中返回了。

// 返回一个数组
function example(){
    return [1,2,3]
}
var [a,b,c] = example()

// 返回一个对象
function example(){
    return {
        foo: 1,
        bar: 2
    }
}
var {foo, bar} = example();

3) 函数参数定义

很方便的将一组参数和变量对应起来

// 参数是一组有次序的值
function f([x,y,z]){
    ...
}
f([1,2,3])

// 无次序
function f({x,y,z}){
    ...
}
f({z:3, y:2, x:1})

4) 提取 JSON 数据

十分有用

var jsonData = {
    id: 1,
    status: 'OK',
    data: [12,13]
}
let {id, status, data: number} = jsonData;

console.log(id, status, number)

5) 函数参数的默认值

jQuery.ajax = function(url,{
    async = true,
    beforeSend = function(){},
    cache = true,
    complete = function(){},
    crossDomain = false,
    global = true
    ....
}){
    ....
}

可以避免在函数内部再写 var foo = config.foo || 'defaule foo';

6) 遍历 Map

任何部署了 Iterator 接口的对象,都可以用 for...of 循环再遍历。Map原生支持 Iterator 接口,使用变量的解构赋值获取 key value 很方便。

var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for(let [key, value] of map){
    console.log(key, value);
}
// 只获取键
let [key] of map
// 只获取值
let [,value] of map

7) 输入模块的指定的方法

加载模块时候,往往需要指定哪些方法。

const {parseURL, util} = require('base');

转成 ES5

'use strict';

var _require = require('base');

var parseURL = _require.parseURL;
var util = _require.util;
@ccforward ccforward self-assigned this Jul 5, 2016
@ccforward ccforward changed the title 29.ES6 笔记 29.ES6 笔记一 Jul 19, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant