Math方法和位運算幾乎是被忽略得最嚴重的知識點, 和正則同樣, 不用不知道, 一用處處查. 爲了告別這種低效的編程模式, 我特意總結此篇, 系統梳理了這兩個知識點. 以此爲冊, 助你攻破它們.javascript
原文: louiszhai.github.io/2016/07/01/…html
截至ES6, JavaScript 中內置(build-in)構造器/對象共有19個, 其中14個是構造器(Number,Boolean, String, Object, Function, Array, RegExp, Error, Date, Set, WeakSet, Map, Proxy, Promise), Global 不能直接訪問, Arguments僅在函數調用時由JS引擎建立, 而 Math, JSON, Reflect 是以對象形式存在的, 本篇將帶你走進 JS 內置對象-Math以及與之息息相關的位運算, 一探究竟.java
衆所周知, 若是須要使用js進行一些常規的數學運算, 是一件十分麻煩的事情. 爲了解決這個問題, ECMAScript 在1.1版本中便引入了 Math. Math 之因此被設計成一個對象, 而不是構造器, 是由於對象中的方法或屬性能夠做爲靜態方法或常量直接被調用, 方便使用, 同時, Math 也沒有建立實例的必要.git
屬性名 | 描述 | 值 |
---|---|---|
Math.E | 歐拉常數,也是天然對數的底數 | 約2.718 |
Math.LN2 | 2的天然對數 | 約0.693 |
Math.LN10 | 10的天然對數 | 約2.303 |
Math.LOG2E | 以2爲底E的對數 | 約1.443 |
Math.LOG10E | 以10爲底E的對數 | 約0.434 |
Math.PI | 圓周率 | 約3.14 |
Math.SQRT1_2 | 1/2的平方根 | 約0.707 |
Math.SQRT2 | 2的平方根 | 約1.414 |
Math對象本就有不少用於運算的方法, 值得關注的是, ES6 規範又對Math對象作了一些擴展, 增長了一系列便捷的方法. 而這些方法大體能夠分爲如下三類.github
方法名 | 描述 |
---|---|
Math.sin(x) | 返回x的正弦值 |
Math.sinh(x) ES6新增 | 返回x的雙曲正弦值 |
Math.cos(x) | 返回x的餘弦值 |
Math.cosh(x) ES6新增 | 返回x的雙曲餘弦值 |
Math.tan(x) | 返回x的正切值 |
Math.tanh(x) ES6新增 | 返回x的雙曲正切值 |
Math.asin(x) | 返回x的反正弦值 |
Math.asinh(x) ES6新增 | 返回x的反雙曲正弦值 |
Math.acos(x) | 返回x的反餘弦值 |
Math.atan(x) | 返回x的反正切值 |
Math.atan2(x, y) | 返回 y/x 的反正切值 |
Math.atanh(x) ES6新增 | 返回 x 的反雙曲正切值 |
方法名 | 描述 | 例子 |
---|---|---|
Math.sqrt(x) | 返回x的平方根 | Math.sqrt(9);//3 |
Math.exp(x) | 返回歐拉常數(e)的x次冪 | Math.exp(1);//約2.718 |
Math.pow(x,y) | 返回x的y次冪, 若是y未初始化, 則返回x | Math.pow(2, 3);//8 |
Math.expm1(x) ES6新增 | 返回歐拉常數(e)的x次冪減去1的值 | Math.exp(1);//約1.718 |
Math.log(x) | 返回x的天然對數 | Math.log(1);//0 |
Math.log1p(x) ES6新增 | 返回x+1後的天然對數 | Math.log1p(0);//0 |
Math.log2(x) ES6新增 | 返回x以2爲底的對數 | Math.log2(8);//3 |
Math.log10(x) ES6新增 | 返回x以10爲底的對數 | Math.log10(100);//2 |
Math.cbrt(x) ES6新增 | 返回x的立方根 | Math.cbrt(8);//約2 |
Math.clz32() ES6新增 | 返回一個數字在轉換成 32位無符號整型數字的二進制形式後, 開頭的 0 的個數 | Math.clz32(2);//30 |
Math.hypot(x,y,z) ES6新增 | 返回全部參數的平方和的平方根 | Math.hypot(3,4);//5 |
Math.imul(x,y) ES6新增 | 返回兩個參數的類C的32位整數乘法運算的運算結果 | Math.imul(0xffffffff, 5);//-5 |
方法名 | 描述 | 例子 |
---|---|---|
Math.abs(x) | 返回x的絕對值 | Math.abs(-5);//5 |
Math.floor(x) | 返回小於x的最大整數 | Math.floor(8.2);//8 |
Math.ceil(x) | 返回大於x的最小整數 | Math.ceil(8.2);//9 |
Math.trunc(x) ES6新增 | 返回x的整數部分 | Math.trunc(1.23);//1 |
Math.fround(x) ES6新增 | 返回離它最近的單精度浮點數形式的數字 | Math.fround(1.1);//1.100000023841858 |
Math.min(x,y,z) | 返回多個數中的最小值 | Math.min(3,1,5);//1 |
Math.max(x,y,z) | 返回多個數中的最大值 | Math.max(3,1,5);//5 |
Math.round(x) | 返回四捨五入後的整數 | Math.round(8.2);//8 |
Math.random() | 返回0到1之間的僞隨機數 | Math.random(); |
Math.sign(x) ES6新增 | 返回一個數的符號( 5種返回值, 分別是 1, -1, 0, -0, NaN. 表明的各是正數, 負數, 正零, 負零, NaN) | Math.sign(-5);//-1 |
Number.prototype中有一個方法叫作toFixed(), 用於將數值裝換爲指定小數位數的形式. 編程
var num = 1234.56789;
console.log(num.toFixed(),num.toFixed(0));//1235,1235
console.log(num.toFixed(1));//1234.6
console.log(-1.235.toFixed(2));//-1.24複製代碼
以上, 數值運算中, 存在以下規律:api
Math.max.apply(null,[5,3,8,9]); // 9
. 可是Math.min 不傳參數返回 Infinity
, Math.max 不傳參數返回 -Infinity
.除去上述方法, Math做爲對象, 繼承了來之Object對象的方法. 其中一些以下:數組
Math.valueOf();//返回Math對象自己
+Math; //NaN, 試圖轉換成數字,因爲不能轉換爲數字,返回NaN
Math.toString();//"[object Math]"複製代碼
Math對象提供的方法種類繁多, 且覆蓋面很是全面, 基本上可以知足平常開發所需. 但同時咱們也都知道, 使用Math對象的方法進行數值運算時, js代碼通過解釋編譯, 最終會以二進制的方式進行運算. 這種運算方式效率較低, 那麼能不能進一步提升運算的效率的呢? 若是咱們使用位運算就可. 這是由於位運算本就是直接進行二進制運算.app
因爲位運算是基於二進制的, 所以咱們須要先獲取數值的二進制值. 實際上, toString 方法已經幫咱們作好了一部分工做, 以下:dom
//正整數可經過toString獲取
12..toString(2);//1100
//負整數問題就來了
(-12).toString(2);//-1100複製代碼
已知: 負數在計算機內部是採用補碼錶示的. 例如 -1, 1的原碼是 0000 0001, 那麼1的反碼是 1111 1110, 補碼是 1111 1111.
故: 負數的十進制轉換爲二進制時,符號位不變,其它位取反後+1. 即: -x的二進制 = x的二進制取反+1
. 由按位取反可藉助^運算符, 故負整數的二進制能夠藉助下面這個函數來獲取:
function getBinary(num){
var s = (-num).toString(2),
array = [].map.call(s,function(v){
return v^1;
});
array.reduceRight(function(previousValue, value, index, array){
var v = previousValue ^ value;
array[index] = v;
return +!v;
},1);
return array.join('');
}
getBinary(-12);//0100, 前面未補全的部分所有爲1複製代碼
而後, 多試幾回就會發現:
getBinary(-1) == 1..toString(2); //true
getBinary(-2) == 2..toString(2); //true
getBinary(-4) == 4..toString(2); //true
getBinary(-8) == 8..toString(2); //true複製代碼
這代表:
一樣, 負數的二進制轉十進制時, 符號位不變, 其餘位取反後+1. 可參考:
function translateBinary2Decimal(binaryString){
var array = [].map.call(binaryString,function(v){
return v^1;
});
array.reduceRight(function(previousValue, value, index, array){
var v = previousValue ^ value;
array[index] = v;
return +!v;
},1);
return parseInt(array.join(''),2);
}
translateBinary2Decimal(getBinary(-12));//12複製代碼
由上, 二進制轉十進制和十進制轉二進制的函數, 大部分均可以共用, 所以下面提供一個統一的函數解決它們的互轉問題:
function translateBinary(item){
var s = null,
array = null,
type = typeof item,
symbol = !/^-/.test(item+'');
switch(type){
case "number":
s = Math.abs(item).toString(2);
if(symbol){
return s;
}
break;
case "string":
if(symbol){
return parseInt(item,2);
}
s = item.substring(1);
break;
default:
return false;
}
//按位取反
array = [].map.call(s,function(v){
return v^1;
});
//+1
array.reduceRight(function(previousValue, value, index, array){
var v = (previousValue + value)==2;
array[index] = previousValue ^ value;
return +v;
},1);
s = array.join('');
return type=="number"?'-'+s:-parseInt(s,2);
}
translateBinary(-12);//"-0100"
translateBinary('-0100');//-12複製代碼
二進制數 | 二進制值 |
---|---|
0xAAAAAAAA | 10101010101010101010101010101010 |
0x55555555 | 01010101010101010101010101010101 |
0xCCCCCCCC | 11001100110011001100110011001100 |
0x33333333 | 00110011001100110011001100110011 |
0xF0F0F0F0 | 11110000111100001111000011110000 |
0x0F0F0F0F | 00001111000011110000111100001111 |
0xFF00FF00 | 11111111000000001111111100000000 |
0x00FF00FF | 00000000111111110000000011111111 |
0xFFFF0000 | 11111111111111110000000000000000 |
0x0000FFFF | 00000000000000001111111111111111 |
如今也可使用上述方法來驗證下經常使用的二進制值對不對. 以下:
translateBinary(0xAAAAAAAA);//"10101010101010101010101010101010"複製代碼
&運算符用於鏈接兩個數, 鏈接的兩個數它們二進制補碼形式的值每位都將參與運算, 只有相對應的位上都爲1時, 該位的運算才返回1. 好比 3 和 9 進行按位與運算, 如下是運算過程:
0011 //3的二進制補碼形式
& 1001 //9的二進制補碼形式
--------------------
0001 //1,相同位數依次運算,除最後一位都是1,返回1之外, 其它位數因爲不一樣時爲1都返回0複製代碼
由上, 3&9的運算結果爲1. 實際上, 因爲按位與(&)運算同位上返回1的要求較爲嚴苛, 所以, 它是一種趨向減少最大值的運算.(不管最大值是正數仍是負數, 參與按位與運算後, 該數老是趨向減小二進制值位上1的數量, 所以老是有值減少的趨勢. ) 對於按位與(&)運算, 知足以下規律:
由公式1, 咱們能夠對非整數取整. 即 x&x === x&-1 === Math.trunc(x)
以下:
console.log(5.2&5.2);//5
console.log(-5.2&-1);//-5
console.log(Math.trunc(-5.2)===(-5.2&-1));//true複製代碼
由公式4, 咱們能夠由此判斷數值是否爲奇數. 以下:
if(1 & x){//若是x爲奇數,它的二進制補碼形式最後一位必然是1,同1進行按位與運算後,將返回1,而1又會隱式轉換爲true
console.log("x爲奇數");
}複製代碼
|不一樣於&, |運算符鏈接的兩個數, 只要其二進制補碼形式的各位上有一個爲1, 該位的運算就返回1, 不然返回0. 好比 3 和 12 進行按位或運算, 如下是運算過程:
0011 //3的二進制補碼形式
| 1100 //12的二進制補碼形式
--------------------
1111 //15, 相同位數依次運算,遇1返回1,故最終結果爲4個1.複製代碼
由上, 3|12的運算結果爲15. 實際上, 因爲按位與(&)運算同位上返回0的要求較爲嚴苛, 所以, 它是一種趨向增大最小值的運算. 對於按位或(|)運算, 知足以下規律:
稍微利用公式1, 咱們即可以將非整數取整. 即 x|0 === Math.trunc(x)
以下:
console.log(5.2|0);//5
console.log(-5.2|0);//-5
console.log(Math.trunc(-5.2)===(-5.2|0));//true複製代碼
爲何 5.2|0 運算後會返回5呢? 這是由於浮點數並不支持位運算, 運算前, 5.2會轉換爲整數5再和0進行位運算, 故, 最終返回5.
~運算符, 返回數值二進制補碼形式的反碼. 什麼意思呢, 就是說一個數值二進制補碼形式中的每一位都將取反, 若是該位爲1, 取反爲0, 若是該位爲0, 取反爲1. 咱們來舉個例子理解下:
~ 0000 0000 0000 0000 0000 0000 0000 0011 //3的32位二進制補碼形式
--------------------------------------------
1111 1111 1111 1111 1111 1111 1111 1100 //按位取反後爲負數(最高位(第一位)表示正負,1表明負,0表明正)
--------------------------------------------
1000 0000 0000 0000 0000 0000 0000 0011 //負數的二進制轉換爲十進制時,符號位不變,其它位取反(後+1)
1000 0000 0000 0000 0000 0000 0000 0100 // +1
--------------------------------------------
-4 //最終運算結果爲-4複製代碼
實際上, 按位非(~)操做不須要這麼興師動衆地去計算, 它有且僅有一條運算規律:
~x === -x-1
.~5 ==> -5-1 === -6;
~-2016 ==> 2016-1 === 2015;複製代碼
由上述公式可推出: ~~x === -(-x-1)-1 === x
. 因爲位運算擯除小數部分的特性, 連續兩次按位非也可用於將非整數取整. 即, ~~x === Math.trunc(x)
以下:
console.log(~~5.2);//5
console.log(~~-5.2);//-5
console.log(Math.trunc(-5.2)===(~~-5.2));//true複製代碼
按位非(~)運算符只能用來求數值的反碼, 而且還不能輸出反碼的二進制字符串. 咱們來稍微擴展下, 使它變得更易用.
function waveExtend(item){
var s = typeof item == 'number' && translateBinary(~item);
return typeof s == 'string'?s:[].map.call(item,function(v){
return v==='-'?v:v^1;
}).join('').replace(/^-?/,function(m){return m==''?'-':''});
}
waveExtend(-8);//111 -8反碼,正數省略的位所有爲0
waveExtend(12);//-0011 12的反碼,負數省略的位所有爲1複製代碼
實際上, 按位非(~)運算符要求其運算數爲整型, 若是運算數不是整型, 它將和其餘位運算符同樣嘗試將其轉換爲32位整型, 若是沒法轉換, 就返回NaN. 那麼~NaN等於多少呢?
console.log(~function(){alert(20);}());//先alert(20),而後輸出-1複製代碼
以上語句意在打印一個自執行函數的按位非運算結果. 而該自執行函數又沒有顯式指定返回值, 默認將返回undefined. 所以它其實是在輸出~undefined的值. 而undefined值不能轉換成整型, 經過測試, 運算結果爲-1(即~NaN === -1). 咱們不妨來看看下來測試, 以便加深理解.
console.log(~'abc');//-1
console.log(~[]);//-1
console.log(~{});//-1
console.log(~function(){});//-1
console.log(~/\d/);//-1
console.log(~Infinity);//-1
console.log(~null);//-1
console.log(~undefined);//-1
console.log(~NaN);//-1複製代碼
^運算符鏈接的兩個數, 它們二進制補碼形式的值每位參與運算, 只有相對應的每位值不一樣, 才返回1, 不然返回0.
(相同則消去, 有些相似兩兩消失的消消樂). 以下:
0011 //3的二進制補碼形式
^ 1000 //8的二進制補碼形式
--------------------
1011 //11, 相同位數依次運算, 值不一樣的返回1複製代碼
對於按位異或(^)操做, 知足以下規律:
8^8=0
, 公式爲 a^a=0
.0^-98=-98
, 公式爲 0^a=a
.x-1
, 若它爲偶數, 則返回 x+1
. 如: 1^-9=-10
, 1^100=101
. 公式爲 1^奇=奇-1
, 1^偶=偶+1
; 推而廣之, 任意整數x與2的n次方進行按位異或運算, 若它的二進制補碼形式的倒數第n+1位是1, 則返回 x-2的n次方
, 反之若爲0, 則返回 x+2的n次方
.-x-1
, 至關於~x運算 . 如: -1^100=-101
, -1^-9=8
. 公式爲 -1^x=-x-1=~x
.3^8^8=3
, 公式爲 a^b^b=a
或 a^b^a=b
.3^9=10
, 3^10=9
, 9^10=3
; 公式爲 a^b=c
, a^c=b
, b^c=a
.以上公式中, 1, 2, 3和4都是由按位異或運算特性推出的, 公式5可由公式1和2推出, 公式6可由公式5推出.
因爲按位異或運算的這種可交換的性質, 咱們可用它輔助交換兩個整數的值. 以下, 假設這兩個值爲a和b:
var a=1,b=2;
//常規方法
var tmp = a;
a=b;
b=tmp;
console.log(a,b);//2 1
//使用按位異或~的方法
a=a^b; //假設a,b的原始值分別爲a0,b0
b=a^b; //等價於 b=a0^b0^b0 ==> b=a0
a=a^b; //等價於 a=a0^b0^a0 ==> a=b0
console.log(a,b);//2 1
//以上可簡寫爲
a^=b;b^=a;a^=b;複製代碼
由上能夠看出:
a操做符b === b操做符a
.<<運算符, 表示將數值的32位二進制補碼形式的除符號位以外的其餘位都往左移動若干位數. 當x爲整數時, 有: x<<n === x*Math.pow(2,n)
以下:
console.log(1<<3);//8
console.log(100<<4);//1600複製代碼
如此, Math.pow(2,n) 即可簡寫爲 1<<n.
對於表達式 x<<n
, 當運算數x沒法被轉換爲整數時,運算結果爲0.
console.log({}<<3);//0
console.log(NaN<<2);//0複製代碼
當運算數n沒法被轉換爲整數時,運算結果爲x. 至關於 x<<0
.
console.log(2<<NaN);//2複製代碼
當運算數x和n均沒法被轉換爲整數時,運算結果爲0.
console.log(NaN<<NaN);//0複製代碼
>>運算符, 除了方向向右, 其餘同<<運算符. 當x爲整數時, 有: x>>n === Math.floor(x*Math.pow(2,-n))
. 以下:
console.log(-5>>2);//-2
console.log(-7>>3);//-1複製代碼
右移負整數時, 返回值最大爲-1.
右移正整數時, 返回值最小爲0.
其餘規律請參考 有符號左移時運算符之一爲NaN的場景.
>>>運算符, 表示連同符號也一塊兒右移.
注意:無符號右移(>>>)會把負數的二進制碼當成正數的二進制碼. 以下:
console.log(-8>>>5);//134217727
console.log(-1>>>0);//4294967295複製代碼
以上, 雖然-1沒有發生向右位移, 可是-1的二進制碼, 已經變成了正數的二進制碼. 咱們來回顧下這個過程.
translateAry(-1);//-1,補全-1的二進制碼至32位: 11111111111111111111111111111111
translateAry('11111111111111111111111111111111');//4294967295複製代碼
可見, -1的二進制原碼本就是32個1, 將這32個1當正數的二進制處理, 直接還原成十進制, 恰好就是 4294967295.
由此, 使用 >>>運算符, 即便是右移0位, 對於負數而言也是翻天覆地的變化. 可是對於正數卻沒有改變. 利用這個特性, 能夠判斷數值的正負. 以下:
function getSymbol(num){
return num === (num>>>0)?"正數":"負數";
}
console.log(getSymbol(-100), getSymbol(123));//負數 正數複製代碼
其餘規律請參考 有符號左移時運算符之一爲NaN的場景.
使用運算符, 若是不知道它們的運算優先級. 就像駕駛法拉利卻分不清楚油門和剎車同樣恐怖. 所以我爲您準備了經常使用運算符的運算優先級表. 請對號入座.
優先級 | 運算符 | 描述 |
---|---|---|
1 | 後置++ , 後置-- , [] , () 或 . | 後置++,後置--,數組下標,括號 或 屬性選擇 |
2 | - , 前置++ , 前置-- , ! 或 ~ | 負號,前置++,前置--, 邏輯非 或 按位非 |
3 | * , / 或 % | 乘 , 除 或 取模 |
4 | + 或 - | 加 或 減 |
5 | << 或 >> | 左移 或 右移 |
6 | > , >= , < 或 <= | 大於, 大於等於, 小於 或 小於等於 |
7 | == 或 != | 等於 或 不等於 |
8 | & | 按位與 |
9 | ^ | 按位異或 |
10 | 或 | 按位或 |
11 | && | 邏輯與 |
12 | 邏輯或 | 邏輯或 |
13 | ?: | 條件運算符 |
14 | =,/=,*=,%=,+=,-=,<<=,>>=,&=,^=,按位或後賦值 | 各類運算後賦值 |
15 | , | 逗號 |
能夠看到, ① 除了按位非(~)之外, 其餘的位運算符的優先級都是低於+-運算符的; ② 按位與(&), 按位異或(^) 或 按位或(|) 的運算優先級均低於比較運算符(>,<,=等); ③位運算符中按位或(|)優先級最低.
使用有符號右移(>>)運算符, 以及按位異或(^)運算符, 咱們能夠實現一個 Math.abs方法. 以下:
function abs(num){
var x = num>>31, //保留32二進制中的符號位,根據num的正負性分別返回0或-1
y = num^x; //返回正數,且利用按位異或中的公式2,若num爲正數,num^0則返回num自己;若num爲負數,則至關於num^-1,利用公式4, 此時返回-num-1
return y-x; //若num爲正數,則返回num-0即num;若num爲負數則返回-num-1-(-1)即|num|
}複製代碼
一般, 比較兩個數是否符號相同, 咱們使用x*y>0 來判斷便可. 但若是利用按位異或(^), 運算速度將更快.
console.log(-17 ^ 9 > 0);//false複製代碼
好比 123%8, 實際上就是求一個餘數, 而且這個餘數還不大於8, 最大爲7. 而後剩下的就是比較二進制值裏, 123與7有幾成類似了. 便不難推出公式: x%(1<<n)==x&(1<<n)-1
.
console.log(123%8);//3
console.log(123&(1<<3)-1);//3 , 爲何-1時不用括號括起來, 這是由於-優先級高於&複製代碼
不妨先判斷n的奇偶性, 爲奇數時計數器增長1, 而後將n右移一位, 重複上面步驟, 直到遞歸退出.
function getTotalForOne(n){
return n?(n&1)+arguments.callee(n>>1):0;
}
getTotalForOne(9);//2複製代碼
加法運算, 從二進制值的角度看, 有 ①同位相加 和 ②遇2進1 兩種運算(實際上, 十進制運算也是同樣, 同位相加, 遇10進1).
首先咱們看看第①種, 同位相加, 不考慮②遇2進1.
1 + 1 = 0
1 + 0 = 1
0 + 1 = 1
0 + 0 = 0複製代碼
以上運算過程有沒有很熟悉. 是否是和按位異或(^)運算有着驚人的類似. 如:
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0複製代碼
所以①同位相加的運算, 徹底可由按位異或(^)代替, 即: x^y.
那麼②遇2進1 應該怎麼實現呢? 實際上, 非位移位運算中, 只有按位與(&)才能知足遇2的場景, 且只有有符號左移(<<)能知足進1的場景.
如今範圍縮小了, 就看&和<<運算符能不能真正知足須要了. 值得高興的是, 按位與(&)只有在同位都是1的狀況下才返回1, 其餘狀況均返回0. 若是對其運算結果再作左移一位的運算, 即: (x&y)<<1. 恰好知足了②遇2進1的場景.
由於咱們是將①同位相加和②遇2進1的兩種運算分開進行. 那麼最終的加法運算結果應該還要作一次加法. 以下:
最終公式: x + y = x^y + (x&y)<<1
這個公式並不完美, 由於它仍是使用了加法, 推導公式怎麼能直接使用推導結果呢? 太可怕了, 就不怕掉入遞歸深淵嗎? 下面咱們就來繞過這個坑. 而繞過這個坑有一個前提, 那就是隻要 x^y 或 (x&y)<<1中有一個值爲0就好了, 這樣便不用進行加法運算了. 講了這麼多, 不如看代碼.
function add(x, y){
var _x = x^y,
_y = (x&y)<<1;
return !_x && _y || !_y && _x || arguments.callee(_x,_y);
}
add(12345678,87654321);//999999999
add(9527,-12);//9515複製代碼
最後補充一點: 位運算通常只適用 [-2^31, 2^31-1] (即 -2147483648~2147483647) 之內的正負數. 超過這個範圍, 計算將可能出現錯誤. 以下:
console.log(1<<31);//-2147483648複製代碼
因爲數值(2^31)超過了31位(加上保留的一個符號位,共32位), 故計算出錯, 因而按照負數的方式解釋二進制的值了.說好的不改變符號呢!!!
本文囉嗦幾千字, 就爲了說清楚兩個事兒. ① Math對象中, 比較經常使用的就是數值運算方法, 不妨多看看, 其餘的知道有這個api就好了. ② 位運算中, 則須要基本瞭解每種位運算符的運算方式, 若是能注意運算中 0和1等特殊數值 的一些妙用就更好了. 不管如何, 本文不可能面面俱到. 若是您對負數的位運算不甚理解, 建議去補下計算機的補碼. 但願能對您有所幫助.
相反數
: 只有符號不一樣的兩個數, 咱們就說其中一個是另外一個的相反數.補碼
: 在計算機系統中, 數值一概用補碼來表示和存儲, 且正數的原碼和補碼相同, 負數的補碼等於其原碼按位取反再加1.本問就討論這麼多內容, 若是您有什麼問題或好的想法歡迎在下方參與留言和評論.
本文做者: louis
本文連接: louiszhai.github.io/2016/07/01/…
參考文章