javascript 速记-ES6

ES6规范

let & const ☆☆☆☆☆

  1. let 是对局部变量的补充设计
  2. 并且向着大型应用语言的方向去要求,
    (1)没有类似var的变量声明提升(可以在声明之前引用这个变量),必须先声明,后使用
// 被称为暂时性死区 还是遵循 先声明后引用的条件
var tmp = 123;

if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}

(2)不允许多次声明
(3)在if swtich for等代码块中也起作用

  1. const 弥补了javascript中没有常量定义的设计。

字符串 ☆☆☆☆☆

  1. 字符串模板语法 ,目前已经非常常用了
  2. 字符串新增方法
    //实例方法
    xxx.trimStart // 删除掉字符串头部的空格
    xxx.trimEnd // 删除掉字符串尾部的空格
    xxx.padStart
    xxx.padEnd(maxLength, fillingString) //第一个参数指定 最终的字符串的最大长度  第二个参数 指定重复添加的字符串 
    xxx.includes // 检测字符串中是否包含 指定的字符串
    xxx.startsWith 
    xxx.endsWith
    xxx.repeat // 重复当前字符串 n次
    

解构赋值: ☆☆☆☆☆

  1. 数组解构赋值
  2. 对象解构赋值
  3. 函数参数的解构
function say({name, age}) {
   console.log(`${name}, ${age}`)
}
let o = {name: "ngnice", age: 10}
say(o);

数值扩展 ☆☆

  1. 二进制和八进制的表示法
    (1)二进制 以 0B 或者 0b开头
0b101 === 5 // true

(2)以0o 开头表示八进制

0o101 === 65 // true
  1. Number增加静态方法
// 是否有限, 对于非数字和Infinity 都返回false
Number.isFinite(1) // true
Number.isFinite(Infinity) // false
Number.isFinite("1") //false

// Number.isNaN  判断是否是一个非数字
// 如果参数类型不是NaN,Number.isNaN一律返回false。
Number.isNaN(NaN) // true
Number.isNaN(9)// false
Number.isNaN(null) //false

// 将parseInt 和 parseFloat 移植到了Number类上
Number.parseInt(90.2) //90
  1. Math对象新增了一些数学函数方法
Math.trunc() 

正则扩展 ☆

数组扩展 ☆☆☆☆☆

  1. 扩展运算符 更像 rest的逆运算
const arr = [1,3,4,4];
console.log(...arr);
// 可以用于重新组合数组
let newArr = [1,22,...arr];
  1. Array.from将其他类数组对象转换成数组
Array.from(arguments)
Array.from(document.querySelectorAll('xxx'))
Array.from(new Set([1,2,3,34]))

注意点:
(1)和扩展运算符区别:Array.from 能将任何类似数组的结构转换成数组(即用于length属性)
(2)扩展运算符本质上是调用被转换对象的iterator接口,所以只有部署了这个接口的对象才能使用。

  1. Array.of 将一组值转换成数组
Array.of(1,2,3,43) // [1, 2, 3, 43]
  1. 其他的一些方法
arr.find(callback) // 返回符合条件的第一个元素
arr.findIndex  // 类似 arr.indexOf

xxx.includes()// 是否包含某个值
xxx.keys xxx.values  xxx.entries
arr.fill(value, start, end) // 使用指定的值 填充指定的范围,范围不包含结束位置
  1. flat 拍平数组 参数拍平多少层:1,2,3, ...Infinity
[1, [2, [3]]].flat(Infinity) //[1, 2, 3]

对象扩展 ☆☆☆☆☆

  1. 属性简写和方法简写
// es6 之前
var name = "ngnce";
const obj = {
  name: name,
  log: function () {
      console.log(this.name)
  }
}

// es6之后
var name = "ngnce";
const obj = {
  name,
  log () {
      console.log(this.name)
  }
}
  1. 属性名表达式
// 对象属性声明的两种方式
var obj = {};
obj.name = "aaa";
// or
var property = "name"
obj["last"+property] = "ngnice";

es6之前,针对对象字面量这种声明方式 无法使用第二种,现在我们就可以了

