談談JavaScript版本演進史及ES3、ES5區別和特性
根據RedMonk釋出的2018年初程式語言排行榜顯示,JavaScript高居榜首,說明JavaScript的火熱程度,其從90年代初誕生到現在經歷了幾個大的版本迭代:
- ES3,JavaScript 的第三版,從 1999 年開始
- ES5,2009 年釋出
- ES6,2015年6月17日,ECMAScript 6釋出正式版本,即ECMAScript 2015
作為開發人員,我們需要擁抱變化,掌握並使用新版本,同時也要了解版本之間的差異,評估歷史遺留程式碼是不是需要改進、甚至重構。本文討論ES5的新特性及ES3和ES5的區別。
1、保留關鍵字
Javascript 的保留關鍵字不可以用作變數、標籤或者函式名。有些保留關鍵字是作為 Javascript 以後擴充套件使用。ES5較ES3新添加了幾個保留關鍵字:
1)class:類,ES6引入
2)const:常量,ES6引入
3)enum:
4)extends:類繼承,ES6引入
5)import:模組匯入,ES6引入
6)export:模組匯出,ES6引入
7)super:呼叫父類的建構函式,ES6引入
2、瀏覽器相容性
參考:https://caniuse.com/#search=ES5說明
1)ES3,可以認為所有瀏覽器都支援;
2)ES5,現代瀏覽器都支援(>=IE9), IE9不支援嚴格模式。
3、ES5豐富了物件方法、屬性處理
1)ES5屬性增加getter、setter儲存器,看個demo就明白了:
// ES3
var o = (function(){
var age = 0;
return {
get_age:function(){ return age; },
set_age:function(v){ age = v; }
}
})();
console.log(o.get_age()); // 0
o.set_age(12);
console.log(o.get_age()); // 12
// ES5
var o = (function(){
var age = 0;
return {
get age (){return age;},
set age (v){ age = v; }
}
})();
console.log(o.age); // 0
o.age =12;
console.log (o.age); // 12
2)ES5屬性增加可讀寫、可遍歷、是否可刪除設定,看個案例:
- Configurable:表示能否通過delete刪除屬性或者刪除後從新定義值,或者能把屬性修改為訪問器屬性,預設true。
- Enumerable:表示能否通過for-in遍歷屬性的值,預設為true。
- Writable:表示能否直接定義屬性的值,預設為true。
- Value:表示屬性對應的值,預設值為undefined。
var o5={}
Object.defineProperty(o5,"name",{
writable:false, //可賦值?
configurable:false, //可刪除?
enumerable:true, //可遍歷?
value:"oes5" //當前name屬性的具體值
})
console.log(o5.name) //oes5
o5.name="321"
console.log(o5.name) //writable為false, 賦值失效, name依然為"oes5"
delete o5.name
console.log(o5.name) //因為configurable為false所以不能刪除, name依然為“oes5”
3)Object增加了很多方法
- Object.defineProperties(obj, propName, descriptorSet) 定義物件屬性,上文DEMO已經提及
- Object.create(protoObj, descriptorSet),物件建立函式,一個很關鍵的函式,可以解決物件繼承問題;
- Object.getOwnPropertyNames(obj),獲取物件自有屬性名稱
- Object.getPrototypeOf(obj),獲取物件原型物件,=== obj.proto
- Object.getOwnPropertyDescriptor(obj, propName),獲取屬性定義描述物件{configurable,enumerable,value,writable}
- Object.preventExtensions(obj),阻止物件擴充套件,物件不能增加新屬性
- Object.isExtensible(obj),判斷物件是否可擴充套件
- Object.seal(obj),密封物件,保護物件屬性除值外,其餘定義屬性都不能修改,也不能新增、刪除屬性;
- Object.isSealed(obj):判斷物件是否被密封;
- Object.freeze(obj):物件凍結,物件屬性不能修改,包括值;
- Object.isFrozen(obj):判斷物件是否被凍結;
- Object.keys(obj):獲取物件可列舉的自有屬性名稱,是getOwnPropertyNames(obj)的子集。
4、ES5的函式特性,新增bind方法
參考MDN web docs,The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
The bind() 建立了一個新function,this執行bind物件,看個DEMO。
var module = {
x: 42,
getX: function() {
return this.x;
}
}
var unboundGetX = module.getX;
console.log(unboundGetX()); //全域性作用域, ->undefiend
var boundGetX = unboundGetX.bind(module); //bind, this->module
console.log(boundGetX()); //this.x = module.x = 42
ES3中,我們可以通過apply或者call實現bind操作。
5、ES5 陣列增加很多方法
2個索引方法:indexOf() 和 lastIndexOf();
5個迭代方法:forEach()、map()、filter()、some()、every();
2個歸併方法:reduce()、reduceRight(),具體如下:
- Array.prototype.indexOf()
Returns the first (least) index of an element within the array equal to the specified value, or -1 if none is found. - Array.prototype.lastIndexOf
Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. - Array.prototype.every
Returns true if every element in this array satisfies the provided testing function. - Array.prototype.some
Returns true if at least one element in this array satisfies the provided testing function. - Array.prototype.forEach
Calls a function for each element in the array. - Array.prototype.map
Creates a new array with the results of calling a provided function on every element in this array. - Array.prototype.filter
Creates a new array with all of the elements of this array for which the provided filtering function returns true. - Array.prototype.reduce
Apply a function against an accumulator and each value of the array (from left-to-right) as to reduce it to a single value. - Array.prototype.reduceRight
Apply a function against an accumulator and each value of the array (from right-to-left) as to reduce it to a single value.
看個DEMO。
var dataArray = [1, 7, 5, 6, 1, 7, 3];
console.log(dataArray.indexOf(7)); // 1 預設從0即第一項開始查詢
console.log(dataArray.indexOf('7')); // -1, ===比較,7!=='7'
console.log(dataArray.indexOf(7, 's')); // 1 格式不正確, 從第一項開始查詢
console.log(dataArray.indexOf(7, 2)); // 5 從第三個項開始查詢
console.log(dataArray.lastIndexOf (7)); // 5 預設從末尾第一項開始查詢
console.log(dataArray.lastIndexOf (7, 's'));// -1 格式不正確, 從第一項開始查詢
console.log(dataArray.lastIndexOf (7, 2)); // 1 從末尾第三項往前查詢
// 陣列每個元素是否>1
var every_rst = dataArray.every(function(ele) {
return ele > 1;
})
console.log("every_rst: ", every_rst);
//陣列是否有元素>5
var some_rst = dataArray.some(function(ele) {
return ele > 5;
})
console.log("some_rst: ", some_rst);
var filter_rst = dataArray.filter(function(ele) {
return ele > 5;
})
console.log("filter_rst: ", filter_rst);
var map_rst = dataArray.map(function(ele) {
return ele + 5;
})
console.log("filter_rst: ", map_rst);
var forEach_rst = "";
dataArray.forEach(function(ele, index) {
forEach_rst += (index == 0) ? ele : ',' + ele;
});
console.log("forEach_rst: ", forEach_rst);
var reduce_rst = dataArray.reduce(function(prev, cur) {
return prev + cur
});
console.log("reduce_rst: ", reduce_rst);
// reduceRight,從右向左
6、JSON
ES5提供一個內建的(全域性)JSON物件,可用來序列化( JSON.stringfy )和反序列化( parse )物件為JSON格式。
- JSON.stringify(),js物件轉換成json字串
- JSON.parse(),解析json字串,構建js物件,看個DEMO。
var jsonObj = { x: 5, y: 6 };
var jsonStr = JSON.stringify(jsonObj);
var jsonObj2 = JSON.parse(jsonStr);
console.log(jsonStr); //{"x":5,"y":6}
console.log(jsonObj2, jsonObj == jsonObj2);//Object { x: 5, y: 6 } false
7、Strict Mode
In ES3 or ES5-nonstrict, Failure is silent. Execution will proceed assuming success. And we can’t check after every assignment to see if it succeeded. In ES5, Failed assignments throw. A subset intended to provide more thorough error checking and avoid error-prone constructs.
ES5引入了嚴格模式,預設不啟用,可以通過2種生效方式:
- 全域性生效,包括通過src引入的js檔案,在js程式碼第一行 “use strict”;
- 函式生效,函式第一行 “use strict”;
關於Javascript嚴格模式詳細說明,大家可以參考:
1)Javascript 嚴格模式詳解
2)MDN web docs: Strict mode
啟用嚴格模式後,js程式碼語法和行為將會發生一定改變,具體可以參考上述兩篇博文,其中this為undefined時,不再指向global,本文之前的一個DEMO在嚴格模式下,js會報錯。
"use strict";
var module = {
x: 42,
getX: function() {
return this.x;
}
}
var unboundGetX = module.getX;
console.log(unboundGetX()); //全域性作用域, ->undefiend
var boundGetX = unboundGetX.bind(module); //bind, this->module
console.log(boundGetX()); //this.x = module.x = 42
執行該段程式碼,會報 TypeError: this is undefined,原因:
非嚴格模式下,this為undefined時,會指向global;而嚴格模式下不會,所以取this.x值就報錯了。