【study】ES3到ES11都增加了什么

939 阅读6分钟

🏆 掘金技术征文|双节特别篇

1.ES5和ES3相比,增加了什么?

  • (1)get/set存储器

和ES3相比,在达到相同的效果时,ES3需要对一个相同的逻辑重复多遍,但是ES5的getter/setter存取器可以实现存储重复逻辑,达到复用的效果。

  • (2)数组的迭代

比如要过滤一些数组,在ES3的时候需要对数组内的每一个元素进行循环,判断符合条件的在push进新数组里面,而ES5里面过滤数组可以用数组的filter方法,让代码变得更加简洁,提高代码的可读性和可维护性,其他的迭代方法还有indexOf,lastIndxOf,forEach,map,some,every,reduce,reduceRight.

  • (3)String.prototype.trim()

ES3去空格的时候,需要利用正则去判断,而ES5只需要去加一个trim属性就可以达到

//ES3
console.log('  123  456  '.replace(/(^\s+)|(\s+$)/g, ''));  //'123  456'
//ES5
console.log('  123  456  '.trim());  //'123  456
  • (4)Date.now()

ES3在获取时间的时候,需要先创建对象,然后才能得到此刻的事件,而ES5可以直接获取当前的时间

//ES3
console.log(new Date().getTime());  //1494091196365
//ES5
console.log(Date.now())  //1494091196365
  • (5)JSON

ES5的JSON序列化和反序列化比ES3更方便安全

//ES3
eval('({"a": 3})')
//ES5
JSON.parse('{"a": 3}')
  • (6)继承

ES5使用Object.create可以实现正确的继承。而ES3缺乏Object.create则只能写出不完美的继承(子类还未实例化父类已经实例化执行了构造函数,构造函数不带参数可能报错

//ES3
var Rectangle = function (id, x, y, width, height) {
    Shape.call(this, id, x, y);
    this.width  = width;
    this.height = height;
};
Rectangle.prototype = new Shape();
//ES5
var Rectangle = function (id, x, y, width, height) {
    Shape.call(this, id, x, y);
    this.width  = width;
    this.height = height;
};
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
  • (7)属性描述器
  • ES3: configurable enumerable value writable
  • ES5:configurable enumerable get set
  • configurable表示是否可以重新定义属性的描述,也就是说,如果把某个属性的configurable设置为false,那就再也无法改变这个对象的属性定义了
  • enumerable表示这个属性是否是可枚举的,枚举的属性在console里打印出来是亮的,而非枚举的是暗的,除此之外,是否可枚举还影响了其他的一些方法的取值表现
  • value和writable,value即属性的值是什么,writable为是否可写,如果不可写,那么这个属性就是只读的
  • get和set,一定会依赖另一个变量或者属性,get和set都是函数,如果进设置get,而不设置set,那么属性也是只读,而不可写
  • 例子1:定义空对象增加属性,并指定value
//最基本的value
a = {};
Object.defineProperty(a, "foo", { value: "bar" });

  • Object.defineProperty接受3个参数,第一个是对 象,第二个是对象的属性(键),而第三个是这个属性的 描述器,上述的代码会改变a,而不是生成一个新的对象, 被修改的对象a拥有了一个新的属性foo,并且我们定义了 它的值(value)是bar
  • 例子2:defineProperty本质不是增加属性,而是定义属性,因为空对象本身并不存在那个属性,所以我们定义了之后,看上去是增加了
  • 我们可以看到,通过defineProperty,我们可以在维持原对象的情况下,改变其特定的属性
  • 例子3:wirtable
  • 修改只定义的writable,此时就是不改变value的值,因为原来已经有了value的描述,不传新的就是不重新定义,现在我们通过设置writable将foo这个属性设置为不可写,也就是只读了(因为只读,所以值永远会是1)
  • 结论:我们可以通过设置value和writable将某个属性值设定为一个固定的只读值
  • 例子4:enumerable(下图中的可枚举,一个设置true,一个设置false)
  • 从上图可以看到,设置为可枚举的bar是亮的,而不可枚举的foo是暗的,一个属性是否可枚举有什么差别呢?我们经常会对对象做循环,比如for(key in obj),或者是Objject.Key(obj)等等,改变了属性的可枚举行,会导致循环的时候的差异,可以简单的理解为,如果把一个属性设置为不可枚举的,那么这个属性将会在这个对象中“隐身”,当然,我们可以通过a.key拿到不可枚举的属性的值,或者一些方法是不管是否枚举也是可以拿到的,一个使用不可枚举的场景是,JSON.stringify(转成JSON字符串)和Object.assign(拓展),因为这2个方法只对可枚举的值进行操作,所以,我们可以把一些私有的中间变量放在对象上并设置为不可枚举,那么最终这些中间变量都是被忽略掉的
  • 例子5:configurable
  • 此时的foo值为1,没有定义writable,所以writable的值是undefined,所以a.foo=2,是不起效果的,同样没定义enumerbale,所以foo是不可枚举的,可以看到他是暗的,通过Object.keys(a),我们可以看到a没有可枚举的值
  • 因为设置了configurable为false,所以这个时候的a的foo属性变为不可再定义的了,所以在此运行,哪怕设置一个相同的值,同时想把在可定义的这个选项打开,都是不会成功的,反而报错,说明不可再重新定义
  • 例子5:get和set
  • 改变a.foo,会发现a.bar也随之变化
  • 特别注意:get函数中用了this,这个this上下文指向的是对象
  • 通过定义bar,希望bar总比foo大1,并且bar的改变会引起foo的改变,本质就是通过set改变foo
  • 重点:Vue 2的核心就是将对象的属性通过get和set做了劫持,从而能获知属性(set)的变动,并且可以在属性被使用的时(get)记录依赖关系 上次举例中用的都是Object.defineProperty,设置的单个属性,还有一个方法Object.defineProperties,这个可以设置多个属性

2.ES6和ES5相比,增加了什么?

  • (1)变量和变量的作用域
  • ES5定义变量的时候使用var,ES6定义变量使用let,常量使用const
  • 区别1:var声明的变量会挂载在window上,而let和const声明的变量不会
  • 区别2:var声明的变量存在变量提升,而let和const不存在变量提升
  • 区别3:let和const声明形成快作用域
  • 区别4:同一作用域下的let和const不能声明同名变量,而var可以
  • 区别5:
var a = 100;
if(1){
   a = 10;
   //在当前块作用域中存在a使用let/const声明的情况下,给a赋值10时,只会在当前作用域找变量a,
   // 而这时,还未到声明时候,所以控制台Error:a is not defined
   let a = 1;
}
  • 注:let,const区别:let用于定义变量,const用于定义常量,且定义的名字要大写!多个单词之间用下划线分割
  • (2)箭头函数
  • 和普通函数的区别:
    1. 只有函数表达式,没有函数声明
    1. 箭头函数中没有arguments,可以使用ES6新增的扩展运算符...rest来收集参数(rest是一个数组,里面装的是剩余的所有实参)
  • 3)箭头函数中的this,一旦确定,就再也不会发生变化,箭头函数遵守的规则,定义箭头函数时所在的作用域this,(call,apply不生效)
  • 4)箭头函数的省略写法:当形参有且只有一个时,可以省略(),当函数体只有一条代码,并且还是返回值时,可以省略{}和return
  • (3)class关键字定义类
  • class的本质是function,它可以看做是一个语法糖,让对象原型的写法更加清晰,更像面向对象编程的写法
