美文网首页
ES6初始记录(较乱)

ES6初始记录(较乱)

作者: shanshanfei | 来源:发表于2016-11-29 15:46 被阅读0次

    转码器:babel,允许用ES6的语法来写程序,而不用考虑现有环境是否支持。

    EcmaScrip是规范,JavaScript是实现。
    Es6包含ecma2015 ecma2016 ecma2017,一般是指ecma2015。

    let 和 const

    顶层对象的属性:
    ES5 顶层对象的属性与全局变量是等价的。
    ES6 开始全局变量不都是顶层对象的属性了,只有var、function定义的才算,let、const、class定义的不算顶层对象的属性。

    const与let一样:

    • 块级作用域内有效
    • 声明不会提升,需先声明再使用(暂时性死区)
    • 不允许重复声明
    • const声明只读常量,声明对象时指对象地址不可变,但对象内容可改变(需立即初始化)
    • 另:对象冻结可使用Object.freeze( obj )。

    ES5声明变量有2种方式:var + function
    ES6声明变量有6种方式:var + function + let + const + import + class

    ES5只有全局+函数作用域,无块级作用域(导致:内部变量覆盖外部变量、for计数变量外泄为外部变量等)
    ES6 let只在块级作用域内有效,可以替换立即执行函数了IIFE。{let a;…..}

    ES5不允许在块级作用域中声明函数,但是浏览器真正实现是:允许声明函数,而且会提升至作用域前面。
    ES6明确允许在块级作用域中声明函数,而且浏览器环境和非浏览器环境表现不同:
    - 浏览器环境:相当于var声明,会提升(提升至所在全局||函数作用域头部),赋值延后(函数声明会提升至所在块级作用域头部)。
    - 非浏览器环境:相当于let声明,不会提升,只在当前块级作用域有效。
    所以:为了表现一致,尽量不在块级作用域内声明函数,若必须声明,则使用 函数表达式方式 ,而非函数声明方式。

    let为js新增了块级作用域,声明变量,只在当前代码块内有效。
    立即执行函数表达式IIFE(Immediately-Invoked Function Expression):(function(){})();

    变量的解构赋值

    解构赋值的规则:只要等号右边不是对象,就现将其转换成对象。
    解构赋值:数组、对象、字符串、数值、布尔值、函数参数等的解构赋值。

    ** 对象的解构赋值 **
    模式不会被赋值,被赋值的是模式后面的变量:

    let {loc: first, glo:last} = {loc:123, glo: 456};//loc和glo是模式,first和last才是真正赋值的变量
    

    对于已经声明的变量进行解构赋值时,需要加上小括号,因为不加的话,js会将行首的花括号解释为代码块,引起语法错误。

    let x;
    {x} = {x:1}; //SyntaxError: syntax error
    ({x} = {x:1}); //正确
    

    解构赋值的几个好处:

    1. 提取JSON数据的值;
    2. 函数参数定义默认值;
    3. 提取某对象或模块的方法;

    字符串的扩展

    对字符串进行操作的时候,要注意常规字符(两字节)和辅助字符(四字节)的区别。
    unicode是世界上所有的字符集,是一种二进制的表示方法,但是并没有规定存储方式。UTF-8和UTF-16、UTF-32就是其具体的存储实现,具体区别可以阅读阮一峰老师的两篇文章,参考:

    字符串的扩展重点:

    • 码点大括号表示法: '\u{20BB7}'
    • 对于传统for循环无法识别的大于0xFFFF的码点,for...of可以正确识别
    • normalize() repeat() includes() startsWith() endsWith()等函数
    • 模板字符串:`xxxxxx ${variable} yyy ${func()}` //引入变量时使用${}

    正则的扩展

    正则表达式新增flags属性,返回修饰符

    • ES5:/abc/ig.source 返回正文abc
    • ES6:/abc/ig.flags 返回修饰符ig
    • 新增修饰符u和y,u代表可以处理unicode大于0xFFFF的字符,y类似于g,只是y是从剩余字符中的第一个位置开始匹配,g是只要剩余字符中匹配即可。
    • /abc/ig.sticky是否设置了粘连属性y
    • 提案:RegExp.escape()函数对字符串进行转义
    • 提案:/abc/s.dotAll属性,修饰符/s:点代表一切字符

    数值的扩展

    • 二进制和八进制表示法(0B和0O)
    • 新增一些方法:Number.isNaN() .isFinite() .parseInt() .parseFloat() .isSafeInteger()
    • 未解决js浮点运算的bug,引入一个极小常量Number.EPSILON
    • Math对象扩展了一些函数:.trunc() .sign()等

    数组的扩展

    • 增加一些方法:Array.from() 将类数组转换成数组;Array.of()将一组值转换成数组,解决Array构造函数参数不等的歧义问题
    • [].find() .findIndex() .entries() .keys() .values() .includes()等方法
    • 尽量避免出现空位,防止表现不一致引起问题

    JS中数组的迭代方法:

    方法 举例
    forEach:对数组中的每一项执行操作 arr.forEach(function(v, i, arr){return v+1;})
    every:每一项都满足某条件则返回true if(arr.every(function(v,i,arr){return v > 2;})){}
    some:只要有一项满足某条件则返回true if(arr.some(function(v,i,arr){return v > 2;})){}
    map:对数组每一项进行操作,返回数据组成新数组返回 var newArr = arr.map(function(v, index, arr){return v*2;});
    filter: 对数组进行过滤,满足条件的项组成新数组返回 var newArr = arr.filter(function(v, index, arr){return v > 10;});
    reduce:对数组的相邻两项进行操作 var sum = arr.reduce(function(sum, item){return sum+item;}, 0)
    includes:数组是否包含某值 if(arr.includes(2)){}

    函数的扩展

    • 参数默认值:双重默认值 function({x=0,y=0} = {}){...},尽量将定义了默认值的参数放于参数的尾部,方便省略

    • (function(a,b,c=1){}).length //2 返回函数的预期参数个数(不含指定了默认值的参数和rest参数)

    • rest参数:只能是尾参数

    • 扩展运算符:... 将数组转换成逗号分隔的数据序列

    • 箭头函数=>:this指向定义时的作用域(this始终指向定义时的this,而非运行时的this)

    • 函数绑定运算符(双冒号** ::**)obj::method 绑定this

    • 尾调用、尾递归调用(先做了解):尾调用-函数的最后一步是调用另一个函数,内部函数可以不用再维护外部函数的调用栈信息。

    对象的扩展

    • 属性名表达式 obj['a'+'bc'] = 111; 简洁属性表示法 let obj = {x, y};
    • Object.keys() .values() .entries()
    • Null传导运算符** ?:** 判断对象是否存在,防止报错 person?.user?.p1?.age
    • 对象的扩展运算符** ...** 单纯的解构赋值可以读取对象的继承属性,扩展运算符的解构赋值只能读取对象自身的属性
    var o = Object.create({ x: 1, y: 2 });//x y算继承属性
    o.z = 3;
    
    let { x, ...m } = o;
    x // 1---单纯的结构赋值
    m // {z: 3} --- 扩展运算中的解构赋值
    
    • 对象属性的遍历5种方法
    for...in //返回对象自身和继承的可枚举属性
    Object.keys() //返回对象自身可枚举属性
    Object.getOwnPropertyNames() //返回对象自身所有属性(包括不可枚举)
    Object.getOwnPropertySymbols() //返回对象自身Symbols属性
    Reflect.ownKeys() //返回对象自身symbol类型和字符串类型的属性(不管是否可枚举)
    
    方法 适用范围 描述
    for...in 数组、对象 获取可枚举的实例和原型属性名(返回键名)
    Object.keys() 数组、对象 返回可枚举的实例属性名组成的数组
    Object.getOwnPropertyNames() 数组、对象 返回除原型属性以外的所有属性(包括不可枚举的属性)名组成的数组
    for…of 可迭代对象(Array Map Set等) 返回属性值(返回键值)
    Reflect.ownKeys() 对象自身的所有属性,包含symbols属性和不可枚举属性
    • object.is(p1, p2):同值判断 基本等同于全等===,不同:
      object.is(+0, -0);//false
      object.is(NaN, NaN);//true
    • Object.assign(target, source1, source2):对象合并,浅拷贝,只拷贝对象自身的属性,继承(prototype上的属性)+不可枚举的属性都不会拷贝到。
      首参不能是null、undefined,否则报错;
      处理数组时:
      Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3] 按照下标进行覆盖合并
      Object.create(原型 | null,实例属性设置):只有显示的指定属性设置的enumrabe等属性才可以。属于ES5

    Symbol

    ES6新增原始数据类型Symbol,表示独一无二的值(对象属性名可以保证不会冲突)。Symbol给我感觉用处不是很顺畅,很别扭的感觉。

    • Symbol(str):参数表示对Symbol实例的描述,不能用new(不是对象);Symbol值不能进行隐士字符串转换,只能显示转换String(Symbol('aa')) or Symbol('aa').toString(),也不能转换成数值,但是可以进行布尔换算
    • Symbol值作为属性名时,只能用[]引用,不能用点.获取(用点默认代表字符串属性)
    • Symbol.for('aa') 是全局登记的值:每次会先搜索给定参数的值是否存在,如果已经存在,则返回,否则新建一个值返回。Symbol.keyFor(Symbol.for('aa'))返回Symbol.for()注册的值的描述。
    Symbol('aa') === Symbol('aa') //false
    Symbol.for('aa') === Symbol.for('aa') //true
    Symbol.keyFor(Symbol.for('aa')) //'aa'
    Symbol.keyFor(Symbol('aa'))//undefined
    
    • 定义了一些内置的Symbol值,用于指向语言内部的方法

    Map和Set数据结构

    数据集合:ES5 -> Array+Object ,ES6 -> Map+Set

    --- Set

    类似于没有重复值的数组。键名和键值完全一样。

    //操作方法 add delete has clear
    var set = new Set([1,2,3,2,3]);//[1,2,3]
    set.add(4);//[1,2,3,4]
    set.size;// 4
    set.delete(1);
    set.has(2);
    set.clear();//清空
    
    //遍历方法 .keys() .values() .entries() .forEach()
    let set = new Set(['red', 'green', 'blue']);
    
    for (let item of set.keys()) {
      console.log(item);
    }
    // red
    // green
    // blue
    
    for (let item of set.values()) {
      console.log(item);
    }
    // red
    // green
    // blue
    
    for (let item of set.entries()) {
      console.log(item);
    }
    // ["red", "red"]
    // ["green", "green"]
    // ["blue", "blue"]
    
    set.forEach((value,key,set) =>console.log(value+':'+key) );
    
    --- WeakSet

    与set类似,但是只保存对象类型的数据,是对象类型数据的弱引用,目的是防止内存泄漏。常用方法有:add has delete,无法遍历

    --- Map
    // 操作方法 set get has delete clear
    var map = new Map([ ['name', 'fss'], ['age', 27] ]);
    map.set('job', 'computer').set('xx', 'aa');
    map.get('xx');//'aa'
    map.size;//3 条目个数
    map.has('job');//true
    
    //遍历方法 map.keys() .values() .entries() forEach()
    
    --- WeakMap

    与Map结构类似,键名只能是对象类型,弱引用,防止内存泄漏。常用方法:get set has delete,无法遍历。

    Proxy

    对对象的一层代理拦截,修改对象操作的默认行为。

    //handler为{}时,代表无拦截效果;handler内部定义了一些内置的拦截方法:get set apply construct等
    var proxy = new Proxy(target, handler);
    
    var handler = {
      get: function(target, name) {
        if (name === 'prototype') {
          return Object.prototype;
        }
        return 'Hello, ' + name;
      },
    
      apply: function(target, thisBinding, args) { //一般函数调用时拦截函数
        return args[0];
      },
    
      construct: function(target, args) {//构造函数调用时拦截函数
        return {value: args[1]};
      }
    };
    
    var fproxy = new Proxy(function(x, y) {
      return x + y;
    }, handler);
    
    fproxy(1, 2) // 1
    new fproxy(1,2) // {value: 2}
    fproxy.prototype === Object.prototype // true
    fproxy.foo // "Hello, foo"
    
    • Proxy.revocable 目标对象不允许直接访问,只能通过代理访问,访问结束,收回代理权,不允许再访问
    • Proxy代理时,目标对象内部的this指向proxy代理对象

    Reflect

    • 与Proxy类似,Proxy handler中有的方法Reflect也都有,只不过Proxy是自定义拦截行为,Reflect实现的是对象的原生行为。
    • 观察者模式:函数自动观察数据对象,一旦数据对象发生变化,函数自动执行。(懵懵懂懂???)

    Promise

    • 异步编程的一种解决方案(传统方法:回调函数和事件),可以这样理解Promise:一个容器,保存着异步编程操作的结果(未来完成)。
    • 状态有2种,要么成功resolved || fulfilled,要么失败rejected
    • 提供一些API:
    var promise = new Promise(resolve, rejected);//新建后立即执行,无法中断
    promise.then(resolveFunc, rejectedFunc)
    .then(resolveFunc)//链式写法
    .catch(function(){})//状态为rejected时执行,resolveFunc执行出错时也执行
    
    • Promise.all([p1,p2,p3])所有参数状态都为resolved时,整体才为resolved;有一个失败,则整体rejected
    • Promise.race([p1,p2,p3])只要有一个实例状态改变,则整体状态改变,执行相应处理函数
    • Promise.resolve() .rejected() 将参数先转换为Promise对象,再执行相关函数
    • .done() .finally() 区别是:finally不管怎样都会执行,done总是在回调链的尾端,保证抛出任何错误(捕捉错误的)。
    • Promise.try() 模拟try模块,尝试运行同步函数 Promise.catch()

    遍历器Iterator接口

    为各种不同的数据结构(Array、Object、Map、Set)提供一种统一的访问机制(即for...of)。只要部署了Symbol.iterator(默认指向该对象的遍历器接口,必须要有next方法)属性的数据结构,就被称为部署了遍历器接口。

    Generator函数

    ES6提供的异步编程解决方案,可以理解成一个状态机,封装了多个内部状态。

    • 语法
    function* generatorFunc(){//带有星号*
        //some code 
        yeild 'status1';//函数内部可以用yeild定义状态
        //some code 
        yeild 'status2';
        //some code 
        yeild 'status3';
        //some code 
        return 'status4'; //可以没有
    }
    var geneFunc = generatorFunc();
    geneFunc.next();//{value:'status1', done: false} 
    geneFunc.next();//{value:'status2', done: false} 
    geneFunc.next();//{value:'status3', done: false} 
    geneFunc.next();//{value:'status4', done: true}
    geneFunc.next();//{value:undefined, done: true}  
    
    • Generator函数像正常函数一样调用,但是函数并不是立即执行,调用生成函数后,返回一个遍历器对象,第一次调用next方法,函数从头开始执行到yeild语句,返回一个状态;后续再调用next,从上次停止的地方开始执行至下一个yeild或者函数最后。(提供函数暂停执行
    • yeild和return的异同:都可以返回紧跟其后的表达式的值;但是yeild不能用在普通函数中,只能在生成器函数中使用;return只执行一次,yeild可以执行多次;
    • yeild用在表达式中,必须使用圆括号:不知道有啥用???
    console.log('Hello' + yield); // SyntaxError
    console.log('Hello' + yield 123); // SyntaxError
    
    console.log('Hello' + (yield)); // OK
    console.log('Hello' + (yield 123)); // OK
    
    foo(yield 'a', yield 'b'); // OK 函数参数和赋值时,可以不用圆括号
    let input = yield; // OK
    
    • yeild语句本身没有返回值,每次返回undefined(var x = yeild 123;//x是undefined);next方法可以传入一个参数,当做 (上一次) yeild语句的返回值,好处:可以在生成函数运行之后,再次向函数内注入值。
    function* foo(x) {
        var y = 2 * (yield (x + 1));
        var z = yield (y / 3);
        return (x + y + z);
    }
    
    var a = foo(5);
    a.next() // Object{value:6, done:false}
    a.next() // Object{value:NaN, done:false}
    a.next() // Object{value:NaN, done:true}
    
    var b = foo(5);
    b.next() // { value:6, done:false }
    b.next(12) // { value:8, done:false }
    b.next(13) // { value:42, done:true }
    

    二十三:SIMD

    (目前JS引擎基本不支持,可以仅作了解)

    SIMD:单指令 多数据(single instruction / mutiply data)
    SISD:单指令 单数据(single instruction / single data)--- JS默认运算模式

    SIMD是js操作CPU对应指令的接口,完成多个数据的运算,广泛用于3D图形运算、物理模拟等运算量超大的项目之中。

    SIMD提供12种数据类型,总长度都是128个二进制位。

    Float32x4:四个32位浮点数
    Float64x2:两个64位浮点数
    
    Int32x4:四个32位整数
    Int16x8:八个16位整数
    Int8x16:十六个8位整数
    
    Uint32x4:四个无符号的32位整数
    Uint16x8:八个无符号的16位整数
    Uint8x16:十六个无符号的8位整数
    
    Bool32x4:四个32位布尔值
    Bool16x8:八个16位布尔值
    Bool8x16:十六个8位布尔值
    Bool64x2:两个64位布尔值
    

    每种数据类型被x符号分隔成两部分,后面的部分表示通道数,前面的部分表示每个通道的宽度和类型。比如,Float32x4就表示这个值有4个通道,每个通道是一个32位浮点数。
    利用SIMD的一些静态方法,可以完成一些运算,具体就不展开介绍了,可以参考链接:http://es6.ruanyifeng.com/#docs/simd

    相关文章

      网友评论

          本文标题:ES6初始记录(较乱)

          本文链接:https://www.haomeiwen.com/subject/bsgapttx.html