ECMAScript 5.1 實用特性概覽

ECMAScript 5發佈於2009年12月。ECMAscript 5.1版(下文稱ES5)發佈於2011年6月,,而且成爲ISO國際標準(ISO/IEC 16262:2011)javascript

http://www.ecma-international...html

ECMAScript 5.1 是ECMAScript(基於JavaScript的規範)標準最新修正。 與HTML5規範進程本質相似,ES5經過對現有JavaScript方法添加語句和原生ECMAScript對象作合併實現標準化。

實用特性

Object


Object.defineProperty()

該方法直接在一個對象上定義一個新屬性,或者修改一個已經存在的屬性, 並返回這個對象。 Object.defineProperties()與其同樣,只是能夠同時定義多個屬性。

該方法容許精確添加或修改對象的屬性。經常使用的場景前端

  • 定義settergetter。 (在ES6中已經有了更好的定義方法)
  • 定義對象屬性是否可枚舉enumerable

可枚舉的屬性鍵值可以被for inObject.keys得到。java

最多見的例子就是,[]數組中索引屬性是可枚舉的,而標準成員方法就是不可枚舉的。git

~! 這也是爲何咱們不要使用for in遍歷數組的緣由,由於可能有一些拙劣的上下文代碼,爲數組添加了一個可枚舉的方法,所以咱們在擴展一個特殊對象屬性時特別須要特別關注這一點github


Object.keys()

把對象的返回一個包括對象可枚舉鍵值的數組。web

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+/(正則表達式),[](數組)

對於後三種特殊objectnull可使用xxx === null,正則表達式能夠經過xxx instanceof RegExp判斷,而數組大多數時候彷佛能夠經過xxx instanceof Array判斷。

可是數組的狀況仍然比較特殊,主要是數組在iframe中被傳遞時的場景,xxx instanceof Array會出現誤判。這種狀況較爲罕見,相關資料參考:

儘管xxx instanceof ArrayArray.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),數組中的每一個值(從左到右)開始合併,最終爲一個值。

最靈活的方法,可以實現很是豐富的功能。

  • reducereduceRight做用同樣,不一樣的是分別是從左右方向開始累加
  • 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"}

...更多


數組加工管道

mapfilterreduce都能返回一個數組,所以咱們可讓其經過鏈式組合成爲數組加工的管道。

[...].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數據處理能力的訴求愈來愈強烈,以致於誕生了後來如jQueryunderscore等普遍使用的工具庫。

ECMAScript 5的到來也正是響應這一訴求,經過對js標準庫的擴展,極大的加強了js的處理數據的能力,尤爲是面對js中[](數組)和{}(對象/哈希表)爲核心的複合數據類型時。標準API抹平了不一樣工具庫對同一個功能的實現差別,同時也提升了代碼的可讀性。

ECMAScript 5的API設計也吸取了其餘類型編程語言中實用思想,例如管道(pipeline)無反作用(no side effects)數據不可變(immumable)等概念,更後來引入的Stream(pipe(...).pipe(...))和Promise(then(...).then(...))也能看到這些影子。

還促進了實用工具庫的完善,例如後來的lodashramda等工具庫。

ES6也是朝着一樣的方向對js進行完善。

有了這些工具,開發者最終能從數據處理繁雜的邏輯中解放出來,去關注那些用戶關注的部分(界面、核心邏輯等)

兼容性

http://kangax.github.io/compa...

做爲javascript標準庫,ES5的特性已經被主流瀏覽器徹底支持,包括桌面端移動端Node.js中均可以放心使用。
(即便你的客戶還在使用IE五、IE七、IE8,大多數也能使用es5-polyfill進行兼容)

性能

對某些標準API帶來潛在性能損耗的猜疑確實使得至關多小夥伴望而卻步,可是咱們仍然應該去了解這些標準的API,學習他們的設計思想,即使在一些性能要求較高的場景中,咱們仍然可以以標準做爲參考,設計出優雅的可讀性高的方法,而在大部分的場景中我認爲應該合理去使用它們,享受標準完善帶來的紅利。

這樣能以一個更好地準備,擁抱將來更多的新特性。

相關連接

Enjoy!

~ 當咱們爲ES6的特性感到興奮的同時, 咱們已經知曉如何應用ES5了嗎?

相關文章
相關標籤/搜索