你真的知道JS嗎

microzz發表於2017-04-30

你真的知道JavaScript嗎

    JavaScript是一門奇怪的語言,要真正掌握並不容易。廢話不多說,來一個快速測試,5道題目,看看你對JavaScript是否真正掌握。準備好了嗎?開始咯?

題目

No.1

if (!("a" in window)) {
    var a = 1;
}

console.log(a);複製程式碼

No.2

var a = 1,
    b = function a(x) {
        x && a(--x);
    };
console.log(a);複製程式碼

No.3

function a(x) {
    return x * 2;
}
var a;
console.log(a);複製程式碼

No.4

function b(x, y, a) {
    arguments[2] = 10;
    console.log(a);
}
b(1, 2, 3);複製程式碼

No.5

function a() {
    console.log(this);
}
a.call(null);複製程式碼

解析

題目來自?dmitry.baranovskiy.com/post/914032…
解析加上了自己的理解?

No.1

    在瀏覽器環境中,全域性變數都是window的一個屬性,即
var a = 1 等價於 window.a = 1in操作符用來判斷某個屬性屬於某個物件,可以是物件的直接屬性,也可以是通過prototype繼承的屬性。
    再看題目,在瀏覽器中,如果沒有全域性變數 a ,則宣告一個全域性變數 a (ES5沒有塊級作用域),並且賦值為1。很多人會認為列印的是1。非也,大家不要忘了變數宣告會被前置!什麼意思呢?題目也就等價於

var a;

if (!("a" in window)) {
    a = 1;
}

console.log(a);複製程式碼

所以其實已經宣告瞭變數a,只不過if語句之前值是undefined,所以if語句壓根不會執行。
最後答案就是 undefined

No.2

這道題有幾個需要注意的地方:

  1. 變數宣告、函式宣告會被前置,但是函式表示式並不會,準確說類似變數宣告前置,舉個例子:
console.log('b', b); // b undefined
var b = function() {}
console.log('b', b); // b function () {}複製程式碼

2.具名的函式表示式的名字只能在該函式內部取到,舉個例子(排除老的IE?):

var foo = function bar () {}

console.log('foo', foo); 
// foo function bar(){}

console.log('bar', bar);
// Uncaught ReferenceError: bar is not defined複製程式碼

    綜合這兩點,再看題目,最後輸出的內容就為 1

No.3

函式宣告會覆蓋變數宣告,但不會覆蓋變數賦值,舉個例子簡單粗暴:

function foo(){
    return 1;
}
var foo;
console.log(typeof foo);    // "function"複製程式碼

函式宣告的優先順序高於變數宣告的優先順序,但如果該變數foo賦值了,那結果就完全不一樣了:

function foo(){
    return 1;
}
var foo = 1;
console.log(typeof foo);    // "number"複製程式碼

變數foo賦值以後,變數賦值初始化就覆蓋了函式宣告。這個需要注意
再看題目

function a(x) {
    return x * 2;
}
var a;
console.log(a); // function a(x) {...}複製程式碼

No.4

這題考察 arguments 物件的用法(詳看?JavaScript中的arguments物件)
一般情況arguments與函式引數是動態繫結關係(為什麼說是一般稍後會解釋),所以很好理解,最後輸出的是10

但是但是但是,我們不要忘了一個特殊情況--嚴格模式,在嚴格模式中 arguments 與相當於函式引數的一個拷貝,並沒有動態繫結關係,舉個例子:

'use strict'
// 嚴格模式!!

function b(x, y, a) {
    arguments[2] = 10;
    console.log(a);
}
b(1, 2, 3); // 3複製程式碼

No.5

function a() {
    console.log(this);
}
a.call(null);複製程式碼

關於 a.call(null); 根據ECMAScript262規範規定:
如果第一個引數傳入的物件呼叫者是null或者undefined的話,call方法將把全域性物件(瀏覽器上是window物件)作為this的值。所以,不管你什麼時候傳入null或者 undefined,其this都是全域性物件window。所以,在瀏覽器上答案是輸出 window 物件。

但是但是但是,我們依舊不能忘記一個特殊情況--嚴格模式,在嚴格模式中,null 就是 nullundefined 就是 undefined ,舉個例子:

'use strict';
// 嚴格模式!!

function a() {
    console.log(this);
}
a.call(null); // null
a.call(undefined); // undefined複製程式碼

提醒

  1. 在瀏覽器中的全域性物件是window,Node.js中是global;
  2. 為了使程式碼更加嚴謹與健壯,建議寫JS都加上嚴格模式'use strict';
  3. ES6已經成為前端必備技能,呼籲大家都使用ES6,方便高效,可以使用babel把ES6轉成ES5甚至ES3,儘量使用ES6推動前端的發展?

About

GitHub: ?github.com/microzz
個人網站: ?microzz.com/

相關文章