1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-29 05:42:20 +00:00

edit Number

This commit is contained in:
ruanyf 2015-09-20 08:41:12 +08:00
parent 8843f24291
commit 9971d06926
4 changed files with 152 additions and 35 deletions

View File

@ -2,14 +2,14 @@
## 二进制和八进制表示法
ES6提供了二进制和八进制数值的新的写法分别用前缀0b和0o表示。
ES6提供了二进制和八进制数值的新的写法分别用前缀`0b``0o`表示。
```javascript
0b111110111 === 503 // true
0o767 === 503 // true
```
八进制不再允许使用前缀0表示而改为使用前缀0o。
八进制不再允许使用前缀0表示而改为使用前缀`0o`
```javascript
011 === 9 // 不正确
@ -18,9 +18,9 @@ ES6提供了二进制和八进制数值的新的写法分别用前缀0b和0o
## Number.isFinite(), Number.isNaN()
ES6在Number对象上新提供了Number.isFinite()和Number.isNaN()两个方法用来检查Infinite和NaN这两个特殊值。
ES6在Number对象上新提供了`Number.isFinite()``Number.isNaN()`两个方法,用来检查`Infinite``NaN`这两个特殊值。
Number.isFinite()用来检查一个数值是否非无穷infinity
`Number.isFinite()`用来检查一个数值是否非无穷infinity
```javascript
Number.isFinite(15); // true
@ -28,12 +28,12 @@ Number.isFinite(0.8); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite("foo"); // false
Number.isFinite("15"); // false
Number.isFinite('foo'); // false
Number.isFinite('15'); // false
Number.isFinite(true); // false
```
ES5通过下面的代码部署Number.isFinite方法。
ES5可以通过下面的代码,部署`Number.isFinite`方法。
```javascript
(function (global) {
@ -50,16 +50,19 @@ ES5通过下面的代码部署Number.isFinite方法。
})(this);
```
Number.isNaN()用来检查一个值是否为NaN。
`Number.isNaN()`用来检查一个值是否为NaN。
```javascript
Number.isNaN(NaN); // true
Number.isNaN(15); // false
Number.isNaN("15"); // false
Number.isNaN(true); // false
Number.isNaN(NaN) // true
Number.isNaN(15) // false
Number.isNaN('15') // false
Number.isNaN(true) // false
Number.isNaN(9/NaN) // true
Number.isNaN('true'/0) // true
Number.isNaN('true'/'true') // true
```
ES5通过下面的代码部署Number.isNaN()。
ES5通过下面的代码部署`Number.isNaN()`
```javascript
(function (global) {
@ -76,7 +79,7 @@ ES5通过下面的代码部署Number.isNaN()。
})(this);
```
它们与传统的全局方法isFinite()和isNaN()的区别在于传统方法先调用Number()将非数值的值转为数值再进行判断而这两个新方法只对数值有效非数值一律返回false。
它们与传统的全局方法`isFinite()``isNaN()`的区别在于,传统方法先调用`Number()`将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,非数值一律返回`false`
```javascript
isFinite(25) // true
@ -92,23 +95,28 @@ Number.isNaN("NaN") // false
## Number.parseInt(), Number.parseFloat()
ES6将全局方法parseInt()和parseFloat()移植到Number对象上面行为完全保持不变。
ES6将全局方法`parseInt()``parseFloat()`移植到Number对象上面行为完全保持不变。
```javascript
// ES5的写法
parseInt("12.34") // 12
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45
// ES6的写法
Number.parseInt("12.34") // 12
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
```
这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。
```javascript
Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true
```
## Number.isInteger()
Number.isInteger()用来判断一个值是否为整数。需要注意的是在JavaScript内部整数和浮点数是同样的储存方法所以3和3.0被视为同一个值。
`Number.isInteger()`用来判断一个值是否为整数。需要注意的是在JavaScript内部整数和浮点数是同样的储存方法所以3和3.0被视为同一个值。
```javascript
Number.isInteger(25) // true
@ -118,7 +126,7 @@ Number.isInteger("15") // false
Number.isInteger(true) // false
```
ES5通过下面的代码部署Number.isInteger()。
ES5可以通过下面的代码部署Number.isInteger()。
```javascript
(function (global) {
@ -138,19 +146,123 @@ ES5通过下面的代码部署Number.isInteger()。
})(this);
```
## 安全整数和Number.isSafeInteger()
## Number.EPSILON
JavaScript能够准确表示的整数范围在`-2^53``2^53`之间。ES6引入了`Number.MAX_SAFE_INTEGER``Number.MIN_SAFE_INTEGER`这两个常量,用来表示这个范围的上下限。`Number.isSafeInteger()`则是用来判断一个整数是否落在这个范围之内
ES6在Number对象上面新增一个极小的常量`Number.EPSILON`
```javascript
var inside = Number.MAX_SAFE_INTEGER;
var outside = inside + 1;
Number.EPSILON
// 2.220446049250313e-16
Number.EPSILON.toFixed(20)
// '0.00000000000000022204'
```
Number.isInteger(inside) // true
Number.isSafeInteger(inside) // true
引入一个这么小的量的目的,在于为浮点数计算,设置一个误差范围。我们知道浮点数计算是不精确的。
Number.isInteger(outside) // true
Number.isSafeInteger(outside) // false
```javascript
0.1 + 0.2
// 0.30000000000000004
0.1 + 0.2 - 0.3
// 5.551115123125783e-17
5.551115123125783e-17.toFixed(20)
// '0.00000000000000005551'
```
但是如果这个误差能够小于`Number.EPSILON`,我们就可以认为得到了正确结果。
```javascript
5.551115123125783e-17 < Number.EPSILON
// true
```
因此,`Number.EPSILON`的实质是一个可以接受的误差范围。
```javascript
function withinErrorMargin (left, right) {
return Math.abs(left - right) < Number.EPSILON
}
withinErrorMargin(0.1 + 0.2, 0.3)
// true
withinErrorMargin(0.2 + 0.2, 0.3)
// false
```
上面的代码部署了一个误差检查函数。
## 安全整数和Number.isSafeInteger()
JavaScript能够准确表示的整数范围在`-2^53``2^53`之间不含两个端点。ES6引入了`Number.MAX_SAFE_INTEGER``Number.MIN_SAFE_INTEGER`这两个常量,用来表示这个范围的上下限。
```javascript
Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1
// true
Number.MAX_SAFE_INTEGER === 9007199254740991
// true
Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER
// true
Number.MIN_SAFE_INTEGER === -9007199254740991
// true
```
`Number.isSafeInteger()`则是用来判断一个整数是否落在这个范围之内。
```javascript
Number.isSafeInteger('a') // false
Number.isSafeInteger(null) // false
Number.isSafeInteger(NaN) // false
Number.isSafeInteger(Infinity) // false
Number.isSafeInteger(-Infinity) // false
Number.isSafeInteger(Number.MIN_SAFE_INTEGER - 1) // false
Number.isSafeInteger(Number.MIN_SAFE_INTEGER) // true
Number.isSafeInteger(1) // true
Number.isSafeInteger(1.2) // false
Number.isSafeInteger(Number.MAX_SAFE_INTEGER) // true
Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1) // false
```
注意,验证运算结果是否落在安全整数的范围时,不要只验证运算结果,而要同时验证参与运算的每个值。
```javascript
Number.isSafeInteger(9007199254740993)
// false
Number.isSafeInteger(990)
// true
Number.isSafeInteger(9007199254740993 - 990)
// true
9007199254740993 - 990
// 返回结果 9007199254740002
// 正确答案应该是 9007199254740003
```
上面代码中,`9007199254740993`不是一个安全整数,但是`Number.isSafeInteger`会返回结果,显示计算结果是安全的。这是因为,这个数超出了精度范围,导致在计算机内部,以`9007199254740992`的形式储存。
```javascript
9007199254740993 === 9007199254740992
// true
```
所以,如果只验证运算结果是否为安全整数,很可能得到错误结果。下面的函数可以同时验证两个运算数和运算结果。
```javascript
function trusty (left, right, result) {
if (
Number.isSafeInteger(left) &&
Number.isSafeInteger(right) &&
Number.isSafeInteger(result)
) {
return result
}
throw new RangeError('Operation cannot be trusted!')
}
trusty(9007199254740993, 990, 9007199254740993 - 990)
// RangeError: Operation cannot be trusted!
trusty(1, 2, 3)
// 3
```
## Math对象的扩展

