虽说这个标准已经出来很久了,所有的主流浏览器的最新版本也都支持了这些特性,但是很多的教程中并没有包含这个部分,这一节我们专门来总结一下这个标准中的新功能。
Object的新方法
  在最新的JavaScript规范(ECMAScript 5)中,Object扩展了很多不错的静态方法,下面来简单看一下:
1. create/getPrototypeOf方法 - 干净的原型链
  先说简单的getPrototypeOf方法,这个方法统一了获取对象原型的方式,使用这个对象可以获取到对象的原型,这个不多说了。
  在ECMAScript5中,Object添加了静态方法create去串接原型链 - 这样就得到干净的不带冗余成员的原型链。先看一下小例子:
var Dog = {
name : 'dog',
speak : function () { alert('Woof!'); }
};
var dog = Object.create(Dog);
dog.speak();

  这里就是使用了这个方法创建了Dog的一个实例dog,这种方式的本质其实还是与我们之前讨论的使用空对象挂接原型对象是一样的,代码基本就像这样:

Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};

  使用这种方式较之使用构造函数加new的方式来说更加简洁,但是不能设置私有和公开成员,而且实例成员在各个实例之间不共享,所以也有一定的局限性。

  这里我们再回过头来看一下这个方法的定义:
Object.create(prototype, descriptors)
参数
prototype:必需。 要用作原型的对象。 可以为 null,一般也可以在需要的时候使用getPrototypeOf方法获取。
descriptors: 可选。 定义的一组属性的对象字面量,该对象包含了每个属性的描述对象。
属性描述对象称为属性的attributes对象,其含有如下成员:
value:表示该属性的值,默认为undefined。
writable:表示该属性的值(value)是否可以改变,默认为true。这个值如果是false的话,即使是继承的子类的话,也无法修改属性的值,这个也是讲得通的。
enumerable: 表示该属性是否可枚举,默认为true,也就是该属性会出现在for...in和Object.keys()等操作中。
configurable:表示“可配置性”,默认为true。如果设为false,表示无法删除该属性,也不得改变attributes对象(value属性除外),也就是configurable属性控制了attributes对象本身的可写性。
get:表示该属性的取值函数(getter),默认为undefined。
set:表示该属性的存值函数(setter),默认为undefined。
返回值
一个具有指定的内部原型且包含指定的属性(如果有)的新对象。

  毫无疑问,这个函数最有意义的应该就是第二个参数:一组属性描述对象,这个在别的语言中非常有用的特性姗姗来迟,虽然在JavaScript中可以直接使用dog.age=2这种方式定义和修改属性,但是这种数据成员终究不满足封装性的需求,而且不满足属性本质上是函数这种惯例,在这个版本中满足封装性的属性(本质上是函数)终于出现在大家视野中了,我们看一个例子来了解一下如何定义一组属性:

var Shape = { twoDimensional: true, color: 'Red'};
var Square = Object.create(Shape, {
// 简单的属性,不包含任何的其他逻辑的属性
type: { value: 'square', enumerable: true, writable: true },
// 复杂一点的属性,包含有一些逻辑的属性
size: {
get: function() { return this.__size__;},
set: function(pSize) {
if (pSize > 10) alert('Too large...');
// 其他的处理逻辑,例如简单的保存一下
this.__size__ = pSize;
},
enumerable: true
}
});
var square = Object.create(Square);
square.type = 'rectangle';
alert(square.type);
square.size = 9;
alert(square.size);

使用起来还是很简单的,但是有一点不太优雅的代码就是this.__size__这个保存属性值的成员,为了满足封装性,我们得使用一下闭包的特性了:

var Square = Object.create(Shape, (function () {
var m_size; return {
// 简单的属性,不包含任何的其他逻辑的属性
type: { value: 'square', enumerable: true, writable: true },
// 复杂一点的属性,包含有一些逻辑的属性
size: {
get: function() { return m_size;},
set: function(pSize) {
// 常见的条件检查
if (pSize > 10) alert('Too large...');
// 其他的处理逻辑,例如简单的保存一下
m_size = pSize;
},
enumerable: true
}
};
}()));

  把Square定义的那段代码换成上面这段,就有点样子了。

  这里有一点需要注意,像上面例子中定义type那样的简单属性,如果不强行把writable不设为true的话,则赋值会失败,这个不知是浏览器的默认设定还是JavaScript的Bug,不管是哪个,虽然那些属性的默认值都是true,大家需要的话还是写上吧,特别是writable这个属性。
2. defineProperty, defineProperties方法 - 迟到的属性
  上面我们看到了在create方法中定义属性的例子,如果是现有的对象,我们仍然可以给它定义新的属性,这是通过使用defineProperty, defineProperties方法实现的,前者定义一个属性,后者定义一组属性,让我们改写上面的例子中定义的type:
var Shape = { twoDimensional: true, color: 'Red'};
var square = Object.create(Shape);
Object.defineProperty(square, 'type', {
value : 'square',
enumerable : true,
writable: true
});
square.type = 'rectangle';
alert(square.type);

  使用defineProperties方法就与create中的第二个参数一致了,参见:

var Shape = { twoDimensional: true, color: 'Red'};
var square = Object.create(Shape);
Object.defineProperties(square, (function () {
var m_size; return {
// 简单的属性,不包含任何的其他逻辑的属性
type: { value: 'square', enumerable: true, writable: true },
// 复杂一点的属性,包含有一些逻辑的属性
size: {
get: function() { return m_size;},
set: function(pSize) {
// 常见的条件检查
if (pSize > 10) alert('Too large...');
// 其他的处理逻辑,例如简单的保存一下
m_size = pSize;
},
enumerable: true
}
};
}()));
square.type = 'rectangle';
alert(square.type);
square.size = 9;
alert(square.size);

  注意defineProperty/defineProperties这两个函数的返回值就是修改后的对象,有时候会使用这个返回值。

  很强大的属性功能吧,下面还有另外一种定义的方式,那就是使用get/set关键字,看个例子:
var Shape = {
get type() { return this.__type__;},
set type(value) { this.__type__ = value;}
};
var square = Object.create(Shape);
square.type = 'rectangle';
alert(square.type);

  简单吧,很简洁,非常强大。

3. keys, getOwnPropertyNames方法 - 获取所有的属性
  这两个方法得到对象上面直接定义的(非原型链上的)所有属性,只不过keys只得到可枚举的属性,而getOwnPropertyNames方法可以得到所有属性,不管属性定义的时候enumerable是否为true。看一个例子:
var o = { name: 'frank'};
Object.defineProperties(o, {
p1: { value: 1, enumerable: true },
p2: { value: 2, enumerable: false }
});
alert(Object.keys(o));
alert(Object.getOwnPropertyNames(o));

  注意name这种原始的属性是可枚举的,以前通过for/in结合hasOwnProperty方法才能完成枚举对象自身定义的属性的功能现在直接可以通过遍历keys完成了。

4. preventExtensions/isExtensible,seal/isSealed,freeze/isFrozen - 禁止扩展对象
  这3组方法用于控制对象的状态:
preventExtensions方法禁止对象添加新属性,isExtensible检测对象是否使用了preventExtensions方法。
seal方法禁止对象添加新属性和禁止删除已有属性,isSealed检测对象是否使用了seal方法。
freeze方法禁止对对象做任何修改,不能添加新属性和删除已有属性,也不能修改对象的属性值,isFrozen检测对象是否使用了freeze方法。

  看到了吧,一个比一个严格,等到了使用freeze方法的时候,对象完全变成了只读对象,这个在很多场合下还是很有用的。看个简单的例子:

var o = { name: 'frank'};
Object.preventExtensions(o);
o.age = 10;
alert(o.age); //undefined,代表无法添加新属性
Object.seal(o);
delete o.name;
alert(o.name); // 删除不了
Object.freeze(o);
o.name = 'dong';
alert(o.name); // 无法修改
Array的新方法
  这里的新方法主要是新的实例方法(扩展了原型链对象)。
