mirror of
https://github.com/ruanyf/es6tutorial.git
synced 2025-05-29 05:42:20 +00:00
edit Number
This commit is contained in:
parent
8843f24291
commit
9971d06926
166
docs/number.md
166
docs/number.md
@ -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对象的扩展
|
||||
|
@ -353,6 +353,8 @@ obj.method = function() { ... }
|
||||
|
||||
有了这个属性,实际上已经不需要通过Object.create()来生成新对象了。
|
||||
|
||||
由于`__proto__`前后的双引号,看上去很像内部属性,而不像一个正式的对外的API,所以从语义角度考虑,最好不要使用这个属性,而是下面的`Object.setPrototypeOf()`和`Object.getPrototypeOf()`代替。
|
||||
|
||||
**(2)Object.setPrototypeOf()**
|
||||
|
||||
Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的prototype对象。它是ES6正式推荐的设置原型对象的方法。
|
||||
|
@ -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)`让它们变成了函数行为。
|
||||
|
||||
(4)Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。
|
||||
(4)Reflect对象的方法与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]`。
|
||||
|
||||
**(5)Reflect.construct(target, args)**
|
||||
**(5)Refl2ect.construct(target, args)**
|
||||
|
||||
等同于`new target(...args)`,这提供了一种不使用new,来调用构造函数的方法。
|
||||
|
||||
@ -838,9 +837,9 @@ Reflect.get(obj, "foo", wrapper);
|
||||
|
||||
**(8)Reflect.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`。
|
||||
|
@ -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 6’s new array methods](http://www.2ality.com/2014/05/es6-array-methods.html): 对ES6新增的数组方法的全面介绍
|
||||
|
Loading…
x
Reference in New Issue
Block a user