ECMAScript 5宣布于2009年12月。ECMAscript 5.1版(下文称ES5)宣布于2011年6月,,而且成为ISO国际规范(ISO/IEC 16262:2011)
http://www.ecma-international…
ECMAScript 5.1 是ECMAScript(基于JavaScript的范例)规范最新修正。 与HTML5范例历程实质相似,ES5经由过程对现有JavaScript要领增加语句和原生ECMAScript对象做兼并完成规范化。
有用特征
Object
Object.defineProperty()
该要领直接在一个对象上定义一个新属性,或许修正一个已存在的属性, 并返回这个对象。
Object.defineProperties()
与其一样,只是可以同时定义多个属性。
该要领许可准确增加或修正对象的属性。经常运用的场景
- 定义
setter
和getter
。 (在ES6中已有了更好的定义要领) - 定义对象属性是不是可罗列
enumerable
。
可罗列的属性键值可以被for in
和Object.keys
取得。
最常见的例子就是,[]数组
中索引属性是可罗列的,而规范成员要领就是不可罗列的。
~! 这也是为何我们不要运用for in
遍历数组的缘由,因为能够有一些低劣的上下文代码,为数组增加了一个可罗列的要领,因而我们在扩大一个迥殊对象属性时迥殊须要迥殊关注这一点
Object.keys()
把对象的返回一个包括对象可罗列键值
的数组。
Object.keys
和语句 for in
的功用非常相似,经常是一些仔细的javascript开辟者的议论热门。追念那ES5还不完整兼容的年代, for in
负担了遍历对象键值的使命。
然则二者现实上是不一样的!
for in
会遍历对象原型链上一切的属性,包括继承下来的属性,而 Object.keys
只会遍历对象自身本身具有的属性,因而在一些场景下 Object.keys
更快,所以在许多场景下我们都应当优先运用Object.keys
。
var a = {a1:1,a2:2,a3:3};
var b = {b1:1,b2:2,b3:3};
b.__proto__ = a;
for(var key in b) {
console.log(key); //b1,b2,b3,a1,a2,a3
}
Object.keys(b); //b1,b2,b3
参考:why-is-object-keys-faster-than-hasownproperty
而且因为该要领返回的是一个数组,因而我们也能很好的连系数组要领去处置惩罚对象中的数据
var obj = { a:'1', b:'2', c:'3' };
var values = Object.keys(obj).map(function(key){return obj[key]}); // 1,2,3
Object.freeze()
与 Object.isFrozen
要领可以凝结一个对象。凝结对象是指那些不能增加新的属性,不能修正已有属性的值,不能删除已有属性,以及不能修正已有属性的可罗列性、可设置性、可写性的对象。也就是说,这个对象永远是不可变的。该要领返回被凝结的对象。
注重的是这个要领只会凝结被传入的对象,而不会凝结对象key值所援用的对象。
var obj = {a: {b: 'c' }};
Object.freeze(obj);
obj.a = 123; //不能胜利赋值,但也不会报错,只会寂静失利
obj.a.b = 'd'; //能胜利赋值 => {a: {b: 'd'}}
相似的要领另有Object.seal(obj)
和Object.preventExtensions(obj)
Object.freeze
引入不可变数据观点,然则因为现实开辟中对机能的忧愁,现实很少被用到。
假如有场景须要防止对象运用者修正对象,Object.freeze
将是一个很好的要领。而且因为数组[]
也是一种对象,一样也可以为经由过程该要领凝结数组。
Array
关于数组规范API的扩大可以说是ES5.1中的重头戏,这些中心API今天和将来都将为我们带来方便和启示, 这里枚举和引见一些经常运用的规范API。
Array.isArray()
Array.isArray() 要领用来推断某个值是不是为数组。假如是,则返回 true,不然返回 false。
javascript有六种原始数据范例primitive
,包括undefined
,object
,function
,boolean
,number
,string
个中object
包括四种能经由过程语法糖组织的形状{}
,null
,/\w+/
(正则表达式),[]
(数组)
关于后三种迥殊object
,null
可以运用xxx === null
,正则表达式可以经由过程xxx instanceof RegExp
推断,而数组大多数时刻好像可以经由过程xxx instanceof Array
推断。
然则数组的状况依然比较迥殊,主假如数组在iframe中被通报时的场景,xxx instanceof Array
会涌现误判。这类状况较为稀有,相干材料参考:
- Difference between using Array.isArray and instanceof Array
- Determining with absolute accuracy whether or not a JavaScript object is an array
只管xxx instanceof Array
和Array.isArray()
大多数时刻表现是一致的,然则我们依然应当运用越发完整硬朗的后者。
注重的是该要领并不能推断一些很像数组的对象ArrayLike
,比方querySelectorAll
返回的ElementsList
,经由过程ES6(ECMAScript 2015
)引入的Array.from
我们可以将其转换成为规范数组
[...].forEach(fn)
让数组的每一项都实行一次给定的函数,返回值为
undefined
大多数时刻该要领是语句for(var i=0;i<length;i++){...}
的替代,在处理作用域变量提拔的时刻forEach
是一个很好的要领。
关于大规模的数组处置惩罚,forEach
机能比for
语句要慢许多,而且有无分外的产出,笔者以为大多数时刻比较鸡肋。然则forEach
依然能够算是读过的代码中运用频次较高的数组要领之一。
[...].map(fn)
返回一个由原数组中的每一个元素挪用一个指定要领后的返回值构成的
新数组。
map
要领现实上是把一个数组映照成为别的一个数组
功用虽然简朴,和forEach很像,但因为能返回新的数组而变得非常有用(失之毫厘,差之千里)。
关于任何一个数组鸠合,都可以运用map举行映照操纵,完成很雄厚的功用,而且保证代码的可读性,该API也非常受开辟者迎接。
**
var arr = ["a","b","c"]
var arrToUpperCase = arr.map(function(ele,index){return ele.toUpperCase()});
// ["A","B","C"]
[...].filter(fn)
要领运用指定的函数测试一切元素,并返回一个包括一切经由过程测试的元素的
新数组。
一样也是非常有用的要领,有时刻会看到不熟习的小伙伴会运用for
和新数组push
完成相似的功用。
<ul>
<li><a href='http://a.com'></a></li>
<li><a href='#invalid'></a></li>
<li><a href='http://b.com'></a></li>
<li><a href='http://c.com'></a></li>
</ul>
var alinks = docuement.querySelector("ul a");
var alinksValid = arrayFrom(alinks).filter(function(a){
return a.getAttribute("href")[0]!=="#"
})
function arrayFrom(arrayLike){
//... Array.from polyfill
}
/*
[
<a href='http://a.com'></a>
,<a href='http://b.com'></a>
,<a href='http://c.com'>
]
*/
[...].some(fn)
要领测试数组中的某些元素是不是经由过程了指定函数的测试,返回boolen值
非常有用的功用,推断数组中是不是某元素相符特定前提。假如传入的要领校验为true
则余下的元素都不会继承遍历,不会有冗余的元素接见。
var arr = [
{name:"xiaoA"}
,{name:"xiaoB"}
,{haha:">_<"}
,{name:"xiaoB"} //不会被接见,已跳出
]
arr.some(function(ele){return !!ele.haha}) // true
该要领有许多用处
- 数组元素举行一些天真的校验
- 挑选数组中第一个相符前提的元素
和for continue break
组合比拟,.some
要领供应更好的可读性和天真性。
[...].every(fn)
和some
相似,但作用是搜检一切元素是不是相符前提,与some
互为补充。大多数场景下都可以用some
完成相干的推断,运用频次不高。
[...].reduce()
与 [...].reduceRight()
要领吸收一个函数作为累加器(accumulator),数组中的每一个值(从左到右)最先兼并,终究为一个值。
最天真的要领,可以完成非常雄厚的功用。
-
reduce
和reduceRight
作用一样,差别的是分别是从摆布方向最先累加 -
reduce(fn,initialValue)
要领第二个参数为初始值initialValue
,会传入累加要领的第一次挪用时的第一个参数中,默许是数组的第一个元素
累加运算
作为累加器,数值盘算可以说是最一般的运用要领。
[1,2,3].reduce(function(a,b){return a+b}); // 1+2+3 => 6
数组去重
[1,2,2,3,3,3].reduce(function(arr,curr){
if (arr.some(equal(curr))) return arr;
arr.push(curr);
return arr;
},[]); // [1,2,3]
function equal(value){
return function(target){return value===target}
}
对象K-V颠倒
var obj = { a:1, b:2, c:3 }
Object.keys(obj).reduce(function(_obj,key){
_obj[obj[key]] = key;
return _obj;
},{}) // {1:"a", 2:"b", 3:"c"}
…更多
数组加工管道
map
、filter
和reduce
都能返回一个数组,因而我们可以让其经由过程链式
组合成为数组加工的管道。
[...].map(fn).filter(fn).reduce(fn)
JSON
两个JSON要领都很经常运用了~
JSON.parse()
依据
rfc4627规范剖析JSON文本。
注重parse假如效果毛病时会抛出非常,壅塞当次事宜轮回中接下来的代码。所以一般须要举行try catch
举行防御性校验
function JSONparseSafe(str) {
try {
return JSON.parse(str);
} catch(e) {
console.warn(str,e);
}
return {};
}
补充:该要领有第二个参数
JSON.parse(text[, reviver])
-
reviver
可选 一个函数,用来转换剖析出的属性值。
JSON.stringify()
把对象序列化成为JSON花样字符串
很经常运用了~,和JSON.parse()
一样会抛出非常,笔者以为一样须要举行try catch
举行防御性校验
注重该要领另有第二和第三个参数的
JSON.stringify(value[, replacer [, space]])
replacer
假如该参数是一个函数,则在序列化过程当中,被序列化的值的每一个属性都邑经由该函数的转换和处置惩罚;假如该参数是一个数组,则只要包括在这个数组中的属性名才会被序列化到终究的 JSON 字符串中。关于该参数更细致的诠释和示例,请参考运用原生的 JSON 对象一文。
space
指定缩进用的空缺字符串,用于美化输出(pretty-print)。
序列化轮回嵌套对象(circular structure
)
var obj = { a:1, b:2 };
obj.self = obj;
// JSON.stringify(obj)
// Uncaught TypeError: Converting circular structure to JSON(…)
// 总所周知,JSON.stringify在序列化轮回对象时会抛出非常
// 这时候我们可以运用如许来处理轮回对象的题目
JSON.stringify(obj ,function(key,value){
if (key && value === obj) return "{[circular]}"
return value
}) //"{"a":1,"b":2,"self":"{[circular]}"}"
String
"string".trim()
要领会删除一个字符串两头的空缺字符。在这个字符串里的空格包括一切的空格字符
(" aa ").trim() //"aa"
要领虽然简朴,然则那些还用正则替代完成一样的功用的同砚好自为之吧<_<
Date
Date.now
Date.prototype.toISOString
保存关键字
虽然在ES5时期,ES6的详细规范特征还没有定稿,然则已定义一些“将来”会被运用的保存的关键字
,在完整完成ES5规范的浏览器/JS引擎中关键字是不能作为字面量(literal)名的,不然将会报错。这些关键字包括:
class
extend
super
enum
import
export
var class = "abc" // Uncaught SyntaxError: Unexpected token =
嗯,没错我们将(已)在ES6顶用上了他们。
兼容性与机能
影响
虽然现在再谈这些”老掉牙”的要领,在现在这个言必及ES6
的时期略显落后,然则ES5作为javascript生长中的重要一环,我们依然有必要去熟习和相识他。
跟着Web的生长,前端开辟者对javascript数据处置惩罚才能的诉求愈来愈猛烈,以至于诞生了厥后如jQuery
、underscore
等普遍运用的东西库。
而ECMAScript 5
的到来也恰是相应这一诉求,经由过程对js规范库的扩大,极大的增强了js的处置惩罚数据的才能,尤其是面临js中[]
(数组)和{}
(对象/哈希表)为中心的复合数据范例时。规范API抹平了差别东西库对同一个功用的完成差别,同时也提高了代码的可读性。
ECMAScript 5
的API设想也吸收了其他范例编程语言中有用头脑,比方管道(pipeline)
、无副作用(no side effects)
、数据不可变(immumable)
等观点,更厥后引入的Stream
(pipe(…).pipe(…))和Promise
(then(…).then(…))也能看到这些影子。
还促进了有用东西库的完美,比方厥后的lodash
和 ramda
等东西库。
ES6也是朝着一样的方向对js举行完美。
有了这些东西,开辟者终究能从数据处置惩罚冗杂的逻辑中解放出来,去关注那些用户关注的部份(界面、中心逻辑等)
兼容性
作为javascript规范库,ES5的特征已被主流浏览器完整支撑,包括桌面端
、挪动端
和Node.js
中都可以放心运用。
(纵然你的客户还在运用IE5、IE7、IE8,大多数也能运用es5-polyfill
举行兼容)
机能
对某些规范API带来潜伏机能消耗的怀疑确切使得相当多小伙伴望而生畏,然则我们依然应当去相识这些规范的API,进修他们的设想头脑,即便在一些机能请求较高的场景中,我们依然可以以规范作为参考,设想出文雅的可读性高的要领,而在大部份的场景中我以为应当合理去运用它们,享用规范完美带来的盈余。
如许能以一个更好地预备,拥抱将来更多的新特征。
相干链接
- JavaScript 规范库 – MDN
- Optimization-killers – bluebird (JavaScript机能优化技能)
- Composers and audiences (译文)
Enjoy!
~ 当我们为ES6
的特征觉得高兴的同时, 我们已晓得怎样运用ES5
了吗?