1. indexOf/lastIndexOf
  这一组方法通过方法名就知道其用途了,返回元素在集合中首次/最后一次出现的索引值,不存在的话返回-1。
var a = ['a','b','c','b'];
alert(a.indexOf('b')); //
alert(a.indexOf('y')); // -1
alert(a.lastIndexOf('b')); //

2. every/some/forEach/filter/map/reduce/reduceRight

  这一组方法都与时髦的函数式编程紧密相关,这些方法的参数是一个函数,这个作为参数的函数本身可以接收三个参数:数组的当前元素item、该元素的位置index和整个数组arr。另外,上下文对象(context)可以作为第二个参数,传入forEach(), every(), some(), filter(), map()方法中,用来绑定函数运行时的上下文。
  下面来看看这些方法的意图:
map/forEach方法 - 遍历元素执行指定的操作
  map方法对所有元素依次调用一个函数,根据函数结果返回一个新数组。
[1, 2, 3].map(function(item, index, arr){
return item * item;
});
// [1, 4, 9]

  通过函数的call方法,map方法可以用于字符串。

[].map.call('abc', function (x) { return x.toUpperCase() })
// [ 'A', 'B', 'C' ]
// 或者
'abc'.split('').map(function (x) { return x.toUpperCase() })
// [ 'A', 'B', 'C' ]

  forEach方法对所有元素依次执行一个函数,它与map的区别在于不返回新数组,而是对原数组的成员执行某种操作,甚至可能改变原数组的值。

[1, 2, 3].forEach(function(item, index, arr){
console.log("array[" + index + "] = " + item);
});
// array[0] = 1
// array[1] = 2
// array[2] = 3

  从上面代码可以看到,map和forEach的参数格式是一样的,都是一个函数。该函数接受三个参数,分别是当前元素、当前元素的位置(从0开始)、整个数组。

  这两个方法都可以接受第二个参数,用来绑定函数中的this关键字。
var out = [];
[1, 2, 3].map(function(item, index, arr){
this.push(item * item);
}, out);
out // [1, 4, 9]

  上面代码表示,如果提供一个数组作为第二个参数,则函数内部的this关键字就指向这个数组。

filter方法 - 选取满足指定条件的元素
  filter方法依次对所有数组成员调用一个测试函数,返回结果为true的成员组成一个新数组返回。
[1,2,3,4,5].filter(function(item){
return (item>3);
})
// [4,5]

  上面代码将大于3的原数组成员,作为一个新数组返回。

  filter方法的参数必须是一个返回布尔值的函数。该函数的第一个参数是当前数组成员的值,这是必需的,后两个参数是可选的,分别是当前数组成员的位置和整个数组。
[1, 2, 3, 4, 5].filter(function(item, index, arr){
return index % 2 === 0;
});
// [1, 3, 5]

  上面代码返回原数组偶数位置的成员组成的新数组。

some/every方法 - 检查集合是否满足指定的条件
  这两个方法用来判断数组成员是否符合某种条件。
  some方法对所有元素调用一个测试函数,只要有一个元素通过该测试,就返回true,否则返回false。
[1, 2, 3, 4, 5].some(function(item, index, arr){
return item >= 3;
});
// 返回true

  上面代码表示,如果存在大于等于3的数组成员,就返回true。

  every方法对所有元素调用一个测试函数,只有所有元素通过该测试,才返回true,否则返回false。
[1, 2, 3, 4, 5].every(function(item, index, arr){
return item >= 3;
});
// 返回false

  上面代码表示,只有所有数组成员大于等于3,才返回true。

  从上面的代码可以看到,some和every的使用方法与map和forEach是一致的,参数完全一模一样。也就是说,它们也可以使用第二个参数,用来绑定函数中的this关键字。
reduce/reduceRight方法 - 累计集合中的指定的元素
  reduce和reduceRight方法的作用,是依次处理数组的每个元素,最终累计为一个值。这两个方法的差别在于,reduce对数组元素的处理顺序是从左到右,reduceRight则是从右到左,其他地方完全一样。
