JavaScript測驗及解答七條幹貨

安全劍客發表於2019-11-30
我相信學習新事物並評估我們所知的東西對自己的進步非常有用,可以避免了我們覺得自己的知識過時的情況。在本文中,我將介紹一些常見的 JavaScript 知識。請享用!

我相信學習新事物並評估我們所知的東西對自己的進步非常有用,可以避免了我們覺得自己的知識過時的情況。在本文中,我將介紹一些常見的 JavaScript 知識。請享用!

JavaScript測驗及解答七條幹貨JavaScript測驗及解答七條幹貨

1.宣告

檢視以下程式碼,並回答輸出的內容(以及原因)。

// situation 1 
console.log(person); 
var person = 'John'; 
 
// situation 2 
console.log(person); 
let person = 'Phill'; 
 
// situation 3 
console.log(person); 
const person = 'Frank'; 
 
// situation 4 
const person = 'Vanessa'; 
console.log(person); 
person = 'Mike'; 
console.log(person); 
 
// situation 5 
var person = 'John'; 
let person = 'Mike'; 
console.log(person); 
 
// situation 6 
var person = 'John'; 
if (person) { 
  let person = 'Mike'; 
  console.log(person); 
} 
console.log(person);

說明
Situation 1: 預期結果是在控制檯中看到文字 John,但是令人驚訝的是,我們看到記錄了undefined。想知道為什麼嗎?
好吧,這是經典的 JavaScript 在起作用。這種行為被稱為提升。在後臺,該語言將變數宣告和值分配分為兩部分。不管變數最初由開發人員在哪裡宣告,變數都將移動到頂部,宣告時將其值設定為 undefined。看起來像這樣:

var person; 
console.log(person); 
person = 'John';

Situation 2: 在這裡,結果將是引用錯誤。

Uncaught ReferenceError: Cannot access 'person' before initialization

錯誤文字說明了一切。因為我們使用了關鍵字 let,所以我們的變數被提升,但沒有初始化,並且丟擲該錯誤,通知我們正在嘗試訪問未初始化的變數。在 ES6 中引入了關鍵字 let,使我們能夠使用塊作用域中的變數,從而幫助我們防止意外行為。
在這裡,我們會得到與 Situation 2 中相同的錯誤。
不同之處在於我們使用了關鍵字 const,從而防止在初始化後重新分配變數。 ES6 中也引入了此關鍵字。
Situation 4: 在這種情況下,我們可以看到關鍵字 const 是如何工作的,以及它如何避免無意中重新分配變數。在我們的示例中,首先會在控制檯中看到 Vanessa,然後是一個型別錯誤。

Uncaught TypeError: Assignment to constant variable

const 變數的使用隨著我們的程式碼庫呈指數增長。
Situation 5: 如果已經在某個作用域內使用關鍵字 var 定義了變數,則在同一作用域中用關鍵字 let 再次宣告該變數將會引發錯誤。
因此,在我們的示例中,將不會輸出任何內容,並且會看到語法錯誤提示。

Uncaught SyntaxError: Identifier 'person' has already been declared

Situation 6: 我們分別有一個函式作用域的變數,和塊作用域的變數。在這種情況下,它們是否有相同的名字或識別符號並不重要。
在控制檯中,我們應該看到 Mike 和 John 被依次輸出。為什麼?
因為關鍵字 let 為我們提供了塊作用域內的變數,這意味著它們僅存在於自己建立的作用域內,在這種情況下,位於if...else 語句中。內部變數優先於外部變數,這就是為什麼我們可以使用相同識別符號的原因。

2.繼承

考慮以下類,並嘗試回答輸出了什麼以及為什麼。

class Person { 
  constructor() { 
    this.sayHello = () => { 
      return 'Hello'; 
    } 
  } 
 
  sayBye() { 
    return 'Bye'; 
  } 
} 
 
class Student extends Person { 
  sayHello() { 
    return 'Hello from Student'; 
  } 
} 
 
const student = new Student(); 
console.log(student.sayHello());

說明
如果你的答案是 Hello,那是對的!
為什麼:每次我們建立一個新的 Student 例項時,都會將 sayHello 屬性設定為是一個函式,並返回字串 Hello。這是在父類(Person)類的建構函式中發生的。
在 JavaScript 中,類是語法糖,在我們的例子中,在原型鏈上定義了 Student 類中的 sayHello 方法。考慮到每次我們建立 Student 類的例項時,都會將 sayHello 屬性設定為該例項,使其成為返回字串 Hello 的 function,因此我們永遠不會使用原型鏈上定義的函式,也就永遠不會看到訊息 Hello from Student 。

3.物件可變性

思考以下情況中每個部分的輸出:

// situation 1 
const user = { 
  name: 'John', 
  surname: 'Doe' 
} 
 
user = { 
  name: 'Mike' 
} 
 
console.log(user); 
 
// situation 2 
const user = { 
  name: 'John', 
  surname: 'Doe' 
} 
 
user.name = 'Mike'; 
console.log(user.name); 
 
// situation 3 
const user = { 
  name: 'John', 
  surname: 'Doe' 
} 
 
const anotherUser = user; 
anotherUser.name = 'Mike'; 
console.log(user.name); 
 
