44個javascript變態題解析上
宣告:參考https://segmentfault.com/a/1190000005681454
新加了一些基礎知識。加強對基礎知識的鞏固。
數值轉換:(非數值轉為數值)
Number() 可以用於任何資料型別。null->0 undefined->NaN物件:valueof() ,如果轉換結果為NaN,呼叫物件的tostring()轉為字串,再按字串的轉換規則返回值。 字串:(1)只包含數字,直接轉為十進位制數值(2)包含浮點格式,轉為對應的浮點數(3)包含十六進位制的,轉為大小相同的十進位制(4)字串為空,轉為0(5)字串包含上述格式以外的字元,轉為NaN。
ParseInt() 字串轉為數值parseInt
在沒有指定基數,或者基數為 0 的情況下,JavaScript作如下處理:
•如果字串 string 以"0x"或者"0X"開頭,則基數是16 (16進位制).
•如果字串 string 以"0"開頭,基數是8(八進位制)或者10(十進位制),那麼具體是哪個基數由實現環景決定。ECMAScript 5 規定使用10,但是並不是所有的瀏覽器都遵循這個規定。因此,永遠都要明確給出radix引數的值。
•如果字串 string 以其它任何值開頭,則基數是10 (十進位制)。
ParseFloat()字串轉為數值.。與
陣列的5種迭代方法:每個方法接受兩個引數,一個回撥函式callback,一個回撥函式的this值。其中回撥函式接受三個引數:item(陣列項的值), index(陣列項在陣列中的位置), arrary(陣列物件本身);
Every()對陣列中的每一項執行給定函式,如果該函式的每一項都返回true,則返回true
Some() 對陣列中的每一項執行給定函式,如果該函式的某一項返回true,則返回true
Filter() 對陣列中的每一項執行給定函式,返回true的項組成的陣列。
Map() 對陣列中的每一項執行給定函式,返回每項函式呼叫的結果組成的陣列
ForEach()對陣列中的每一項執行給定函式,該函式沒有返回值。
第一題:["1", "2", "3"].map(parseInt)
parseInt即為map()的回撥函式,根據回撥函式函式接收的引數和parseInt本身接收的引數,對比,本題即問
parseInt('1', 0);
parseInt('2', 1);
parseInt('3', 2);
parseInt('2', 1),parseInt('3', 2); 當引數radix 的值為0,或沒有設定該引數時,parseInt()會根據string 來判斷數字的基數。如果string 以1 ~ 9 的數字開頭,parseInt()將把它解析為十進位制的整數.而且字串string中的數字不能大於radix才能正確返回數字結果值。
所以答案是 [1, NaN, NaN]
var a=["1", "2", "3", "4","5",6,7,8,9,10,11,12,13,14,15];
a.map(parseInt);
返回結果為:[1,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,9,11,13,15,17,19]
javascript中,有5中基本型別,
5種基本型別分別為:undefined、null、boolean、number、string。
除了基本型別,還有引用型別。
什麼是基本型別?
如:undefined、null、1、2、3、'hello'、"hi",可以理解為:基本型別,就是簡簡單單一個數值。
什麼是引用型別?(引用型別,也就物件型別)
如:var o=newObject();
Var d=new Date; //js中new物件的時候,括號是可以省略的
//以上的o、d,就是引用型別,不再是一個簡單的數值。
Typeof運算子
typeof 返回一個表示型別的字串.
typeof的結果請看下錶:
type |
|
Undefined |
“undefined” |
Boolean |
"Boolean" |
Number |
"Number" |
String |
"string" |
Function |
"function" |
Object |
"Object/null" |
注: typeof運算子對於null值會返回"object"。
在引用型別值判斷型別的時候,typeof運算子會出現一個問題,無論引用的是什麼型別的物件,它都返回"object"。
ECMAScript引入了另一個Java運算子instanceof來解決這個問題。instanceof能判斷一個值具體是由什麼建構函式構造出來的。
function Person(){}
function User(){}
var u=new User;
console.log( u instanceof Person ); //false
console.log( u instanceof User ); //true
Object.constructor屬性
javascript中的所有物件都繼承自Object。
constructor是Object的一個屬性,他指向:建立物件的函式的引用(指標)。(可以理解為constructor指向物件的建構函式)
簡單示例:
Function User(){}
var u=new User;
console.log(u.constructor===User );//得到true,也就是說物件的constructor屬性指向他的建構函式。
console.log(u.constructor.name );//得到User,也就是建構函式的名稱
注:constructor屬性並非一定指向建構函式,他也是可以修改、變更的
[typeof null, null instanceof Object]
所以答案 [object, false]
Array歸併方法: redude() reduceRight()迭代陣列所有項,構建一個最終返回值。Reduce,reduceRight()都接受兩個引數,一個回撥,一個初始值.回撥函式接受四個引數 previousValue, currentValue, currentIndex, array
需要注意的是 If the array is empty and no initialValue was provided, TypeError would be thrown.
第3題:
[ [3,2,1].reduce(Math.pow), [].reduce(Math.pow) ]
答案 9 an error
Math物件
Math.ceil()向上取整 Math.min() 求陣列中最小 Math.max()求陣列中最大
Math.floor()向下取整 Math.random() 返回[0,1)之間的隨機數
Math.round()四捨五入 Math.abs(num) Math.exp(num) Math.pow(num,pow) Math.log(num) Math.sqrt(num) Math.acos(num) Math.asin(num) Math.atant2(num) Math.cos(num) Math.sin(num) Math.tant(num)
第四題:
var val = 'smtg';
console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing');
兩個知識點:
•Operators/Operator_Precedence
•Operators/Conditional_Operator
簡而言之 + 的優先順序 大於 ?
所以原題等價於 'Value is true' ? 'Somthing' : 'Nonthing' 而不是 'Value is' + (true ? 'Something' : 'Nonthing')
答案 'Something'
提升:
在 JavaScript中,function宣告 和variables會被提升。function宣告是在執行程式碼之前會讀取函式宣告。Function表示式則不會提前讀取。
變數提升是JavaScript將宣告移至作用域scope (全域性域或者當前函式作用域)頂部的行為。
第5題
var name = 'World!';
(function () {
if (typeof name === 'undefined') {
var name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
等價於
var name = 'World!';
(function () {
var name;
if (typeof name === 'undefined') {
name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
所以答案是 'Goodbye Jack'
第6題
JavaScript中的稀疏陣列與密集陣列
一般來說,JavaScript中的陣列是稀疏的,也就是說,陣列中的元素之間可以有空隙,因為一個數組其實就是一個鍵值對映.本文解釋瞭如何建立稀疏陣列和不稀疏的陣列.
譯者注:實際上,JavaScript並沒有常規的陣列,所有的陣列其實就是個物件,只不過會自動管理一些"數字"屬性和length屬性罷了.說的更直接一點,JavaScript中的陣列根本沒有索引,因為索引應該是數字,而JavaScript中陣列的索引其實是字串.arr[1]其實就是arr["1"],給arr["1000"] = 1,arr.length也會自動變為1001.這些表現的根本原因就是,JavaScript中的物件就是字串到任意值的鍵值對.注意鍵只能是字串.這和AWK類似.不信可以試試awk 'BEGIN{a[1]=1;print(a["1"])}'.也許這是因為Brendan Eich在發明JavaScript時參考了不少awk的設計的原因.不過目前,ES6中已經有了類似於Java等語言的Map型別,鍵可以是任意型別的值.請參考我翻譯的MDN文件Map
var ary = [0,1,2];
ary[10] = 10;
ary.filter(function(x) { return x === undefined;});
答案是 []
也就是說 從 3 - 9 都是沒有初始化的'坑'!,這些索引並不存在與陣列中.在array的函式呼叫的時候是會跳過這些'坑'的.
var ary = Array(3);
ary[0]=2
ary.map(function(elem) { return '1'; });
答案是:Array [ "1", <2 個空的儲存位置> ]
第7題
Switch()比較值時使用的是全等操作符===,不會發生型別轉換
function showCase(value) {
switch(value) {
case 'A':
console.log('Case A');
break;
case 'B':
console.log('Case B');
break;
case undefined:
console.log('undefined');
break;
default:
console.log('Do not know!');
}
}
showCase(new String('A'));
答案是 'Do not know!'
switch 是嚴格比較, String例項(物件)和 字串不一樣.
function showCase2(value) {
switch(value) {
case 'A':
console.log('Case A');
break;
case 'B':
console.log('Case B');
break;
case undefined:
console.log('undefined');
break;
default:
console.log('Do not know!');
}
}
showCase2(String('A'));
答案 'Case A'
使用NEW呼叫基本包裝型別的建構函式與直接呼叫同名的轉型函式(將任何資料型別轉為string/Boolean/number基本型別)是不一樣的。
String('A') 儲存的是基本型別string的字串 (p34)js高階程式設計
new String('A') 儲存的是string的例項。
第8題
Array.isArray(Array.prototype); // true
一個鮮為人知的實事: Array.prototype => [] ;
第9題
var a = [0];
if ([0]) {
console.log(a == true);
} else {
console.log("wut");
}
解析:
• Boolean([0]) === true
•[0] == true ◦true 轉換為數字 => 1
[0] 轉化為數字失敗, 轉化為字串 '0', 轉化成數字 => 0
0 !== 1
答案: false
第10題
[] ==[] 為 false [] == ![]為true;[] == {}為false
[] == [] 這個好理解.當兩個值都是物件(引用值)時,比較的是兩個引用值在記憶體中是否是同一個物件. 因為此[]非彼 [],雖然同為空陣列,確是兩個互不相關的空陣列,自然==為 false.
[] == ![] 這個要牽涉到 JavaScript中不同型別==比較的規則,具體是由相關標準定義的. ![]的值是false,此時表示式變為[] == false,參照標準,該比較變成了[] == ToNumber(false),即[] == 0.這個時候又變成了ToPrimitive([]) == 0,即'' == 0,接下來就是比較ToNumber('') == 0,也就是0 == 0,最終結果為true.在犀牛書49頁,任意陣列轉換為字串"",數字0和布林值true
所以![]會轉為布林值true再取反false
然後根據相等運算子“==”的規則,有boolean的轉為數字,有Object的轉為原始值
左右兩邊會變成“” == 0
最後如果是字串和數字比較,會把字串轉為數字0 == 0
結果就是為true
[]=={}//false [] == []//false是因為兩個物件比較時候,比較的是引用,陣列也是物件
基本型別比較時(string/number/boolean),比較的是他們的值,object/array/function比較的是他們的引用。
第11題
function sidEffecting(ary) {
ary[0] = ary[2];
}
function bar(a,b,c) {
c = 10
sidEffecting(arguments);
return a + b + c;
}
bar(1,1,1)
這是一個大坑, 尤其是涉及到ES6語法的時候
知識點:
•Functions/arguments
首先 The arguments object is an Array-like object corresponding to the arguments passed to a function.
也就是說 arguments 是一個 object , c就是arguments[2],所以對於c的修改就是對arguments[2]的修改.
所以答案是 21 .
然而當函式引數涉及到 any rest parameters, any default parameters or any destructured parameters 的時候,這個arguments就不在是一個 mapped arguments object 了.....
請看:
function sidEffecting(ary) {
ary[0] = ary[2];
}
function bar(a,b,c=3) {
c = 10
sidEffecting(arguments);
return a + b + c;
}
bar(1,1,1)
答案是 12
第12題
var a = 111111111111111110000,
b = 1111;
a + b;
答案是:111111111111111110000
第13題
var x = [].reverse;
x();
知識點:
•Array/reverse
The reverse method transposes the elements of the calling array object in place, mutating the array, and returning a reference to the array.
也就是說 最後會返回這個呼叫者(this), 可是x執行的時候是上下文是全域性.那麼最後返回的是 window .
補充:
@stellar91 這個筆者實踐了一下 發現 firefox是window, chrome報錯 VM190:2 Uncaught TypeError: Array.prototype.reverse called on null or undefined(…) 可能是實現不同,在chrome中應該是對呼叫者做了檢查.
Number.MIN_VALUE > 0
答案: true
第14題
MIN_VALUE 屬性是 JavaScript中可表示的最小的數(接近0,但不是負數)。它的近似值為5 x 10-324。
第15題
3.toString()
3..toString()
3...toString()
答案是 error, '3', error
你如果換一個寫法就更費解了
var a = 3;
a.toString()
這個答案就是 '3';
為啥呢?
因為在 js 中1.1, 1., .1都是合法的數字.那麼在解析3.toString的時候這個.到底是屬於這個數字還是函式呼叫呢?只能是數字,因為3.合法啊!