reduce方法的第一个参数是一个处理函数。该函数接受四个参数,分别是:
用来累计的变量(即当前状态)
数组的当前元素
当前元素在数组中的序号(从0开始)
原数组

  这四个参数之中,只有前两个是必须的,后两个则是可选的。

[1, 2, 3, 4, 5].reduce(function(x, y){
return x+y;
});
//

  上面代码的参数x表示累计变量,默认为0,y则是数组的当前元素。reduce方法依次将每个数组元素加入x,最终返回它们的总和15。

  利用reduce方法,可以写一个数组求和的sum方法。
Array.prototype.sum = function (){
return this.reduce(function (partial, value){
return partial + value;
})
};
[3,4,5,6,10].sum()
//

  如果要对累计变量指定初值,可以把它放在reduce方法的第二个参数。

[1, 2, 3, 4, 5].reduce(function(x, y){
return x+y;
}, 10);
//

  上面代码指定参数x的初值为10,所以数组元素从10开始累加,最终结果为25。

  由于reduce方法依次处理每个元素,所以实际上还可以用它来搜索某个元素。比如,下面代码是找出长度最长的数组元素。
function findLongest(entries) {
return entries.reduce(function (longest, entry) {
return entry.length > longest.length ? entry : longest;
}, '');
}
静态方法 - isArray
  这个方法不用多说,就是判断一个对象是否是数组,直接看个例子:
var names = ['Collis', 'Cyan'];
Array.isArray(names); // true
Function的新实例方法 - bind方法
  这个方法与apply/call类似,只不过apply/call是直接调用了方法,而bind只是把this绑定到了指定的参数上,而并不执行方法,看个例子:
// 仅仅绑定了this,还需要主动的通过对象去调用
tooltip.show = showText.bind(tooltip);
tooltip.show();
overlay.show = showText.bind(overlay);
overlay.show();
// 直接调用的apply/call形式
showText.call(tooltip);
showText.call(overlay);
Date的新方法
静态方法 - now方法
  now方法返回当前距离1970年1月1日 00:00:00 UTC的毫秒数(Unix时间戳乘以1000)。看个例子:
Date.now()
// 1364026285194类似的数字

  如果需要更精确的时间,可以使用window.performance.now()。它提供页面加载到命令运行时的已经过去的时间,单位是浮点数形式的毫秒。

window.performance.now()
// 21311140.415类似的数字

  这一组方法可用于生成一种唯一的id标识。

实例方法 - toJSON方法
  自己写也不难,不过内置了也不错,看个例子:
alert(new Date().toJSON());
String的新实例方法 - 迟到的trim方法
  该方法用于去除字符串两端的空格,终于内置了,看个简单的例子:
" hello world ".trim()
// "hello world"

JavaScript大杂烩13 - 总结ECMAScript 5新功能的更多相关文章

  1. ECMAScript es6新功能讲解视频教程

    下载链接:https://www.yinxiangit.com/1.html 目录: 01.课程介绍-ECMAScript 新功能.mp402.块的作用域-let.mp403.恒量-const.mp4 ...

  2. Python Twisted系列教程13:使用Deferred新功能实现新客户端

    作者:dave@http://krondo.com/deferred-all-the-way-down/  译者:杨晓伟(采用意译) 你可以从这里从头阅读这个系列. 介绍 回忆下第10部分中的客户端5 ...

  3. ECMAScript 2016,2017 和 2018 中所有新功能的示例

    很难追踪 JavaScript(ECMAScript)中的新功能. 想找到有用的代码示例更加困难. 因此,在本文中,我将介绍 TC39 已完成 ES2016,ES2017 和 ES2018(最终草案) ...

  4. [转]ECMAScript 2016,2017 和 2018 中所有新功能的示例

    很难追踪 JavaScript(ECMAScript)中的新功能. 想找到有用的代码示例更加困难. 因此,在本文中,我将介绍 TC39 已完成 ES2016,ES2017 和 ES2018(最终草案) ...

  5. 探秘IntelliJ IDEA 13测试版新功能——调试器显示本地变量

    IntelliJ IDEA在业界被公认为最好的Java开发平台之一,JetBrains公司将在12月正式发布IntelliJ IDEA 13版本. 现在,小编将和大家一起探秘密IntelliJ IDE ...

  6. Cobalt Strike 3.13的新功能

    Cobalt Strike 3.13现已推出.此版本添加了TCP Beacong,进程参数欺骗,并将Obfuscate和Sleep功能扩展到SMB和TCP Beacons. TCP Beacon Co ...

  7. Java 17 将要发布,补一下 Java 13 中的新功能

    本文章属于Java 新特性教程 系列,已经收录在 Github.com/niumoo/JavaNotes ,点个赞,不迷路. 自从 Oracle 调整了 Java 的版本发布节奏之后,Java 版本发 ...

  8. 超详细 Java 15 新功能介绍

    点赞再看,动力无限.微信搜「程序猿阿朗 」,认认真真写文章. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. Java 15 在 2 ...

  9. Visual Studio 2017十五项新功能体验

    Visual Studio 2017正式已经于2017.3.7号正式发布,选在这一天发布也是为了纪念Visual Studio 二十周年.MVP 2017技术峰会将于这个周末(3.17)在北京举办,由 ...