View File

@ -353,6 +353,8 @@ obj.method = function() { ... }
有了这个属性实际上已经不需要通过Object.create()来生成新对象了。
由于`__proto__`前后的双引号看上去很像内部属性而不像一个正式的对外的API所以从语义角度考虑最好不要使用这个属性而是下面的`Object.setPrototypeOf()``Object.getPrototypeOf()`代替。
**2Object.setPrototypeOf()**
Object.setPrototypeOf方法的作用与__proto__相同用来设置一个对象的prototype对象。它是ES6正式推荐的设置原型对象的方法。

View File

@ -329,7 +329,6 @@ var p = new Proxy(target, handler);
p() === 'I am the proxy';
// true
```
上面代码中变量p是Proxy的实例当它作为函数调用时`p()`就会被apply方法拦截返回一个字符串。
@ -741,21 +740,21 @@ Reflect对象与Proxy对象一样也是ES6为了操作对象而提供的新AP
3 让Object操作都变成函数行为。某些Object操作是命令式比如`name in obj``delete obj[name]`,而`Reflect.has(obj, name)``Reflect.deleteProperty(obj, name)`让它们变成了函数行为。
4Reflect对象的方法与Proxy对象的方法一一对应只要是Proxy对象的方法就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法完成默认行为作为修改行为的基础。
4Reflect对象的方法与Proxy对象的方法一一对应只要是Proxy对象的方法就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法完成默认行为作为修改行为的基础。也就是说不管Proxy怎么修改默认行为你总可以在Reflect上获取默认行为。
```javascript
Proxy(target, {
set: function(target, name, value, receiver) {
var success = Reflect.set(target,name, value, receiver);
if (success) {
log('property '+name+' on '+target+' set to '+value);
log('property ' + name + ' on ' + target + ' set to ' + value);
}
return success;
}
});
```
上面代码中Proxy方法拦截target对象的属性赋值行为。它采用Reflect.set方法将值赋值给对象的属性然后再部署额外的功能。
上面代码中Proxy方法拦截target对象的属性赋值行为。它采用`Reflect.set`方法将值赋值给对象的属性,然后再部署额外的功能。
下面是get方法的例子。
@ -824,7 +823,7 @@ Reflect.get(obj, "foo", wrapper);
等同于`delete obj[name]`
**5Reflect.construct(target, args)**
**5Refl2ect.construct(target, args)**
等同于`new target(...args)`这提供了一种不使用new来调用构造函数的方法。
@ -838,9 +837,9 @@ Reflect.get(obj, "foo", wrapper);
**8Reflect.apply(fun,thisArg,args)**
等同于`Function.prototype.apply.call(fun,thisArg,args)`。一般来说如果要绑定一个函数的this对象可以这样写`fn.apply(obj, args)`但是如果函数定义了自己的apply方法就只能写成`Function.prototype.apply.call(fn, obj, args)`采用Reflect对象可以简化这种操作。
等同于`Function.prototype.apply.call(fun,thisArg,args)`。一般来说如果要绑定一个函数的this对象可以这样写`fn.apply(obj, args)`,但是如果函数定义了自己的`apply`方法,就只能写成`Function.prototype.apply.call(fn, obj, args)`采用Reflect对象可以简化这种操作。
另外需要注意的是Reflect.set()、Reflect.defineProperty()、Reflect.freeze()、Reflect.seal()和Reflect.preventExtensions()返回一个布尔值表示操作是否成功。它们对应的Object方法失败时都会抛出错误。
另外,需要注意的是,`Reflect.set()``Reflect.defineProperty()``Reflect.freeze()``Reflect.seal()``Reflect.preventExtensions()`返回一个布尔值表示操作是否成功。它们对应的Object方法失败时都会抛出错误。
```javascript
// 失败时抛出错误
@ -849,4 +848,4 @@ Object.defineProperty(obj, name, desc);
Reflect.defineProperty(obj, name, desc);
```
上面代码中Reflect.defineProperty方法的作用与Object.defineProperty是一样的都是为对象定义一个属性。但是Reflect.defineProperty方法失败时不会抛出错误只会返回false。
上面代码中,`Reflect.defineProperty`方法的作用与`Object.defineProperty`是一样的,都是为对象定义一个属性。但是,`Reflect.defineProperty`方法失败时,不会抛出错误,只会返回`false`

View File

@ -50,6 +50,10 @@
- Mathias Bynens, [Unicode-aware regular expressions in ES6](https://mathiasbynens.be/notes/es6-unicode-regex): 详细介绍正则表达式的u修饰符
- Axel Rauschmayer, [New regular expression features in ECMAScript 6](http://www.2ality.com/2015/07/regexp-es6.html)ES6正则特性的详细介绍
## 数值
- Nicolas Bevacqua, [ES6 Number Improvements in Depth](http://ponyfoo.com/articles/es6-number-improvements-in-depth)
## 数组
- Axel Rauschmayer, [ECMAScript 6s new array methods](http://www.2ality.com/2014/05/es6-array-methods.html): 对ES6新增的数组方法的全面介绍