// situation 4 
const user = { 
  name: 'John', 
  surname: 'Doe', 
  address: { 
    street: 'My Street' 
  } 
} 
 
Object.freeze(user); 
 
user.name = 'Mike'; 
user.address.street = 'My Different Street'; 
console.log(user.name); 
console.log(user.address.street);

說明
Situation 1: 正如我們在上一節中所瞭解的,我們試圖重新分配不允許使用的 const 變數,所以將會得到型別錯誤。
控制檯中的結果將顯示以下文字:

Uncaught TypeError: Assignment to constant variable

Situation 2: 在這種情況下,即使我們改用關鍵字 const 宣告的變數,也會有不同的行為。不同之處在於我們正在修改物件屬性而不是其引用,這在 const 物件變數中是允許的。
控制檯中的結果應為單詞 Mike。
Situation 3: 透過將 user 分配給 anotherUser 變數,可以在它們之間共享引用或儲存位置(如果你願意)。換句話說,它們兩個都會指向記憶體中的同一個物件,因所以更改一個物件的屬性將反映另一個物件的更改。
控制檯中的結果應為 Mike。
Situation 4: 在這裡,我們使用 Object.freeze 方法來提供先前場景(Situation 3)所缺乏的功能。透過這個方法,我們可以“凍結”物件,從而不允許修改它的屬性值。但是有一個問題!它只會進行淺凍結,這意味著它不會保護深層屬性的更新。這就是為什麼我們能夠對 street 屬性進行更改,而 name 屬性保持不變的原因。
控制檯中的輸出依次為 John 和 My Different Street 。

4.箭頭函式

執行以下程式碼段後,將會輸出什麼以及原因:

const student = { 
  school: 'My School', 
  fullName: 'John Doe', 
  printName: () => { 
    console.log(this.fullName); 
  }, 
  printSchool: function () { 
    console.log(this.school); 
  } 
}; 
 
student.printName(); 
student.printSchool();

說明
控制檯中的輸出將依次為 undefined 和 My School。
你可能會熟悉以下語法:

var me = this; 
// or 
var self = this; 
 
// ... 
// ... 
// somewhere deep... 
// me.doSomething();

你可以把 me 或 self 變數視為父作用域,該作用域可用於在其中建立的每個巢狀函式。
當使用箭頭函式時,這會自動完成,我們不再需要儲存 this 引用來訪問程式碼中更深的地方。箭頭函式不繫結自己,而是從父作用域繼承一個箭頭函式,這就是為什麼在呼叫 printName 函式後輸出了 undefined 的原因。

5.解構

請檢視下面的銷燬資訊,並回答將要輸出的內容。給定的語法是否允許,否則會引發錯誤?

const rawUser = { 
   name: 'John', 
   surname: 'Doe', 
   email: 'john@doe.com', 
   displayName: 'SuperCoolJohn', 
   joined: '2016-05-05', 
   image: 'path-to-the-image', 
   followers: 45 
} 
 
let user = {}, userDetails = {}; 
({ name: user.name, surname: user.surname, ...userDetails } = rawUser); 
 
console.log(user); 
console.log(userDetails);

說明
儘管有點開箱即用,但是上面的語法是允許的,並且不會引發錯誤! 很整潔吧?
上面的語法功能強大,使我們能夠輕鬆地將任何物件分成兩個更具體的物件,上面的示例在控制檯的輸出為:

// {name: "John", surname: "Doe"} 
// {email: "john@doe.com", displayName: "SuperCoolJohn", joined: "2016-05-05", image: "path-to-the-image", followers: 45}
6.非同步/等待

呼叫以下函式後將輸出什麼?

(async () => { 
  let result = 'Some Data'; 
 
  let promise = new Promise((resolve, reject) => { 
    setTimeout(() => resolve('Some data retrieved from the server'), 2000); 
  }); 
 
  result = await promise; 
  console.log(result); 
})();

說明
如果你認為是兩秒鐘後輸出 Some data retrieved from the server ,那麼你是對的!
程式碼將會暫停,直到 promise 得到解決。兩秒鐘後,它將繼續執行並輸出給定的文字。這意味著 JavaScript 引擎實際上會等到非同步操作完成。可以說 async/await 是用來獲得 promise 結果的語法糖。也有人認為它是比 promise.then 更具可讀性的方式。

7. Return 語句
const multiplyByTwo = (x) => { 
    return 
    { 
        result: x * 2 
    }; 
} 
console.log(multiplyByTwo(2));

說明
如果你的答案是 {result: 4},那你就錯了。輸出是 undefined。但是不要對自己太苛刻,考慮到我也寫 C# 程式碼,這也曾經困擾著我,這在 C# 那兒不是個問題。
由於自動分號插入的原因,上面的程式碼將返回 undefined。 return 關鍵字和表示式之間不允許使用行結束符
解決方案是用以下列方式之一去修復這個函式:

const multiplyByTwo = (x) => { 
    return { 
        result: x * 2 
    }; 
} 
要麼
const multiplyByTwo = (x) => { 
  return ( 
    { 
      result: x * 2 
    } 
  ); 
}

原文地址:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2666321/,如需轉載,請註明出處,否則將追究法律責任。

相關文章