随机推荐

  1. Unicode 字符串排序规则(一):如何确定单个字符的顺序

    一.一个具体的例子引发的问题 当今是国际化的时代,多种语言可能同时显示在屏幕上.比如一个人可能喜欢听华语歌.英文歌.韩文歌和日语歌,又比如他的联系人中有中国人.英国人.日本人.韩国人以及有英文名字的中 ...

  2. lable标签的用途

    lable标签的用途:为iput输入框元素定义标注: label 元素不会向用户呈现任何特殊效果.不过,它为鼠标用户改进了可用性.如果您在 label 元素内点击文本,就会触发此控件.就是说,当用户选 ...

  3. A Nice Paper About Mobile Data Offloading

    关于Mobile Data Offloading这个研究领域的Paper基本上该有的都看过了,我想即使再有也无非是那些套路,新不到哪去.同样,这篇paper也是这样,它的出发点是改进原有的利用ad h ...

  4. Http请求-get和post的区别

    GET和POST是HTTP请求的两种基本方法. 最直观的区别就是GET把参数包含在URL中,以?的方式来进行拼接,POST通过request body传递参数.并且GET请求在URL中传送的参数是有长 ...

  5. 从svn下载项目,并在tomcat启动

    1.需要先在本地安装mysql,并且启动成功(配置环境变量.客户端等). 2.需要下载小乌龟,需要从svn上下载项目. 3.安装eclipse,并且在eclipse上下载项目,会下载成两个聚合项目,不 ...

  6. ArrayList的实现原理

    ArrayList的线性复杂度是1.想确定一个数据,直接通过索引进行访问.实际上这个过程和数组是非常相似的.ArrayList在整个使用过程中,如果想要高效操作,最好设置一个数组的大小.在个数固定的情 ...

  7. 解决Android Studio 3.x版本的安装时没有SDK,运行时出现SDK tools错误

    好久没更新了,最近手机上的闹钟APP没一个好用的,所以想自己写个. 那Android开发环境搭起来,注意先装好jdk. 1.安装Android Studio google的Android开发网站已经有 ...

  8. Netty自带连接池的使用

    一.类介绍1.ChannelPool——连接池接口 2.SimpleChannelPool——实现ChannelPool接口,简单的连接池实现 3.FixedChannelPool——继承Simple ...

  9. Makefile.am文件配置

    Makefile.am Makefile.am是一种比Makefile更高层次的编译规则,可以和configure.in文件一起通过调用automake命令,生成Makefile.in文件,再调用./ ...

  10. SVM笔记

    1.前言 SVM(Support Vector Machine)是一种寻求最大分类间隔的机器学习方法,广泛应用于各个领域,许多人把SVM当做首选方法,它也被称之为最优分类器,这是为什么呢?这篇文章将系 ...