快速掌握JavaScript面試基礎知識(一)

譯者按: 總結了大量JavaScript基本知識點,頗有用!javascript

爲了保證可讀性,本文采用意譯而非直譯。另外,本文版權歸原做者全部,翻譯僅用於學習。java


根據StackOverflow調查, 自2014年一來,JavaScript是最流行的編程語言。固然,這也在情理之中,畢竟1/3的開發工做都須要一些JavaScript知識。所以,若是你但願在成爲一個開發者,你應該學會這門語言。git

這篇博客的主要目的是將全部面試中常見的概念總結,方便你快速去了解。
(譯者按:鑑於本文內容過長,方便閱讀,將分爲三篇博客來翻譯。)github

類型和類型轉換

在JavaScript中有7個內置類型:nullundefinedbooleannumberstringobject,和symbol(ES6)。面試

除了object之外,其它都叫作基本類型。編程

typeof 0 // number
typeof true // boolean
typeof 'Hello' // string
typeof Math // object
typeof null // object !!
typeof Symbol('Hi') // symbol (New ES6)
  • Null vs. Undefined

Undefined表示未定義。對於沒有初始化的變量、函數調用時候未提供的函數參數、缺失的對象屬性,它們的默認值就是undefined。若是一個函數沒有返回語句,那麼默認的返回值也是undefined數組

NUll表示值爲空。一個變量咱們能夠將其賦值爲null,表示當前的沒有值。瀏覽器

  • 隱式轉換

請看下面的例子:編程語言

var name = 'Joey';
if (name) {
console.log(name + " doesn't share food!") // Joey doesn’t share food!
}

if語句的條件判斷中,name從字符串轉換爲布爾型。在if的代碼塊中,在控制檯將name原本來本打印出來。你知道在什麼狀況下字符串會轉換爲真,何時爲假麼?函數

""0, nullundefinedNaNfalse 會自動轉換爲false。其它的都會轉換爲真:

Boolean(null) // false
Boolean('hello') // true
Boolean('0') // true
Boolean(' ') // true
Boolean([]) // true
Boolean(function(){}) // true

空數組、對象、函數定義都會自動轉換爲真。

  • String & Number之間的轉換

第一個你要很是當心的是+操做符。由於它同時用於數字相加和字符串拼接。

*,/,-只用於數字運算,當這些操做符和字符串一塊兒使用,那麼字符串會被強制轉換爲數字。

1 + "2" = "12"
"" + 1 + 0 = "10"
"" - 1 + 0 = -1
"-9\n" + 5 = "-9\n5"
"-9\n" - 5 = -14
"2" * "3" = 6
4 + 5 + "px" = "9px"
"$" + 4 + 5 = "$45"
"4" - 2 = 2
"4px" - 2 = NaN
null + 1 = 1
  • == vs. ===

一個普遍被接受的認知就是:==判斷值是否相等,===同時判斷值是否相等和類型是否相同。可是,這裏有些誤解。

實際上,==在驗證相等性的時候,會對類型不一樣的值作一個類型轉換。===對要判斷的值不作類型轉換。

2 == '2' // True
2 === '2' // False
undefined == null // True
undefined === null // False

類型轉換有不少取巧的地方,要注意:

let a = '0';
console.log(Boolean(a)); // True
let b = false;
console.log(Boolean(b)); // False
```

你認爲下面的相等判斷會輸出什麼值呢?
```js
console.log(a == b);

 

實際上會返回true。知道爲何嗎?
若是你將一個布爾類型的和非布爾類型的判斷,JavaScript會將布爾類型的轉換爲數字而後再比對。
執行過程以下:

'0' == false (1)
'0' == 0 (2)
0 == 0 (3)

 

因此,最終變成了0==0,固然返回true啦。

若是你想看完整的資料,請查看ES5的官方文檔

若是想看cheat sheet, 點擊這裏

一些比較容易掉坑的比較,我在這裏列出來:

false == "" // true
false == [] // true
false == {} // false
"" == 0 // true
"" == [] // true
"" == {} // false
0 == [] // true
0 == {} // false
0 == null // false

 

值 vs. 引用

對於基本類型的值,賦值是經過值拷貝的形式;好比:nullundefinedbooleannumberstring和ES6的symbol。對於複雜類型的值,經過引用拷貝的形式賦值。好比:對象、對象包括數組和函數。

var a = 2; // 'a' hold a copy of the value 2.
var b = a; // 'b' is always a copy of the value in 'a'
b++;
console.log(a); // 2
console.log(b); // 3
var c = [1,2,3];
var d = c; // 'd' is a reference to the shared value
d.push( 4 ); // Mutates the referenced value (object)
console.log(c); // [1,2,3,4]
console.log(d); // [1,2,3,4]
/* Compound values are equal by reference */
var e = [1,2,3,4];
console.log(c === d); // true
console.log(c === e); // false

