4月阅读周·你不知道的JavaScript | 从值的转换到数学计算,ES6新增API,辅助完成常见的任务
背景
去年下半年,我在微信书架里加入了许多技术书籍,各种类别的都有,断断续续的读了一部分。
没有计划的阅读,收效甚微。
新年伊始,我准备尝试一下其他方式,比如阅读周。每月抽出1~2个非连续周,完整阅读一本书籍。
这个“玩法”虽然常见且板正,但是有效,已经坚持阅读三个月。
4月份的阅读计划有两本,《你不知道的JavaScrip》系列迎来收尾。
已读完书籍:《架构简洁之道》、《深入浅出的Node.js》、《你不知道的JavaScript(上卷)》、《你不知道的JavaScript(中卷)》。
当前阅读周书籍:《你不知道的JavaScript(下卷)》。
新增API
Object
从ES6开始,Object静态方法也开始用于那些还没有更自然的有另外归属的(比如Array.from(..))通用全局API。
静态函数Object.is(..)
静态函数Object.is(..)执行比===比较更严格的值比较。
比如:
var x = NaN,
y = 0,
z = -0;
x === x; // false
y === z; // true
Object.is(x, x); // true
Object.is(y, z); // false
应该继续使用===进行严格相等比较;不应该把Object.is(..)当作这个运算符的替代。但是,如果需要严格识别NaN或者-0值,那么应该选择Object.is(..)。
静态函数Object.getOwnPropertySymbols(..)
Symbol很可能会成为对象最常用的特殊(元)属性。所以引入了工具Object.getOwnPropertySymbols(..),它直接从对象上取得所有的符号属性:
var o = {
foo: 42,
[Symbol('bar')]: 'hello world',
baz: true,
};
Object.getOwnPropertySymbols(o); // [ Symbol(bar) ]
静态函数Object.setPrototypeOf(..)
工具Object.setPrototypeOf(..)设置对象的[[Prototype]]用于行为委托。
比如:
var o1 = {
foo() {
console.log('foo');
},
};
var o2 = Object.setPrototypeOf(
{
// .. o2的定义 ..
},
o1,
);
// 委托给o1.foo()
o2.foo(); // foo
更通俗地说,o2和o1的关系在o2的定义上指定。
静态函数Object.assign(..)
ES6新增了Object.assign(..),这是这些算法的简化版本。第一个参数是target,其他传入的参数都是源,它们将按照列出的顺序依次被处理。对于每个源来说,它的可枚举和自己拥有的(也就是不是“继承来的”)键值,包括符号都会通过简单=赋值被复制。Object.assign(..)返回目标对象。
var target = {},
o1 = { a: 1 },
o2 = { b: 2 },
o3 = { c: 3 },
o4 = { d: 4 };
// 设定只读属性
Object.defineProperty(o3, 'e', {
value: 5,
enumerable: true,
writable: false,
configurable: false,
});
// 设定不可枚举属性
Object.defineProperty(o3, 'f', {
value: 6,
enumerable: false,
});
o3[Symbol('g')] = 7;
// 设定不可枚举符号
Object.defineProperty(o3, Symbol('h'), {
value: 8,
enumerable: false,
});
Object.setPrototypeOf(o3, o4);
Object.assign(target, o1, o2, o3);
target.a; // 1
target.b; // 2
target.c; // 3
Object.getOwnPropertyDescriptor(target, 'e');
// { value: 5, writable: true, enumerable: true,
// configurable: true }
Object.getOwnPropertySymbols(target);
// [Symbol("g")]
只有属性a、b、c、e以及Symbol("g")会被复制到target中。
Math
ES6增加了几个新的数学工具,填补了常用计算方面的空白。
这些工具的使用者更可能是asm.js/transpile的JavaScript代码,而非直接开发者。
三角函数
双曲余弦函数:
cosh(..)
反双曲余弦函数:
acosh(..)
双曲正弦函数:
sinh(..)
反双曲正弦函数:
asinh(..)
双曲正切函数:
tanh(..)
反双曲正切函数:
atanh(..)
平方和的平方根(也即:广义勾股定理):
hypot(..)
算术
立方根:
cbrt(..)
计算32位二进制表示的前导0个数:
clz32(..)
等价于exp(x) -1:
expm1(..)
二进制对数(以2为底的对数):
log2(..)
以10为底的对数:
log10(..)
等价于log(x + 1):
log1p(..)
两个数字的32位整数乘法:
imul(..)
元工具
返回数字符号:
sign(..)
返回数字的整数部分向:
trunc(..)
最接近的32位(单精度)浮点值取整:
fround(..)
Number
对Number的两个新增内容就是指向已有的全局函数的引用: Number.parseInt(..)和Number.parseFloat(..)。
静态属性
ES6新增了一些作为静态属性的辅助数字常量:
- Number.EPSILON
任意两个值之间的最小差:2^-52(使用了这个值作为浮点数算法的精度误差值)
- Number.MAX SAFE INTEGER
JavaScript可以用数字值无歧义“安全”表达的最大整数:2^53-1
- Number.MIN SAFE INTEGER
JavaScript可以用数字值无歧义“安全”表达的最小整数:-(2^53-1)或(-2)^53+ 1
静态函数Number.isNaN(..)
标准全局工具isNaN(..)自出现以来就是有缺陷的,它对非数字的东西都会返回true,而不是只对真实的NaN值返回true,因为它把参数强制转换为数字类型(可能会错误地导致NaN)。ES6增加了一个修正工具Number.isNaN(..),可以按照期望工作:
var a = NaN,
b = 'NaN',
c = 42;
isNaN(a); // true
isNaN(b); // true--oops!
isNaN(c); // false
Number.isNaN(a); // true
Number.isNaN(b); // false--修正了!
Number.isNaN(c); // false
静态函数Number.isFinite(..)
Number.isFinite(..)用来检查一个数值是否是有限的。
标准的全局isFinite(..)会对参数进行强制类型转换,但是Number.isFinite(..)会略去这种强制行为。比如:
var a = NaN,
b = Infinity,
c = 42;
Number.isFinite(a); // false
Number.isFinite(b); // false
Number.isFinite(c); // true
var a = '42';
isFinite(a); // true
Number.isFinite(a); // false
整型相关静态函数
JavaScript的数字值永远都是浮点数(IEE-754)。所以确定数字是否为“整型”的概念并不是检查其类型,因为JavaScript并没有这样区分。
ES6新增了一个辅助工具Number.isInteger(..),检查这个值的小数部分是否非0:
Number.isInteger(4); // true
Number.isInteger(4.2); // false
另外,Number.isInteger(..) 会过滤掉x === Math.floor(x)可能会搞混的明显非整数值:
Number.isInteger(NaN); // false
Number.isInteger(Infinity); // false
ES6还定义了一个工具Number.isSafeInteger(..),这个工具检查一个值以确保其为整数并且在Number.MIN SAFE INTEGER-Number.MAX SAFE INTEGER范围之内(全包含):
var x = Math.pow(2, 53),
y = Math.pow(-2, 53);
Number.isSafeInteger(x - 1); // true
Number.isSafeInteger(y + 1); // true
Number.isSafeInteger(x); // false
Number.isSafeInteger(y); // false
字符串
Unicode函数
String.fromCodePoint(..)、String#codePointAt(..)和String#normalize(..)。新增这些函数是为了提高JavaScript字符串值对Unicode的支持。
字符串原型方法normalize(..) 用于执行Unicode规范化,或者把字符用“合并符”连接起来或者把合并的字符解开。
一般来说,规范化不会对字符串的内容造成可见的效果,但是会改变字符串的内容,这可能会影响像length属性的结果,以及通过位置访问字符的方式:
var s1 = 'e\u0301';
s1.length; // 2
var s2 = s1.normalize();
s2.length; // 1
s2 === '\xE9'; // true
normalize(..)接受一个可选的参数,来指定要使用的规范化形式。这个参数必须是这几个值之一:"NFC" ( 默认)、 "NFD"、 "NFKC"或者"NFKD"。
静态函数String.raw(..)
String.raw(..)工具作为内置标签函数提供,与模板字符串字面值(参见第2章)一起使用,用于获得不应用任何转义序列的原始字符串。
这个函数基本上不会被手动调用,而是与标签模板字面值一起使用:
var str = 'bc';
String.raw`\ta${str}d\xE9`;
// "\tabcd\xE9", 而不是" abcdé"
在结果字符串中,\和t是独立的原始字符,而不是转义字符\t。对于Unicode转义序列也是一样。
原型函数repeat(..)
ES6定义了一个字符串原型方法repeat(..)来完成复制的任务:
'foo'.repeat(3); // "foofoofoo"
字符串检查函数
除了ES6之前的String#indexOf(..)和String#lastIndexOf(..),又新增了3个用于搜索/检查的新方法:startsWith(..)、endsWidth(..)和includes(..)。
var palindrome = 'step on no pets';
palindrome.startsWith('step on'); // true
palindrome.startsWith('on', 5); // true
palindrome.endsWith('no pets'); // true
palindrome.endsWith('no', 10); // true
palindrome.includes('on'); // true
palindrome.includes('on', 6); // false
对于所有的字符串搜索/检查方法,如果寻找空字符串"",总是会在字符串的开头或结尾找到。
总结
我们来总结一下本篇的主要内容:
- Object新增了静态函数is(..)和assign(..)。
- Math新增了静态函数acosh(..)和clz32(..)。
- Number新增了静态属性Number.EPSILON,以及静态函数Number.isFinite(..)。
- String新增了静态函数String.fromCodePoint(..)和String.raw(..),以及原型函数repeat(..)和includes(..)。
作者介绍
非职业「传道授业解惑」的开发者叶一一。
《趣学前端》、《CSS畅想》等系列作者。华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。
如果看完文章有所收获,欢迎点赞👍 | 收藏⭐️ | 留言📝。
- 点赞
- 收藏
- 关注作者
评论(0)