class Apple{
     constructor(a){
          this.a = a 
     }
}
  • 类的实例化:let apple = Apple(1)
  • 类的继承:使用extends
  • 类的constructor方法是类的默认方法,创建类的实例化对象时被调用
  • 类的定义不会被提升,必须在访问前对类进行定义
  • class内部只有静态方法,没静态属性
  • ES6引入了模块化,分export与import模块自动开启了严格模式
  • promise
  • (4)解构赋值
//数组
let [a,b,c] =[1,2,3] 
//对象
let{a,b,c} = {a:1,b:2,c:3}
  • (5)字符串
  • ES6中,新增了一种字符串的定义方式,多行字符串 var a = ``
  • ${}是一个固定的语法,在多行字符串中,{}之内是一个JS执行环境,可以调用任何的方法,写任何的js语句
  • (6)字符串方法
  • startsWith:用于判定字符串是否以另一个字符串开头,返回布尔值
  • 第一个参数判断字符串,第二个参数判断开始的位置
var str = 'asdfghjkl'
consolelog(str.startsWith("abc",3))
  • endsWith:与上述的startsWith恰好相反
  • includes:该方法用于判定字符串是否包含另一个字符串,返回布尔值
  • 第一个参数时判断字符串,第二个参数是判定开始的位置
var str = 'asdfghjkl'
consolelog(str.includes("abc"))
  • repeat:用于将字符串复制多次,参数就是被复制的次数
  • (7)数组方法
  • Array在ES6中新增了两个静态方法,三个普通方法
  • 1)静态方法就是函数本身调用的方法,也就是Array调用的方法
  • 2 )普通方法是数组实例,也就是字面量定义的数组,调用的方法
  • 第一个静态方法:Array.of:定义数组,该方法解决了Array在接收参数时的BUG
