资讯专栏INFORMATION COLUMN

ECMAScript 5.1 实用特性概览

xiao7cn / 2542人阅读

摘要:返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组。方法测试数组中的某些元素是否通过了指定函数的测试,返回值非常实用的功能,判断数组中是否某元素符合特定条件。

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()与其一样,只是可以同时定义多个属性。

该方法允许精确添加或修改对象的属性。常用的场景

定义settergetter。 (在ES6中已经有了更好的定义方法)

定义对象属性是否可枚举enumerable

可枚举的属性键值能够被for inObject.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+/(正则表达式),[](数组)

对于后三种特殊objectnull可以使用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 ArrayArray.isArray()大多数时候表现是一致的,但是我们仍然应该使用更加完备健壮的后者。

注意的是该方法并不能判断一些很像数组的对象ArrayLike,例如querySelectorAll返回的ElementsList,通过ES6(ECMAScript 2015)引入的Array.from我们可以将其转换成为标准数组

[...].forEach(fn)
让数组的每一项都执行一次给定的函数,返回值为undefined

大多数时候该方法是语句for(var i=0;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实现类似的功能。

var alinks = docuement.querySelector("ul a");
var alinksValid = arrayFrom(alinks).filter(function(a){
    return a.getAttribute("href")[0]!=="#"
})

function arrayFrom(arrayLike){
    //... Array.from polyfill
}

/* 
[
   
   ,
   ,
]
*/
[...].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中都可以放心使用。
(即使你的客户还在使用IE5、IE7、IE8,大多数也能使用es5-polyfill进行兼容)

性能

对某些标准API带来潜在性能损耗的猜疑确实使得相当多小伙伴望而却步,但是我们仍然应该去了解这些标准的API,学习他们的设计思想,即便在一些性能要求较高的场景中,我们仍然能够以标准作为参考,设计出优雅的可读性高的方法,而在大部分的场景中我认为应该合理去使用它们,享受标准完善带来的红利。

这样能以一个更好地准备,拥抱未来更多的新特性。

相关链接

JavaScript 标准库 - MDN

Optimization-killers - bluebird (JavaScript性能优化技巧)

Composers and audiences (译文)

Enjoy!

~ 当我们为ES6的特性感到兴奋的同时, 我们已经知晓如何应用ES5了吗?

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86477.html

相关文章

  • ECMAScript 5.1 实用特性概览

    摘要:返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组。方法测试数组中的某些元素是否通过了指定函数的测试,返回值非常实用的功能,判断数组中是否某元素符合特定条件。 ECMAScript 5发布于2009年12月。ECMAscript 5.1版(下文称ES5)发布于2011年6月,,并且成为ISO国际标准(ISO/IEC 16262:2011) http://www.ecma...

    bang590 评论0 收藏0
  • es6

    摘要:只要上述版权通知版权许可和免责声明均包含在所有此类副本和衍生物中。它应用于网景后来所有的浏览器中以及微软之后的版本中。年月,这份标准采用快速程序提交给,并被核准成为国际标准。标准第三版在年月会议上通过并在年月作为标准发布。 ECSA-262标准第六版/2015年6月 ECMAScript 2015语言规范 这是 ECMA-262 第六版,ECMAScript 2015 语言规范 HTM...

    blair 评论0 收藏0
  • javascript如何判断变量的数据类型

    摘要:除和外,所有的数据类型都是可以转化为对象,而如果是对象,就肯定有构造函数。特性因为和没有构造函数,因此不能用此方法来判断。由于同一条原型继承链上的各个对象的构造函数都不一样,因此,此方法可以区分开继承链上的各个自定义数据类型。 typeof 用法示例 var arr = []; typeof arr; //object typeof(arr); //object typeo...

    曹金海 评论0 收藏0
  • ES6-前世今生(0)

    摘要:更新了个版本,最新正式版是语言的下一代标准,早已在年月正式发布。基本不支持移动端浏览器对的支持情况版起便可以支持的新特性。比较通用的工具方案有,,,等。 1、ECMAScript是什么? 和 JavaScript 有着怎样的关系? 1996 年 11 月,Netscape 创造了javascript并将其提交给了标准化组织 ECMA,次年,ECMA 发布 262 号标准文件(ECMA-...

    LeviDing 评论0 收藏0
  • [ ES6 ] 一. ECMAScript 6 相关学习资源

    摘要:浏览器兼容性列表可以看到还是全线飘红的和支持特新列表据此在和上使用这些新特新待补充二相关教程最重要的产品规格书,什么教程也脱离不了这里的标准,英文好的还是多看点。 一. ES6新特性相关 es6features : 经典的ES6新特性预览,github 逼近 10k star . ES6新特性概览 :同样也很全面的特性介绍的中文版。 浏览器兼容性列表 :可以看到还是全线飘红的~~~ ...

    Towers 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<