var obj = {
  // 属性可以使用第二种方法声明
  [["last"+property]: "ngnice",
  log() {
  }
}
  1. 扩展运算符,解构赋值
  2. ES2020 新增的链判断运算符,类似dart中的语法
var a = obj?.other?.age||'default';
  1. ===== 以及 Object.is
    (1)== 非严格相等 判断两个值相等: 会进行类型自动转换
    (2)=== 严格相等: 不会进行类型转换,对于基础类型只判断其值是否相等,对于引用类型 判断其内存地址是否相等,了NaN=== NaN 不成立
    (3)Object.js 在=== 基础上修正了两点:
    Object.is(NaN, NaN)//true
    Object.is(+0, -0)//false
    
  2. Object.assign 对象合并
    (1) 浅拷贝
    (2)使用对象的扩展运算符 能达到类似的效果
var a = {name: "ngnice"};
var b = {age: 10}
var c =  Object.assign({}, a,b);
// or
var c =  {...a, ...b}

函数扩展 ☆☆☆☆☆

  1. 函数参数默认值
// es6 之前
function log(msg) {
  msg = msg || "默认值";
  console.log(msg)
}
// es6 之后 更加清晰 简洁
function log(msg = "默认值") {
  console.log(msg)
}

注意点:
(1)参数变量是默认声明的,所以不能用let或const再次声明。
(2)参数默认值是惰性求值的。
(3)参数默认值 一般设置 最后一个参数 否则 无法省略

  1. rest参数
    可以用来替换 arguments , 而且 arguments是一个类数组对象,不能直接使用数组的实例方法, 但是 rest参数就是一个数组
function add(...values) {
  let sum = 0;
  for (var val of values) {
    sum += val;
  }
  return sum;
}
add(1,2,3)// 6
  1. 箭头函数
var log = (msg="aaa")=>console.log(msg);

箭头函数有几个使用注意点。
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

错误使用

const cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}
cat.jumps();
  1. 函数的name属性 标准化
    注意点:
    (1)bind返回的函数,name属性值会加上bound前缀。
function foo() {};
foo.bind({}).name // "bound foo"

(function(){}).bind({}).name // "bound "
  1. 尾调用优化

新数据结构 Set Map ☆☆☆☆☆

  1. Set 集合,是一种值不重复的数组

  2. WeakSet
    (1)只能存储引用类型的值 不能存储基础数据类型
    (2)弱引用 无法遍历 可以防止内存泄露

  3. MapObject类似 区别在于 Map的键 可以是对象类型

  4. WeakMap 的键只能是对象类型,并且不计入垃圾回收机制

类 ☆☆☆☆☆

  1. 定义对象
    es6之前一直使用构造函数来定义类, 看起来和普通的函数无任何的区别
function Person() {
}

(1) 必须先定义 后使用,不存在声明提升

es6提供了class关键字来定义一个类,和传统的OOP 语言 更加接近。

  1. 属性和方法声明
    (1)属性声明
 class foo {
  // 写在类中的顶层
  bar = 'hello';
  baz = 'world';

  constructor(age) {
    // 可以放到这里
    this.name = "ngnice";
    this.age = age;
  }
}

(2)静态方法 static,静态属性 Person.staticProp, 新提案中提出用static关键字
(3)私有属性和方法:使用_命名方式(没有代码实际效果,只是约定编码规则),使用Symble实现

  1. 构造函数
    (1)必须和new一起使用
  2. super关键字
    (1)super函数 一般用于子类继承父类,在子类中的构造函数中调用;ES6 规定 必须在子类中的构造方法中调用super方法 否则就会在new的时候 报错。
    (2)在子类的方法中调用 指向父类的原型对象, 所以无法直接通过super.prop 访问父类的属性,调用的父类方法中的this 指向当前子类实例对象。
class N {
    name = "ngnice";
    age = 10;
    say() {
        console.log(this.name);
    }
}
class NN extends N {
   name = "new name";
   log() {
     console.log(super.age)
   }
   log1() {
    super.say();
  }
}
var n = new NN();
n.log();// 输出undefined
// log1中的this 指向当前子类实例对象 所以输出的是 new name
n.log1();// 输出 new name  

(3)在子类的静态方法中调用 指向父类对象

  1. __proto__属性和 prototype属性
    (1)对象的__proto__属性 指向 构造函数的原型对象(初始化这个对象的构造函数的原型对象)
class Animal{
}
let cat = new Animal();
cat.__proto__ === Animal.prototype //true

// 普通字面量
var a = 2;
a.__proto__ == Number.prototype

(2)实例对象(通过new 关键字创建的对象)没有prototype属性, 只有函数 或者是 通过class关键字定义的类才有这个属性 指向当前类的原型对象。
(3)可以通过instanceof来判断是否是某个类的实例对象

总结来说:
针对实例对象来说(不论是通过new 命令创建的还是通过字面量创建)__proto__都是指向构造类的原型对象prototype
对于类来说 如果是通过extends关键字实现继承的 子类的 __proto__指向的是父类,如果是通过ES5方式实现继承的话,还是指向 构造函数的原型 Function.prototype

  1. ES6中的继承
    (1) ES6中的继承 通过关键字extends实现。
    (2)和ES5中的继承对比,ES5中的继承本质上是先创建子类实例对象this,然后将父类的属性和方法添加到新的子类上
function People(name, age) {
   this.age = age;
   this.name = name;
}
People.prototype.say  =function () {
  console.log(`${this.name} is ${this.age}`);
}

// 定义子类 继承 父类
function Xiaoming(name, age, sex) {
   // this 已经存在
   this.sex = 1;
  // 实例属性通过下面的方法 添加到子类实例对象上
   People.apply(this, [name, age]);
}
// 通过原型拷贝的方式 给子类的原型上添加父类的方法 实现继承
Xiaoming.prototype = Object.create(People.prototype)
// 对子类对象的构造函数属性进行修正
Xiaoming.prototype.constructor = Xiaoming

可以参考:Object.create实现继承

es6中实现继承就比较简单了(代码摘自阮一峰老师的教程)

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

class ColorPoint extends Point {
  // 子类中如果显式的声明 constructor 构造函数 
  //必须在构造函数中添加 super调用,并且在此调用之前无法获取到`this`的引用。
  constructor(x, y, color) {
    this.color = color; // ReferenceError
    super(x, y);
    this.color = color; // 正确
  }
}

(3)通过Object.getPrototype可以判断是否继承了另外一个类
对于ES6 class关键字声明的类

Object.getPrototype(ColorPoint) 

对于ES5语法 声明的类 需要判断的是其prototype

Object.getPrototype(Xiaoming.prototype)=== People.prototype 

本质上是 原型对象上的__proto__指向的原型对象

ColorPoint.__proto__ === Point
Xiaoming.prototype.__proto__ === People.prototype 

模块 ☆☆☆☆☆

模块化的意义: 针对中大型编程中而言,我们实际上有两个述求,
(1) 能使用第三方模块提供通用的功能实现(不需要重复造轮子)可能有同学说重复造轮子难道不好吗,如果针对业务需求开发,你会发现如果通用的功能模块都有优秀的第三方实现,我们只需要开发业务逻辑部分的开发是多么的幸福;
(2) 则是针对业务逻辑通用代码或者是没有开源的第三方模块,需要我们自己去实现,在组织我们大量的业务逻辑代码的时候,模块化的机制是多么的重要,方便协作的同事和自己后续维护。

(1)封装、解耦、分治
(2)防止全局污染
(3)代码组织方式

总结
到最后还是能总结到软件编程中的两个永恒的话题:效率和质量。

  1. javascript中的模块化之路
    (1)commonjs
    (2)amd/cmd
    (3)es6中的模块化

ES6的模块 和 commonjs模块
(1)ES6 模块是引用
(2)commonjs 模块是拷贝

promise ☆☆☆☆☆

前端异步编程的解决方案之一,改写了callback模式

实现自己的promise

Iterator和 for of

遍历器概念

javascript中目前存在的数据集合 Set Map Array Object

  1. 为了给数据集合提供统一的访问接口,ES6提供了Iterator接口,和for of
  2. ES6规定Iterator接口部署在数据集合的Symbol.iterator属性上,Iterator是一个函数 返回一个对象,包含一个next的的方法,用来移动内部指针,遍历数据集合。
  3. ES6中的有些数据结构原生部署了Iterator接口
Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象

以数组做例子:

var arr = [1,2,2];
var iterator = arr[Symbol.iterator]()
iterator.next();// {value: 1, done: false}
iterator.next();//{value: 2, done: false}
iterator.next();//{value: 2, done: false}
iterator.next();//{value: undefined, done: false}
  1. 有些场合默认会调用Iterator接口
    (1)解构赋值
    (2)扩展运算符
    (3)yield* 跟上部署了遍历器接口的数据结构
    (4)其他一些应用
for...of
Array.from()
Map(), Set(), WeakMap(), WeakSet()(比如new Map([['a',1],['b',2]]))
Promise.all()
Promise.race()
  1. Iterator接口除了必须设置实现的next方法,还可以部署return throw方法
var obj = {
   num: 10,
   [Symbol.iterator]() {
       return {
            next() {
                if(obj.num -- == 0) {
                    return {done: true, value: obj.num}
                } else {
                    return {done: false, value: obj.num}
                }
                
            },
            return() {
                // logic code
                console.log('return function')
                // 返回值 必须是一个对象
                return {
                    done: true,
                    value: "ngnice"
                }
            }
       }
   }

}
// break可以触发 return
for(let a of obj) {
    console.log(a);
    if(a < 4) {
        break;
    }
}
// throw error也可
for(let a of obj) {
    console.log(a);
    if(a < 4) {
        throw  new Error('ngnice');
    }
}

