前后端差异更小了——浅谈ES(ECMAScript)6
2015年6月,ES6正式发布。至今一年多的时间内,各个浏览器也对支持ES6做出了很大的改善,所以同学们无需顾忌你写代码的浏览器不认识~
这么久的东西一定早有大神剖析过,今天我们以一个后端菜鸟的视角重新解读下ES6加入的新语法。
首先很开心,ES6对class(类)的支持上升到了一个新高度,允许构造和继承,新语法看上来是这样的:
//继承 class parent { constructor(par) { this.Name = par; console.log('[父类的构造方法 ' + this.Name + ']'); } sayHello() { console.log('父类的sayHello方法 Hello ' + this.Name); } } class child extends parent { constructor(name) { super('[子类调用父类的构造 ' + name + ']'); } sayGoodBye() { console.log('子类的sayGoobBue方法 GoodBye ' + this.Name); } }
//调用
var a = new parent('Es6');
a.sayHello();
var b = new child('Max');
b.sayHello();
b.sayGoodByr();
有没有被惊艳到?(可这的确是个Js文件),运行后的效果是这样的:
和后端一样,子类继承父类需要使用关键字extends,继承后,可以使用关键字super调用父类属性。
并且我发现此处的this在被继承后也被子类一并带入,也就是说:this的作用域将会被向下传递。(请参照运行结果最后一行。)
上面是class(类)的继承,有了继承,我们在构建Js代码时,就会获得更强大的能力(可扩展、易维护、易阅读等)。
可能有些同学会说了:我根本不习惯这样写,感觉都不像Js了啊喂!
没关系,ES6怎么会忘记我们的对象字面量呢?继承当然也会出现在对象字面量的应用中:
var Es6Parent = { cons(mess) { console.log('原型Es6Parent的cons方法' + mess); } } var Es6Child = { //设置原型为 Es6Parent ,相当于继承 __proto__: Es6Parent, work() { console.log('下层Es6Child的work方法 I\'m very busy!'); } }
//调用
Es6Parent.cons('原型cons方法');
Es6Child.cons('下级调用上层原型的方法');
Es6Child.work();
运行结果如下:
设置的方式也超简单:使用关键字'__proto__'设置原型即可(只不过是给原型链换了种叫法而已嘛)
下面介绍一些简单实用的语法糖,首先是方便的参数设置:
var Name = 'Max'; console.log(`我是很方便带参数的的波浪符${Name}`);
重点是${},它可以直接在字符串中带入参数(拼接方便很多有木有),但是需要和波浪符(`)搭配使用才有效哦~
接下来是...语法,当它出现在形参列表内,代表不定量参数:
function show(...all) { all.forEach(function (i, v) { console.log(`不定量参数的值:${v}`); }, all); }
//调用
show(1,2,3,4,5,6);
运行结果如下:
定义的时候是不是省力很多呢?还有更好用的,当...出现在实参列表内,它将允许直接传入数组(而不是使用apply):
function sayHi(name, age, sex) { console.log(`大家好,我是${name},今年${age}岁,我是${sex}生。`); } //调用 var arr = ['小明', 18, '男']; sayHi(...arr);
运行结果如下:
定义sayHi函数时,写了3个参数,调用时使用...传入数组时,它将从0下标开始依次顺序匹配参数。
我们在工作中,经常使用回调函数来完成某些操作,但是每次回调都要写个完整的funciton(好麻烦的说),ES6引入了lambda表达式,大大优化了这一操作:
function callBack(back) { back(); } //两种调用方式对比 callBack(function () { console.log('我是旧的调用方式'); }); callBack(()=>console.log('我是lambda调用方式'));
运行结果如下:
使用了lambda以后的函数传入方式是不是更优雅呢?如果比较萌比,那就再来一个对象字面量版本的:
var show_msg = (name, job) => { console.log(`大家好,我叫${name},是一名${job}`) }; //调用 show_msg('暮城','软件攻城狮');
运行结果如下:
现在大家应该已经很清楚了:()=>语法呢,=>前面是参数列表,后面是方法体。以后看到类似的语法可别晕~
语法糖还有很多,我先说这么多,因为下面要说更重要的:新数据类型和监听的实现。
Es6新增了map,set,以及weakMap、weakSet四种类型。
它们都有什么差异呢?先说说map:map以key-value的方式存储,并且在map内所有的键都是唯一的,来看被for in 遍历后的结果:
var par1 = 'key_1'; var par2 = 'key_2'; var testMap = new Map(); testMap.set(par1, '第一个值'); testMap.set(par2, '第二个值'); testMap.set(par1, '第三个值'); for(i of testMap) { console.log(i); }
可以看到第三个值将第一个值顶替掉而不是共存,原因就是第一个值和第三个值键相同。
set和map的差别就在于,它是以value的方式存储,而且同样不允许重复值出现:
var par11 = 'value_1'; var par22 = 'value_2'; var testSet = new Set(); testSet.add(par11); testSet.add(par22); testSet.add(par11); for(i of testSet) { console.log(i); }
至于WeakMap和WeakSet,使用方式都一样,只是这两种类型的键都采用了弱引用,即:作为属性键的对象如果没有其他地方引用时自动回收(自动释放)。
此处就不多做解释,不过我推荐大家使用WeakMap和WeakSet。
现在,我们终于说到了监听器(监听器可是重头戏)
监听器是很有意思的东西,它给予了我们极大的便利,这一点在实现MVVM模型的操作时尤为重要,ES6中的监听看上去大概是这样的:
//被监听的对象 var ob = { name: 'Max', like: 'women' }; //触发监听时的程序 var pro = { set: function (cagObj, cagKey, cagValue) { console.log(`${cagObj[cagKey]}变为了${cagValue}`); cagObj[cagKey] = cagValue; } } ob = new Proxy(ob, pro); ob.like = 'man';
set内定义的function将会在监听对象发生改变时自动触发,参数列表内的3个值也是默认定义的,它们依次是:被修改的对象、该对象的键、该对象的值。
需要注意的是如果你为某元素设定的监听器触发后,它原本的修改进程会被阻止(如果你不进行这一步的话),所以需要我们显式的去修改才可。
运行效果如下:
拥有了这些特性,我们自己想写一个类似于VUE的数据框架也变得简单了许多。
另外,ES6还更新了很多命名空间下的函数(如:math),这里就不一一罗列(写不完并且网上大把)。
最后,ES6的推出让我直观感觉到前后端差距进一步缩小,希望有一天Js可以不借助后端完成数据交互~(不要吐槽我学的晚)