全局对象Math在ES6中新增了几个方法。
首先来看下各种数值功能方法。
Math.sign() 函数返回一个数字的符号, 指示数字是正数,负数还是零。
此函数共有5种返回值, 分别是 1, -1, 0, -0, NaN. 代表的分别是正数, 负数, 正零, 负零, NaN。
传入该函数的参数会被隐式转换成数字类型。
例如:
Math.sign(3); // 1
Math.sign(-3); // -1
Math.sign("-3"); // -1
Math.sign(0); // 0
Math.sign(-0); // -0
Math.sign(-Infinity); // -1
Math.sign(Infinity); // 1
Math.sign(NaN); // NaN
Math.sign("foo"); // NaN
Math.sign(); // NaN
对于不支持的浏览器可以使用下面的Polyfill:
if (!Math.sign) {
Math.sign = function(x) {
// 如果 x 是 NaN, 结果是 NaN.
// 如果 x 是 -0,结果是 -0.
// 如果 x 是 +0,结果是 +0.
// 如果 x 是 负数但不是 -0,结果是 -1.
// 如果 x 是 正数但不是 +0,结果是 +1.
x = +x; // 转换成数值
if (x === 0 || isNaN(x)) {
return Number(x);
}
return x > 0 ? 1 : -1;
};
}
单词trunc是截断截取的意思, Math.trunc() 方法会将数字的小数部分去掉,只保留整数部分。
不像 Math 的其他三个方法: Math.floor() 、 Math.ceil() 、 Math.round() , Math.trunc() 的执行逻辑很简单,仅仅是删除掉数字的小数部分和小数点,不管参数是正数还是负数。
传入该方法的参数会被隐式转换成数字类型。
使用示意:
Math.trunc(13.37) // 13
Math.trunc(42.84) // 42
Math.trunc(0.123) // 0
Math.trunc(-0.123) // -0
Math.trunc("-1.123") // -1
Math.trunc(NaN) // NaN
Math.trunc("foo") // NaN
Math.trunc() // NaN
如果想要在IE浏览器中使用,可以试试下面的Polyfill代码:
if (!Math.trunc) {
Math.trunc = function(v) {
v = +v;
return (v - v % 1) || (!isFinite(v) || v === 0 ? v : v < 0 ? -0 : 0);
};
}
Math.cbrt() 函数返回任意数字的立方根。
例如:
Math.cbrt(8); // 2
Math.cbrt(NaN); // NaN
Math.cbrt(-1); // -1
Math.cbrt(-0); // -0
Math.cbrt(-Infinity); // -Infinity
Math.cbrt(0); // 0
Math.cbrt(1); // 1
Math.cbrt(Infinity); // Infinity
Math.cbrt(null); // 0
Math.cbrt(2); // 1.2599210498948734
Polyfill代码如下,可以兼容老旧的浏览器:
if (!Math.cbrt) {
Math.cbrt = function(x) {
var y = Math.pow(Math.abs(x), 1/3);
return x < 0 ? -y : y;
};
}
Math.expm1() 函数返回 Ex - 1,其中 x 是该函数的参数, E 是自然对数的底数 2.718281828459045。
Math.expm1() 中的expm1 是 "exponent minus 1" 的缩写,语义上等同于Math.exp(x)-1,但是实际上两者还是有区别的,当Math.exp()的结果接近于1的时候,Math.expm1()的精度更高,例如:
Math.expm1(1e-10);
// 1.00000000005e-10
Math.exp(1e-10) - 1;
// 1.000000082740371e-10
语法:
Math.expm1(x)
使用示意:
Math.expm1(-1); // -0.6321205588285577
Math.expm1(0); // 0
Math.expm1(1) // 1.7182818284590453
Math.expm1(-38) // -1
Math.expm1("-38") // -1
Math.expm1("foo") // NaN
Polyfill代码如下,可以兼容Internet Explorer浏览器:
Math.expm1 = Math.expm1 || function(x) {
return Math.exp(x) - 1;
};
Math.log1p() 返回参数值+1的自然对数(e),用数学公式表示就是:
如果参数值x小于-1,则返回NaN。
使用示意:
Math.log1p(1); // 0.6931471805599453
Math.log1p(0); // 0
Math.log1p(-1); // -Infinity
Math.log1p(-2); // NaN
对于非常小的x值,添加1可以降低或消除精度。
JS中使用的双浮点数可以提供大约15位的精度。1+1e-15=1.000000000000001,但1+1e-16=1.000000000000000,因此在该算法中正好是1.0,因为超过15的数字是四舍五入的。
当你计算对数(1+x)时,如果x很小,你应该得到一个非常接近x的答案(这就是为什么这些被称为“自然”对数)。如果你计算Math.log(1+1.1111111e-15),你会得到接近1.1111111e-15的答案。取而代之的是,你将得到1.00000000000000111022的对数(舍入是二进制的,所以有时会变得难看),所以你得到的答案是1.11022…e-15,只有3个正确的数字。相反,如果你计算Math.log1p(1.1111111e-15),你会得到一个更精确的答案1.1111110999995e-15,精确到15位(在这种情况下实际上是16位)。
Math.log1p() 方法IE浏览器不支持,polyfill代码如下:
Math.log1p = Math.log1p || function(x) {
return Math.log(1 + x);
};
Math.log2() 方法返回以2为底的对数。
公式如下:
使用示意:
Math.log2(8); // 3
Math.log2(3); // 1.584962500721156
Math.log2(2); // 1
Math.log2(1); // 0
Math.log2(0); // -Infinity
Math.log2(-2); // NaN
Math.log2(1024); // 10
下面是Polyfill代码,此Polyfill模拟Math.log2函数。注意,如果使用位掩码,它会在某些输入(如1<<29)上返回不精确的值,并包装到Math.round()中。
if (!Math.log2) Math.log2 = function(x) {
return Math.log(x) * Math.LOG2E;
};
Math.log10() 方法返回以10为底的对数。
公式如下:
使用示意:
Math.log10(100); // 2
Math.log10(2); // 0.3010299956639812
Math.log10(2); // 0.3010299956639812
Math.log10(1); // 0
Math.log10(0); // -Infinity
Math.log10(-2); // NaN
Math.log10(100000); // 5
参数x小于0会返回NaN。
IE浏览器不支持这个Math静态方法,可以使用下面的Polyfill:
Math.log10 = Math.log10 || function(x) {
return Math.log(x) * Math.LOG10E;
};
Math.fround() 返回最接近的32位单精度浮点数值。
语法:
var singleFloat = Math.fround(doubleFloat);
单精度浮点数占用4个字节(32位)存储空间,包括符号位1位,8位指数,23位小数。
而双精度是1位符号,11位指数,52位小数。
其数值范围为-3.4E38~3.4E38,单精度浮点数最多有7位十进制有效数字,超出部分四舍五入。为什么最多是有7位呢?是这样的,小数部分是23位,除去全部为0的情况以外,最小为2的-23次方,约等于1.19乘以10的-7次方,所以单精度浮点数的小数部分只能精确到后面6位,加上小数点前的一位,即有效数字为7位。
类似,double 尾数部分52位,最小为2的-52次方,约为2.22乘以10的-16次方,所以精确到小数点后15位,有效位数为16位。
回到这里,在JS中,数值默认都是64位双精度的,精度很高,但是,有时候我们只需要32位单精度,例如数值源自于 Float32Array 数据的时候,此时,你会发现虽然数字看起来是相同的,但是32位浮点和64位浮点数无法相等。
为了解决这个问题,就有了 Math.fround() 方法,可以把64位浮点数转换成32位浮点数。
需要注意的是,在内部,JavaScript仍然把参数x视为64位浮点,它只是在尾数的第23位(小数第7位)执行“舍入到偶数”,并将后面所有尾数位设置为0。
例如我们使用Math.random()随机返回一个双精度浮点值,结果是0.8602673475467222,然后作为参数应用在 Math.fround() 方法中,结果下面这些值结果都是一样的:
Math.fround(0.8602673475467222); // 0.8602673411369324
Math.fround(0.8602673499999999); // 0.8602673411369324
Math.fround(0.8602673400000000); // 0.8602673411369324
Math.fround(0.86026733); // 0.8602673411369324
之所以最终的值都是一样的,是因为小数点第7位之后的值都被当做0处理了。
数字1.5可以在二进制数字系统中精确表示,所以在32位和64位中相同:
Math.fround(1.5); // 1.5
Math.fround(1.5) === 1.5; // true
数字1.337不能在二进制数字系统中精确表示,因此它的32位和64位值是不相等的:
Math.fround(1.337); // 1.3370000123977661
Math.fround(1.337) === 1.337; // false
如果值太大,超过了32位浮点值的限制,则返回Infinity,如果值小到超出范围限制,则返回-Infinity:
2 ** 150; // 1.42724769270596e+45
Math.fround(2 ** 150); // Infinity
如果参数不是一个数值,或者参数值是NaN,则返回NaN:
Math.fround('abc'); // NaN
Math.fround(NaN); // NaN
Math.fround() 方法IE浏览器是不认识的,如果项目只需要兼容到IE10+浏览器,则可以使用下面的Polyfill,借助Float32Array对象:
Math.fround = Math.fround || (function (array) {
return function(x) {
return array[0] = x, array[0];
};
})(new Float32Array(1));
如果还需要兼容IE9,甚至IE8浏览器,则可以使用下面这个Polyfill:
if (!Math.fround) Math.fround = function(arg) {
arg = Number(arg);
// 如果是 ±0 和 NaN 直接返回
if (!arg) return arg;
var sign = arg < 0 ? -1 : 1;
if (sign < 0) arg = -arg;
// 计算指数(8位,有符号)。
var exp = Math.floor(Math.log(arg) / Math.LN2);
var powexp = Math.pow(2, Math.max(-126, Math.min(exp, 127)));
// 处理比较小的值:如果指数位都为零,则前导数字为零。
var leading = exp < -127 ? 0 : 1;
// 尾数23位之后的变成0。
var mantissa = Math.round((leading - arg / powexp) * 0x800000);
if (mantissa <= -0x800000) return sign * Infinity;
return sign * powexp * (leading - mantissa / 0x800000);
};
将两个32位整数x和y相乘,并返回类C的32位结果。
这是目前JS中唯一一个32位的基本数学运算,可能有人使用过JavaScript操作符模拟32位运算。例如,idiv可以实现如下:
function idiv(x, y) {
return (x / y) | 0;
}
这种模拟是不行的,将两个32位大整数相乘可能会产生一个过大的双精度数,导致靠后的很多位数丢失。
使用示意:
Math.imul(2, 4); // 8
Math.imul(-1, 8); // -8
Math.imul(-2, -2); // 4
Math.imul(0xffffffff, 5); // -5
Math.imul(0xfffffffe, 5); // -10
IE浏览器的Polyfill如下:
if (!Math.imul) Math.imul = function(a, b) {
var aHi = (a >>> 16) & 0xffff;
var aLo = a & 0xffff;
var bHi = (b >>> 16) & 0xffff;
var bLo = b & 0xffff;
// 0的移位固定了高位部分的符号
// 最后的| 0将无符号值转换为有符号值
return ((aLo * bLo) + (((aHi * bLo + aLo * bHi) << 16) >>> 0) | 0);
};
Math.clz32() 返回参数x的32位二进制表示形式中的前导零位数。
“clz32”是CountLeadingZeroes32的缩写。
如果x不是数字,则它将首先转换为数字,然后转换为32位无符号整数。
如果转换后的32位无符号整数是0,则返回32,因为所有位都是0。
这个函数对于编译成JS的系统特别有用,比如Emscripten。
使用示意:
// 00000000000000000000000000000001
console.log(Math.clz32(1));
// 预期输出: 31
// 00000000000000000000000000000100
console.log(Math.clz32(4));
// 预期输出: 29
// 00000000000000000000001111101000
console.log(Math.clz32(1000));
// 预期输出: 22
Math.clz32(1); // 31
Math.clz32(1000); // 22
Math.clz32(); // 32
var stuff = [NaN, Infinity, -Infinity, 0, -0, null, undefined, 'foo', {}, []];
stuff.every(n => Math.clz32(n) == 32); // true
Math.clz32(true); // 31
Math.clz32(3.5); // 30
下面的polyfill是最有效的:
if (!Math.clz32) Math.clz32 = (function(log, LN2){
return function(x) {
var asUint = x >>> 0;
if (asUint === 0) {
return 32;
}
return 31 - (log(asUint) / LN2 | 0) |0; // "| 0" 作用类似于math.floor
};
})(Math.log, Math.LN2);
Math.hypot() 返回参数平方和的平方根。
语法:
Math.hypot([value1[, value2[, ...]]]);
使用示意:
Math.hypot(3, 4); // 5
Math.hypot(3, 4, 5); // 7.0710678118654755
Math.hypot(); // 0
Math.hypot(NaN); // NaN
Math.hypot(3, 4, 'foo'); // NaN, +'foo' => NaN
Math.hypot(3, 4, '5'); // 7.0710678118654755, +'5' => 5
Math.hypot(-3); // 3, the same as Math.abs(-3)
IE浏览器不支持此方法,可以引入下面的JS代码使之兼容:
if (!Math.hypot) Math.hypot = function() {
var y = 0, i = arguments.length;
while (i--) y += arguments[i] * arguments[i];
return Math.sqrt(y);
};
此方法适合计算两个点之间的距离。
let distance = Math.hypot(y2-y1, x2-x1);
Math.sinh() 返回参数x的双曲正弦值。
使用示意:
Math.sinh(0); // 0
Math.sinh(1); // 1.1752011936438014
Math.sinh(-1); // -1.1752011936438014
Math.sinh(2); // 3.626860407847019
Polyfill代码如下:
Math.sinh = Math.sinh || function(x) {
return (Math.exp(x) - Math.exp(-x)) / 2;
}
Math.cosh() 返回参数x的双曲余弦值。
使用示意:
Math.cosh(0); // 1
Math.cosh(1); // 1.543080634815244
Math.cosh(-1); // 1.543080634815244
Math.cosh(2); // 3.7621956910836314
Polyfill代码如下:
Math.cosh = Math.cosh || function(x) {
return (Math.exp(x) + Math.exp(-x)) / 2;
}
Math.tanh() 返回参数x的双曲正切值。
使用示意:
Math.tanh(0); // 0
Math.tanh(Infinity); // 1
Math.tanh(1); // 0.7615941559557649
Math.tanh(-1); // -0.7615941559557649
Polyfill代码如下:
Math.tanh = Math.tanh || function(x){
var a = Math.exp(+x), b = Math.exp(-x);
return a == Infinity ? 1 : b == Infinity ? -1 : (a - b) / (a + b);
}
Math.asinh() 返回参数x的反双曲正弦值。
使用示意:
Math.asinh(1); // 0.881373587019543
Math.asinh(0); // 0
Math.asinh(-1); // -0.881373587019543
Math.asinh(2) // 1.4436354751788103
Polyfill代码如下:
Math.asinh = Math.asinh || function(x) {
if (x === -Infinity) {
return x;
} else {
return Math.log(x + Math.sqrt(x * x + 1));
}
};
Math.acosh() 返回参数x的反双曲余弦值。
小于1的参数会返回NaN。
使用示意:
Math.acosh(-1); // NaN
Math.acosh(0); // NaN
Math.acosh(0.5); // NaN
Math.acosh(1); // 0
Math.acosh(2); // 1.3169578969248166
Polyfill代码如下:
Math.acosh = Math.acosh || function(x) {
return Math.log(x + Math.sqrt(x * x - 1));
};
Math.atanh() 返回参数x的反双曲正切值。
小于1或者大于1的参数会返回NaN。
使用示意:
Math.atanh(-2); // NaN
Math.atanh(-1); // -Infinity
Math.atanh(0); // 0
Math.atanh(0.5); // 0.5493061443340548
Math.atanh(1); // Infinity
Math.atanh(2); // NaN
Polyfill代码如下:
Math.atanh = Math.atanh || function(x) {
return Math.log((1+x)/(1-x)) / 2;
};
Number.isFinite() 方法用来确定传递的值是否为有限值。
使用示意:
Number.isFinite(Infinity); // false
Number.isFinite(NaN); // false
Number.isFinite(-Infinity); // false
Number.isFinite(0); // true
Number.isFinite(2e64); // true
Number.isFinite('0'); // false, 全局的isFinite('0')返回值是true
Number.isFinite(null); // false, 全局的isFinite(null)返回值是true
如果想要在低版本浏览器中使用,可以引入下面这段JavaScript脚本:
if (Number.isFinite === undefined) Number.isFinite = function(value) {
return typeof value === 'number' && isFinite(value);
}
Number.isNaN() 方法用来判断参数x是否是NaN,同时类型是Number,这是一个比最初的、全局的 isNaN() 方法更健壮的版本。
使用示意:
Number.isNaN(NaN); // true
Number.isNaN(Number.NaN); // true
Number.isNaN(0 / 0); // true
// 下面这些参数如果使用全局的isNaN()方法都是返回true
Number.isNaN('NaN'); // false
Number.isNaN(undefined); // false
Number.isNaN({}); // false
Number.isNaN('blabla'); // false
// 下面的全部返回false
Number.isNaN(true);
Number.isNaN(null);
Number.isNaN(37);
Number.isNaN('37');
Number.isNaN('37.37');
Number.isNaN('');
Number.isNaN(' ');
此方法并不是所有浏览器都支持的,需要打个小补丁:
Number.isNaN = Number.isNaN || function isNaN(input) {
return typeof input === 'number' && input !== input;
}
语法如下:
Number.parseFloat(string)
Number.parseInt(string, radix)
Number.parseFloat方法和全局的parseFloat方法是一样的方法。
Number.parseFloat === parseFloat; // true
Number.parseInt方法和全局的parseInt方法是一样的方法。
Number.parseInt === parseInt; // true
Number.EPSILON是一个数值很小的常量:
Number.EPSILON == 2.220446049250313e-16; // true
可以用来准确比较浮点值。
例如:
0.1 + 0.2 === 0.3; // false
可以借助Number.EPSILON进行准备比较:
function epsEqu(x, y) {
return Math.abs(x - y) < Number.EPSILON;
}
console.log(epsEqu(0.1+0.2, 0.3)); // true
JavaScript只有浮点数(双精度)。因此,整数只是不带小数的浮点数。
Number.isInteger() 方法可以判定数字是不是没有小数,如果没有,则返回 true 。
使用示意:
Number.isInteger(0); // true
Number.isInteger(1); // true
Number.isInteger(-100000); // true
Number.isInteger(99999999999999999999999); // true
Number.isInteger(0.1); // false
Number.isInteger(Math.PI); // false
Number.isInteger(NaN); // false
Number.isInteger(Infinity); // false
Number.isInteger(-Infinity); // false
Number.isInteger('10'); // false
Number.isInteger(true); // false
Number.isInteger(false); // false
Number.isInteger([1]); // false
Number.isInteger(5.0); // true
Number.isInteger(5.000000000000001); // false
Number.isInteger(5.0000000000000001); // true
由于是新特性,不是所有浏览器都支持这个方法,如果想要额外兼容下,可以参考下面的语句:
Number.isInteger = Number.isInteger || function(value) {
return typeof value === 'number' &&
isFinite(value) &&
Math.floor(value) === value;
};
检测是否是合法范围内的整数。包括下面1个方法和2个常量:
其中,Number.MIN_SAFE_INTEGER表示虽小安全整数,Number.MAX_SAFE_INTEGER表示最大安全整数,分别是−2^53^ + 1和2^53^ - 1,具体值是-9007199254740991和9007199254740991。
Number.isSafeInteger() 方法用来判断参数值是否在安全的整数范围内。
使用示意:
Number.isSafeInteger(3); // true
Number.isSafeInteger(Math.pow(2, 53)); // false
Number.isSafeInteger(Math.pow(2, 53) - 1); // true
Number.isSafeInteger(NaN); // false
Number.isSafeInteger(Infinity); // false
Number.isSafeInteger('3'); // false
Number.isSafeInteger(3.1); // false
Number.isSafeInteger(3.0); // true
此方法有兼容性要求,可以使用下面的JS代码修正:
Number.isSafeInteger = Number.isSafeInteger || function (value) {
return Number.isInteger(value) && Math.abs(value) <= Number.MAX_SAFE_INTEGER;
};
ES6中可以使用二进制和八进制表示法指定整数,例如:
0xFF // ES5: 十六进制
结果是:255
0b11 // ES6: 二进制
结果是:3
0o10 // ES6: 八进制
结果是:8
parseInt()方法可以解析十六进制表示的字符串,例如:
parseInt('0xFF'); // 255
parseInt('0xFF', 0); // 255
parseInt('0xFF', 16) // 255
但是如果指定其他进制会认为是0,如下所示:
parseInt('0xFF', 10); // 0
parseInt('0xFF', 17); // 0
ES6支持了数值其他表示方法,例如0b11表示3,0o10表示8,但是, parseInt() 方法在ES6中并没有同步升级,因此,直接 parseInt('0b11') 或者 parseInt('0o10') 不会返回对应的进制值,如下示意:
parseInt('0b111'); // 0
parseInt('0b111', 2); // 0
parseInt('111'); // 7
parseInt('0o10'); // 0
parseInt('0o10', 8); // 0
parseInt('10', 8); // 8
可以使用Number()方法进行转化:
Number('0b111'); // 7
Number('0o10'); // 8
大量案例和Polyfill代码整理自MDN文档。
其中有些数学方法比较实用,例如 Math.hypot() 方法,有些数学处理方法我们很少有机会用到,例如 Math.clz32() 方法。
整理的过程中还是学到不少东西的,希望一段时间后还记得。
本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。
本文地址: https://www.zhangxinxu.com/wordpress/?p=9379
contain 属性允许我们指定特定的 DOM 元素和它的子元素,让它们能够独立于整个 DOM 树结构之外。目的是能够让浏览器有能力只对部分元素进行重绘、重排,而不必每次都针对整个页面。
Html5的新特性语义化标签:有利于SEO,有助于爬虫抓取更多的有效信息,爬虫是依赖于标签来确定上下文和各个关键字的权重。表单新特性,多媒体视频(video)和音频(audio)
var不存在块级作用域,具有变量提升机制。 let和const存在块级作用域,不存在变量提升。在同一作用域内只能声明一次。const在声明时需要赋值且无法修改,但如果常量是对象,则对象的属性可以修改。
Optional Chaining(可选链式调用);Nullish coalescing(空值合并);Pipeline operator(管道运算符)通过三个函数对字符串进行处理;
在今天早些时候Angular团队发布了8.0.0稳定版。其实早在NgConf 2019大会上,演讲者就已经提及了从工具到差分加载的许多内容以及更多令人敬畏的功能。下面是我对8.0.0一些新功能的简单介绍,希望可以帮助大家快速了解新版本
与我使用的其他框架相比,我最喜欢 React 的原因之一就是它对 JavaScript 的暴露程度。没有模板DSL( JSX 编译为合理的 JavaScript),组件 API 只是通过添加 React Hooks 变得更简单,并且该框架为解决的核心 UI 问题提供非常少的抽象概念
最近 ECMAScript2019,最新提案完成:tc39 Finished Proposals,我这里也是按照官方介绍的顺序进行整理,如有疑问,可以查看官方介绍啦~另外之前也整理了 《ES6/ES7/ES8/ES9系列》,可以一起看哈。
JavaScript 最初的目的是为了“赋予网页生命”。这种编程语言我们称之为脚本。它们可以写在 HTML 中,在页面加载的时候会自动执行。脚本作为纯文本存在和执行。它们不需要特殊的准备或编译即可运行。
你可能刚上手 JavaScript,或者只是曾经偶尔用过。不管怎样,JavaScript 改变了很多,有些特性非常值得一用。 这篇文章介绍了一些特性,在我看来,一个严肃的 JavaScript 开发者每天都多多少少会用到这些特性
HTTP/2 相比于 HTTP/1.1,可以说是大幅度提高了网页的性能,只需要升级到该协议就可以减少很多之前需要做的性能优化工作,当然兼容问题以及如何优雅降级应该是国内还不普遍使用的原因之一。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!