- 简洁属性与简洁方法
- 计算属性名与[[prototype]]
- super对象(暂时保留解析)
- 模板字面量(模板字符串)
一、简洁属性与简洁方法
ES6中为了不断优化代码,减低代码的耦合度在语法上下了很大的功夫,上一篇博客解构就是其中一种,在对象属性和方法名称上也有所优化,也就是这篇博客要解析的简洁属性和简洁方法。
什么是简洁属性呢?当通过字面量的方式声明对象时,属性名与赋值的变量名一致时,就可以采用简洁属性,示例:
1 //ES6的对象字面量简洁属性 2 var x = 2, y = 3, 3 obj = { 4 x, 5 y 6 }; 7 //ES5的编译结果 8 var x = 2, 9 y = 3, 10 obj = { 11 x: x, 12 y: y 13 };
什么是简洁方法呢?当采用对象字面量的方式声明对象,可以省略方法的function字符,示例:
1 //ES6的对象字面量简洁方法 2 var obj = { 3 foo(){ 4 //... 5 }, 6 fun(){ 7 //... 8 } 9 } 10 //ES5的编译结果 11 var obj = { 12 foo: function foo() {//... 13 }, 14 fun: function fun() {//... 15 } 16 };
但是简洁方法需要注意,如果在对象方法中出现需要实现递归算法的话,就不能使用简洁方法的语法,比如下面这个代码(ES5的代码)就不能转换成简洁方法的写法:
1 function ruSomething(o){ 2 var x = Math.random(), 3 y = Math.random(); 4 return o.something(x, y); 5 } 6 7 ruSomething({ 8 something:function something( x , y){ 9 if(x > y){ 10 return something(y , x); //这里递归了,请勿使用简洁语法 11 } 12 return y - x; 13 } 14 });
为什么不能呢?接着来看简洁语法的写法:
1 //ES6简洁语法编写上一个示例代码(错误代码,请勿使用) 2 ruSomething({ 3 something( x , y){ 4 if(x > y){ 5 return something(y , x); 6 } 7 return y - x; 8 } 9 }); 10 //ES5的编译结果 11 ruSomething({ 12 something: function (_something) { 13 function something(_x, _x2) { 14 return _something.apply(this, arguments); 15 } 16 17 something.toString = function () { 18 return _something.toString(); 19 }; 20 21 return something; 22 }(function (x, y) { 23 if (x > y) { 24 return something(y, x); 25 } 26 27 return y - x; 28 }) 29 });
因为something(y,x)递归是找不到这个方法的引用,在编译的时候就会认为简洁写法小括号前面是方法执行,后面是一个作用域块,编译时会认为有一个function something(x,y){...}在作用域上,最后导出的ES5的编译结果就是这个奇怪的代码了。
这时候可能会有人认为给something(y,x)递归加上一个this指向,就可以解决了,来看看这种猜想是否成立:
1 //ES6中对象方法递归使用this实现 2 ruSomething({ 3 something( x , y){ 4 if(x > y){ 5 return this.something(y , x); 6 } 7 return y - x; 8 } 9 }); 10 //ES5的编译结果 11 ruSomething({ 12 something: function something(x, y) { 13 if (x > y) { 14 return this.something(y, x); 15 } 16 17 return y - x; 18 } 19 });
看着上面的代码好像编译正确了,没有什么问题,但是这种写法有一个缺陷,来看下面这个模拟代码:
1 var controller = { 2 makeRequest(..){ 3 //.. 4 this.makeRequest(..); 5 } 6 } 7 bun.addEventListener("click",controller.makeRequest,false);
这点代码模拟的是对象方法是被事件触发的,你想想它的this指向了谁?这不用我多说了吧。所以在对象方法需要被执行递归计算的时候最好采用ES5的语法。
二、计算属性名
计算属性名起始在ES5中就已经有存在,只是相对ES6的计算属性名来说还是没有达到最简便的方式。计算属性名其实就是使用表达式计算获取对象属性名,先来回忆ES5的计算属性名:
1 //ES5的计算属性名 2 var prefix = "user_"; 3 var o = { 4 baz:function(){} 5 } 6 o[prefix + "foo"] = function(){}; 7 o[prefix + "bar"] = function(){};
ES5中使用计算属性名不能直接写在对象字面量上,而是需要另外采用对象键的方式来实现,而ES6可以直接写在对象字面量上:
1 var prefix = "user_"; 2 var obj = { 3 baz:function(){}, 4 [prefix + "foo"] : function(){}, 5 [prefix + "bar"] : function(){} 6 }
在对象属性字面这部分,顺便说明一下,ES6标准了[[prototype]]的可以直接使用点的方法添加对象原型属性,但是这个标准化存在着很大的争议,都是这个标准化是为了兼容之前的js代码不得不标准话的语法。
1 var a = {...} 2 var obj = { 3 __proto__:a, 4 ... 5 }
三、模板字面量
模板字面量有通常被称为模板字符串,也有人说是增强版的字符串,用反引号(`)标识。模板字符串可以当作普通的字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
1 //ES6模板字面量语法 2 // 普通字符串 3 console.log(`In JavaScript is a line-feed.`); //可以使用 来实现换行 4 // 多行字符串,模板可以自动实现换行 5 console.log( 6 `In JavaScript this is 7 not legal`); 8 //字符串中嵌入变量 9 var name = "Bob", time = "today"; 10 console.log(`Hello ${name}, how are you ${time}`); 11 12 //ES5编译结果 13 console.log("In JavaScript is a line-feed."); 14 console.log("In JavaScript this is not legal"); 15 var name = "Bob", 16 time = "today"; 17 console.log("Hello ".concat(name, ", how are you ").concat(time));
在模板中可以使用${...}嵌入语法,这样就可以使用模板复用了,因为如果是纯字符的化只能采用字符串拼接“+“,这种写法获取到的是字符串的拼接后的值,而不是拼接表达式,有了模板字面量和${..}嵌入语法就可以实现字符串模板复用。
1 //ES6插入(嵌入)表达式可以嵌套,并且也可以使用模板 2 function upper(s){ 3 return s.toUpperCase(); 4 } 5 var who = "reader"; 6 var text = 7 `A rey ${upper("warm")} welcome 8 to all of you ${upper(`${who}s`)}!`; 9 console.log(text); 10 //ES5的编译结果: 11 function upper(s) { 12 return s.toUpperCase(); 13 } 14 15 var who = "reader"; 16 var text = "A rey ".concat(upper("warm"), " welcome to all of you ").concat(upper("".concat(who, "s")), "!"); 17 console.log(text);
关于标签模板字面量作为方法参数使用时,会像字符串字符串一样吗?千万别用模板字面量替代方法的参数,因为使用模板字面量作为方法的实参是一个独立的语法,通常被称为标签模板字面量,来看示例:
1 function foo(strings, ...values){ 2 console.log(strings), 3 console.log(values) 4 } 5 6 function bar(){ 7 return function foo(strings, ...values){ 8 console.log(strings), 9 console.log(values) 10 } 11 } 12 var desc = "awesome"; 13 foo `Everything is ${desc}!`; 14 bar()`Everything is ${desc}!`; 15 //上面两种执行结果一致 16 //["Everything is ", "!"] 17 //["awesome"]
在标签模板字面量语法中,第一个形参收集的是模板中被嵌入表达式${...}分割的字符串数组,第二个形参要使用“...”语法收集嵌入表达式获取的数据集。关于更多可以了解《你不知道的js》下卷P100~P103