for of 就是用来消费部署了Iterator接口的数据集合。

var set = new Set([1,2,3,4]);
for( let item of set ) {
  console.log(item)
}
// 注意map
var m = new Map()
m.set('name', 'ngnice')
m.set('age', 10)

for(let item of m) {
    console.log(item)
}
// ["name", "ngnice"]
//  ["age", 10]

generator ☆☆☆☆☆

generator 函数

  1. generator书写上和普通函数不同的地方就是 函数名和function关键字之间需要添加一个*号, 并且函数体内部可以通过 yield定义多个状态(或者是任务)。
  2. 在执行效果上,和普通普通函数不同的地方就是可以暂停当前函数的执行。
  3. ES6中提供解决javascript中异步编程解决方案的方案之一。

示例代码:

function *gen(x) {
  var a = yield x+1;
  yield a+x;
  return 11;
}
// 调用之后 返回的是一个部署了iterator 接口的对象 而不是函数的返回值
var g = gen(10);
// 需要调用遍历器的next方法
g.next();// {value: 11, done: false}
g.next(10);// {value: 20, done: false}
g.next(); // {value: 11, done: true}
g.next(); // {value: undefined, done: true}

注意点:

  1. generator函数执行之后 不会返回函数的返回值,而是返回一个部署了可迭代协议的对象,因此可以使用for of遍历。
  2. 通过调用next方法执行yield后面的表达式,而yield并不会有返回值,或者说是默认返回undefined,但是可以通过 next方法传入参数,将作为上一个yield表达式的返回值。
  3. 每次执行next方法,都会依次执行yield后面的表达式,并且暂停在哪里,直到下一个next的调用,
  4. 如果后面没有yield语句,就将函数的返回值作为value值 返回 done属性为true.
  5. yield命令只能使用在generator方法中。

generator的异常处理

我们在进行异常捕获的时候 使用try catch语句块,但是只能捕获try语句块中的代码异常。
但是 Generator因为它可以暂停执行,交出控制权,所以允许我们捕获代码块之外的异常。

function *gen() {
  try {
    yield a;
    console.log('10');
    yield 11;
    console.log('11')
  } catch(err) {
    console.log(err);
    
  }
}

var g = gen();
g.next();
g.throw('outer error');

Generatorreturn方法

类似普通函数的return 作用,它可以结束Generator的执行,提前将done属性改成 true,如果return提供了入参的话,将作为value值。
如果存在try finally则会直接跳到finally中执行完成。

function *gen() {
  yield "ngnice";
  yield console.log("a");
  try {
    console.log(yield 'nice');
  } finally{
    console.log('finally');  
    yield 1;
    yield 2;
  }
}

var g = gen();
g.next();
g.return("return value");

对比:

function *gen() {
  yield "ngnice";
  yield console.log("a");
  try {
    console.log(yield 'nice');
  } finally{
  // 如果finally代码块中还存在yield语句 将不会结束
    console.log('finally');  
    yield 1;
    yield 2;
  }
}

var g = gen();
g.next();
g.next();
g.next();
g.return("return value");

yield * 表达式 可以获取generator函数生成对象的内部值。

function* gena () {
  yield 1;
  yield 0;
  yield 2;
  yield 3;
}

function *genB() {
  yield 'a';
  yield* gena();
  yield 'last';

}
var g = genB()
g.next();
g.next();
g.next();

generator的应用

异步操作的同步化表达

  1. javascriptthunk函数将多参数函数转换成 接受一个回调函数的参数形态。
  2. 通过在回调函数中 递归的调用generator生成的对象的next方法实现了 自动化运行。
  3. 那么出了回调函数这种方式,也可以通过 promise的这种方案实现(本质上还是回调实现)
  4. 通过next方法 可以将数据从回调中 传递出来

代码具体实现, 我们可以参考TJ大神的co函数库

async

一句话 就是 async 就是 generator在异步编程应用的语法糖

proxy reflect ☆☆☆☆

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容

  • [TOC] 参考阮一峰的ECMAScript 6 入门参考深入浅出ES6 let和const let和const都...
    郭子web阅读 1,773评论 0 1
  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,378评论 0 5
  • 函数参数的默认值 基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。 上面代码检查函数l...
    呼呼哥阅读 3,364评论 0 1
  •   引用类型的值(对象)是引用类型的一个实例。   在 ECMAscript 中,引用类型是一种数据结构,用于将数...
    霜天晓阅读 1,045评论 0 1
  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,219评论 0 4