若是想對複雜類型的值進行值拷貝,你須要本身去對全部子元素進行拷貝。

const copy = c.slice() // 'copy' 即便copy和c相同,可是copy指向新的值
console.log(c); // [1,2,3,4]
console.log(copy); // [1,2,3,4]
console.log(c === copy); // false

做用域(Scope)

做用域值程序的執行環境,它包含了在當前位置可訪問的變量和函數。

全局做用域是最外層的做用域,在函數外面定義的變量屬於全局做用域,能夠被任何其餘子做用域訪問。在瀏覽器中,window對象就是全局做用域。

局部做用域是在函數內部的做用域。在局部做用域定義的變量只能在該做用域以及其子做用域被訪問。

function outer() {
let a = 1;
function inner() {
let b = 2;
function innermost() {
let c = 3;
console.log(a, b, c); // 1 2 3
}
innermost();
console.log(a, b); // 1 2 — 'c' is not defined
}
inner();
console.log(a); // 1 — 'b' and 'c' are not defined
}
outer();

你能夠將做用域想象成一系列不斷變小的門。若是一個個子不高的人能夠穿過最小的門(局部最小做用域),那麼必然能夠穿過任何比它大的門(外部做用域)。

提高(Hoisting)

在編譯過程當中,將varfunction的定義移動到他們做用域最前面的行爲叫作提高。

整個函數定義會被提高。因此,你能夠在函數還未定義以前調用它,而不用擔憂找不到該函數。

console.log(toSquare(3)); // 9

function toSquare(n){
return n*n;
}

變量只會被部分提高。並且只有變量的聲明會被提高,賦值不會動。

letconst不會被提高。

{  /* Original code */
console.log(i); // undefined
var i = 10
console.log(i); // 10
}

{ /* Compilation phase */
var i;
console.log(i); // undefined
i = 10
console.log(i); // 10
}
// ES6 let & const
{
console.log(i); // ReferenceError: i is not defined
const i = 10
console.log(i); // 10
}
{
console.log(i); // ReferenceError: i is not defined
let i = 10
console.log(i); // 10
}

函數表達式和函數聲明

  • 函數表達式

一個函數表達式是在函數執行到函數表達式定義的位置纔開始建立,並被使用。它不會被提高。

var sum = function(a, b) {
return a + b;
}
  • 函數聲明

函數聲明的函數能夠在文件中任意位置調用,由於它會被提高。

function sum(a, b) {
return a + b;
}

變量:var,let和const

在ES6以前,只能使用var來聲明變量。在一個函數體中聲明的變量和函數,周圍的做用域內沒法訪問。在塊做用域iffor中聲明的變量,能夠在iffor的外部被訪問。

注意:若是沒有使用var,let或則const關鍵字聲明的變量將會綁定到全局做用域上。

function greeting() {
console.log(s) // undefined
if(true) {
var s = 'Hi';
undeclaredVar = 'I am automatically created in global scope';
}
console.log(s) // 'Hi'
}
console.log(s); // Error — ReferenceError: s is not defined
greeting();
console.log(undeclaredVar) // 'I am automatically created in global scope'

ES6的letconst都是新引入的關鍵字。它們不會被提高,並且是塊做用域。也就是說被大括號包圍起來的區域聲明的變量外部將不可訪問。

let g1 = 'global 1'
let g2 = 'global 2'
{ /* Creating a new block scope */
g1 = 'new global 1'
let g2 = 'local global 2'
console.log(g1) // 'new global 1'
console.log(g2) // 'local global 2'
console.log(g3) // ReferenceError: g3 is not defined
let g3 = 'I am not hoisted';
}
console.log(g1) // 'new global 1'
console.log(g2) // 'global 2'

一個常見的誤解是:使用const聲明的變量,其值不可更改。準確地說它不能夠被從新賦值,可是能夠更改。

const tryMe = 'initial assignment';
tryMe = 'this has been reassigned'; // TypeError: Assignment to constant variable.
// You cannot reassign but you can change it…
const array = ['Ted', 'is', 'awesome!'];
array[0] = 'Barney';
array[3] = 'Suit up!';
console.log(array); // [「Barney」, 「is」, 「awesome!」, 「Suit up!」]
const airplane = {};
airplane.wings = 2;
airplane.passengers = 200;
console.log(airplane); // {passengers: 200, wings: 2}
相關文章
相關標籤/搜索