1. 程式人生 > >44個javascript變態題解析上

44個javascript變態題解析上

宣告:參考https://segmentfault.com/a/1190000005681454

新加了一些基礎知識。加強對基礎知識的鞏固。

數值轉換:(非數值轉為數值)

Number() 可以用於任何資料型別。null->0  undefined->NaN物件:valueof() ,如果轉換結果為NaN,呼叫物件的tostring()轉為字串,再按字串的轉換規則返回值。    字串:(1)只包含數字,直接轉為十進位制數值(2)包含浮點格式,轉為對應的浮點數(3)包含十六進位制的,轉為大小相同的十進位制(4)字串為空,轉為05)字串包含上述格式以外的字元,轉為NaN

ParseInt() 字串轉為數值parseInt

()只接受兩個兩個引數string, radix(基數,即多少進位制).按照radix進位制來轉換stringparseInt(string,radix)的引數radix必須介於2~36之間,而且字串string中的數字不能大於radix才能正確返回數字結果值。當引數radix 的值為0,或沒有設定該引數時,parseInt()會根據string 來判斷數字的基數。如果 string 以"0x"開頭,parseInt()會把string 的其餘部分解析為十六進位制的整數。如果 string 以 0 開頭,那麼ECMAScript v3允許parseInt()的一個實現把其後的字元解析為八進位制或十六進位制的數字。
如果string 以1 ~ 9 的數字開頭,parseInt()將把它解析為十進位制的整數。

在沒有指定基數,或者基數為 0 的情況下,JavaScript作如下處理:

•如果字串 string "0x"或者"0X"開頭,則基數是16 (16進位制).

•如果字串 string "0"開頭,基數是8(八進位制)或者10(十進位制),那麼具體是哪個基數由實現環景決定。ECMAScript 5 規定使用10,但是並不是所有的瀏覽器都遵循這個規定。因此,永遠都要明確給出radix引數的值。

•如果字串 string 以其它任何值開頭,則基數是10 (十進位制)

ParseFloat()字串轉為數值.。與

ParseInt()類似,但第一個小數點有效,只解析十進位制數值,16進位制解析後被轉換為0.

陣列的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種基本型別分別為:undefinednullbooleannumberstring

除了基本型別,還有引用型別。

什麼是基本型別

如:undefinednull123'hello'"hi",可以理解為:基本型別,就是簡簡單單一個數值。

什麼是引用型別?(引用型別,也就物件型別)

如:var o=newObject();

Var d=new Date; //jsnew物件的時候,括號是可以省略的

//以上的od,就是引用型別,不再是一個簡單的數值。

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()迭代陣列所有項,構建一個最終返回值。ReducereduceRight()都接受兩個引數,一個回撥,一個初始值.回撥函式接受四個引數  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 這個筆者實踐了一下 發現 firefoxwindow, 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.合法啊!