Appendix A: Smaller Changes

整数的工作机制

在之前类型化数组里有讨论到关于js存储数字类型的不同,IEEE 754引起了很多的混乱。 js需要付出巨大努力才能确保开发人员不必担心数字编码的细节,但问题仍然不时泄漏。ES 6旨在通过使整数更容易识别和使用来解决这个问题。

识别整数

ES6添加了Number.isInteger方法来表示是否整数。虽然js使用IEEE 754编码系统来表示整数和浮点型,但是他们的存储有些不同,isInteger就是利用这一点,去检查值是不是一个整数。这就意味着看起来是浮点型的数字,可能存储的是整数,导致isInteger返回的是true

console.log(Number.isInteger(25));      // true
console.log(Number.isInteger(25.0));    // true
console.log(Number.isInteger(25.1));    // false

Safe Integers

IEEE 754只能准确地表示-2的53次方2的53次方之间的整数,并且在这个“安全”范围之外,二进制最终会复用于多个数值。 这就意味着js只能表示这个安全范围内的数字:

console.log(Math.pow(2, 53));      // 9007199254740992
console.log(Math.pow(2, 53) + 1);  // 9007199254740992

可以发现,超出这个范围就不行了。 ES6通过Number.isSafeInteger方法去识别一个数字是不是安全的。Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER表示最大和最小的值。 看下面这个例子:

var inside = Number.MAX_SAFE_INTEGER,
    outside = inside + 1;

console.log(Number.isInteger(inside));          // true
console.log(Number.isSafeInteger(inside));      // true

console.log(Number.isInteger(outside));         // true
console.log(Number.isSafeInteger(outside));     // false

你可以试下,MAX_SAFE_INTEGER就是2的53次方减1

new math methods

ECMAScript 6Math对象添加了几种方法,以提高常见数学计算的速度。提高通用计算的速度还可以提高执行许多计算的应用程序的整体速度,例如图形程序。

Math.acosh(x)返回x的反双曲余弦值。

Math.asinh(x)返回x的反双曲正弦值。

Math.atanh(x)返回x的反双曲正切

Math.cbrt(x)返回x的立方根。

Math.clz32(x)返回x的32位整数表示中的前导零位数。

Math.cosh(x)返回x的双曲余弦值。

Math.expm1(x)返回从x的指数函数中减去1的结果。

Math.fround(x)返回x的最近的单精度浮点数。

Math.hypot(... values)返回每个参数的平方和的平方根。

Math.imul(x,y)返回执行两个参数的真正32位乘法的结果。

Math.log1p(x)返回1 + x的自然对数。

Math.log10(x)返回x的基数10对数。

Math.log2(x)返回x的基数2对数。

Math.sign(x)如果x为负,则返回-1;如果x为+0或-0,则返回0;如果x为正,则返回1。

Math.sinh(x)返回x的双曲正弦值。

Math.tanh(x)返回x的双曲正切值。

Math.trunc(x)从float中移除小数位并返回一个整数。

解释每种新方法及其详细功能超出了本章的范围。但是,如果对应用程序需要进行常见的计算,请务必在自己实现之前检查新的Math方法。

Unicode Identifiers

ES6相对之前的版本提供了更好的支持,它还可以更改可用作标识符的字符。在ECMAScript 5中,已经可以将Unicode转义序列用于标识符。例如:

// Valid in ECMAScript 5 and 6
var \u0061 = "abc";

console.log(\u0061);     // "abc"

// equivalent to:
console.log(a);          // "abc"

在此示例中的var语句之后,可以使用\ u0061a来访问该变量。在ECMAScript 6中,还可以使用Unicode代码点转义序列作为标识符,如下所示:

// Valid in ECMAScript 5 and 6
var \u{61} = "abc";

console.log(\u{61});      // "abc"

// equivalent to:
 console.log(a);          // "abc"

此外,ECMAScript 6根据Unicode标准附件#31:Unicode标识符和模式语法正式指定了有效标识符,它提供了以下规则:

  1. 第一个字符必须是$_或任何带有ID_Start的派生核心属性的Unicode符号。

  2. 每个后续字符必须是$_\ u200c(零宽度非连接符),\ u200d(零宽度连接符),或具有ID_Continue的派生核心属性的任何Unicode符号。

ID_StartID_Continue派生的核心属性在Unicode标识符和模式语法中定义,作为识别适用于变量和域名等标识符的符号的方法。该规范不是特定于JavaScript。

Formalizing the proto Property

甚至在ECMAScript 5``完成之前,几个JavaScript引擎已经实现了一个名为__proto__的自定义属性,可用于获取和设置[[Prototype]]属性。 实际上,__ proto__Object.getPrototypeOfObject.setPrototypeOf方法的早期前身。期望所有JavaScript引擎删除此属性是不 现实的(有流行的JavaScript库使用__proto__),因此ECMAScript6也正式化了__proto__行为。但正式化出现在ECMA-262的附录B中以及此警告:

这些功能不被视为核心ECMAScript语言的一部分。编写新的ECMAScript代码时,程序员不应使用或假设存在这些特性和行为。不鼓励ECMAScript实现这 些功能,除非实现是Web浏览器的一部分或者需要运行Web浏览器遇到的相同的旧ECMAScript代码。

ECMAScript规范建议使用Object.getPrototypeOfObject.setPrototypeOf,因为__proto__具有以下特征: 1. 只能在对象文字中指定__proto__一次。如果指定两个__proto__属性,则会引发错误。这是具有该限制的唯一对象文字属性。 2. 计算形式[“__ proto__”]的作用类似于常规属性,不会设置或返回当前对象的原型。与对象文字属性相关的所有规则都适用于此形式,而非计算形式则具有例外。

虽然应该避免使用__proto__属性,但规范定义它的方式很有趣。在ECMAScript 6引擎中,Object.prototype .__ proto__被定义为一个访问器属性, 其get方法调用Object.getPrototypeOf并且其set方法调用Object.setPrototypeOf方法。这与使用__proto__Object.getPrototypeOf/ Object.setPrototypeOf之间 没有什么区别,只是__proto__允许直接设置对象文字的原型。看下面例子:

let person = {
    getGreeting() {
        return "Hello";
    }
};

let dog = {
    getGreeting() {
        return "Woof";
    }
};

// prototype is person
let friend = {
    __proto__: person
};
console.log(friend.getGreeting());                      // "Hello"
console.log(Object.getPrototypeOf(friend) === person);  // true
console.log(friend.__proto__ === person);               // true

// set prototype to dog
friend.__proto__ = dog;
console.log(friend.getGreeting());                      // "Woof"
console.log(friend.__proto__ === dog);                  // true
console.log(Object.getPrototypeOf(friend) === dog);     // true

此示例不是调用Object.create来创建friend对象,而是创建一个标准对象文字,为__proto__属性赋值。使用Object.create方法创建对象时,必须为任何其他对象属性指定完整属性描述符。不够直接。

Last updated