new Array(1,2,3) //[1,2,3]
new Array(3) //[empty * 3]
var arr = Array.of(3)
conso.log(arr)
  • 第二个静态方法:Array.from,该方法用于将类数组对象(之前称为集合的东西,有数组的特点,没数组的方法)转为数组,ES6之前,我们可以通过[].slice.call(arr)方式转为数组
  • 普通方法1:find:用于查询数组中的内容,成员:value,索引:index,元素组:arr
  • 如果为真,则停止循环并返回当前成员作为find方法的返回值,如果为假则继续循环,如果到最后依旧没有返回真,则find方法方法没有返回值,变量的值就是Undefined
  • 普通方法2:findIndex,该方法与find方法一致,返回值是符合条件的下标,如果没有符合条件的,返回值为-1
  • 普通方法3:用于数组内部的复制,第一个参数:复制的位置,第二个参数:开始的位置,第三个参数:结束的位置,不包含
  • (8)对象方法(两个静态)
  • Object.is用于比较两者是否全等
    1. NaN与NaN比较
console.log(NaN === NaN) //false
console.log(Object.is(NaN,NaN) //true
  • 2)0和-0的比较
console.log(0 === -0) //true
console.log(Object.is(0,-0) //false

Object.assign用于对象属性的复制(浅复制)

var obj = {}
var obj1 ={name:'棠梨煎雪1226'}
var obj2 ={sex :'女'}
Object.assign(obj,obj1,obj2}
//如果有相同的属性,则后面的参数属性会覆盖前面的
  • (9)...的作用,第一是在函数中收集参数,第二是解构数组的时候,可以使用,第三个是传递参数
  • (10)Symbol,是ES6中新增的数据类型,该数据属于值类型,表示独一无二的符号,定义一个Symbol数据的方式是通过Symbol(),该数据类型主要用于解决对象的属性不能重复的问题,Symbol作为属性默认不可遍历
  • (11)代理对象:ES6中增加了一个Proxy代理类,他可以对指定的对象的访问操作和修改操作进行拦截,
var proxy=new Proxy(原对象,{
get:function(原对象,属性名){},
set:function(原对象,属性名,属性值){},
  • (12)Set是ES6中新增的数据结构,他可以认为是一个不可重复的数组,但是和数组不同的是,里面的内容即是索引又是成员
  • ...可以解构数组Set
  • 数组去重 ...new Set()
  • Set对象具备的方法:
    1. set.add():用于添加一个新的成员到集合中,但是不能是已经存在的成员
  • 2)set.delete():用于删除一个成员
    1. set.hs():判断set是否存在一个成员,返回布尔值
    1. set.clear():清空
    1. set.forEach :循环
  • (13)Map可以认为是一个超对象,它的属性名key和属性值value可以是任何内容,普通对象的key必须是字符串,符合命名规范的属性名可以不加双引号,属性值可以是任何内容
  • 方法:
  • map.set()
  • map.get()
  • map.delete()
  • map.clear()
  • map.has()
  • map.forEach()

3.ES7和ES6相比,增加了什么?

  • (1)幂的运算符
Math.pow(3,2) === 3 ** 2 //9
  • (2)Array.prototype.includes()

4.ES8和ES7相比,增加了什么?

  • (1)async,await异步解决方案:优化回调地狱,ES6中的promise解决了回调地狱,但是要连续打点调用then,就会显得不清楚,所以引入了async函数,awiat表达式
  • (2)Object.entries(),Object.values()
  • 和迭代器相关的分别是keys,values和entries,这3个方法都是object上的,因为数组本身也是对象,所以后面又加上了这3个方法,这3个方法返回的都是迭代器,(可能是数组,也可能不是),迭代器就要用for...of去遍历,或者用Array.from()转换成真实的数组
  • keys返回的是key集合的迭代器,values返回的是value集合的迭代器,对象里面,key就是索引,而value就是项,然后entries同时返回key和value,每项是一个数组。[key,value]这样,所以会返回[key,value]集合的迭代器,最终会成为一个二维数组
Array.from(["a","b","c"]).entries())
  • 这也是为什么flat会出现的原因了,falt可以让一个二维数组变回一维数组。flat不传参只可以打平一层,传参可以打平多层,打平无限传参Infinity(ES10出现了flat)
  • 字符串填充padStart().padEnd()
  • 使用场景:我们希望以0000-00-00的方式去显示一个日期,在以前,我们可能需要去判断月份的大小,然后考虑是否补全0
  • 现在我们可以使用padStart去补齐,String.prototype.padStart.call(3,2,"0")等同于"3".padStart(2,"0"),补全2位,用0去补齐

5.ES9和ES8相比,增加了什么?

6.ES10和ES9相比,增加了什么?

  • (1)Object.fromEntries()
  • (2)trimStart()和trimEnd()
  • (3)flat和flatMap()
  • (4)Symbol对象的description属性
  • (5)可选的catch
  • segmentfault.com/a/119000001…

7.ES11和ES10相比,增加了什么?


本文部分来源: