7 個常見的 JavaScript 測驗及解答

做者:Milos Protic

翻譯:瘋狂的技術宅javascript

原文:https://devinduct.com/blogpos...前端

未經容許嚴禁轉載java

介紹

我相信學習新事物並評估咱們所知的東西對本身的進步很是有用,能夠避免了咱們以爲本身的知識過期的狀況。在本文中,我將介紹一些常見的 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);

說明segmentfault

Situation 1: 預期結果是在控制檯中看到文本 John,可是使人驚訝的是,咱們看到記錄了 undefined。想知道爲何嗎?

好吧,這是經典的 JavaScript 在起做用。這種行爲被稱爲提高。在後臺,該語言將變量聲明和值分配分爲兩部分。無論變量最初由開發人員在哪裏聲明,變量都將移動到頂部,聲明時將其值設置爲 undefined。看起來像這樣:promise

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: 咱們分別有一個函數做用域的變量,和塊做用域的變量。在這種狀況下,它們是否有相同的名字或標識符並不重要。

在控制檯中,咱們應該看到 MikeJohn 被依次輸出。爲何?

由於關鍵字 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 屬性設置爲該實例,使其成爲返回字符串 Hellofunction,所以咱們永遠不會使用原型鏈上定義的函數,也就永遠不會看到消息 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 屬性保持不變的緣由。

控制檯中的輸出依次爲 JohnMy 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();

說明

控制檯中的輸出將依次爲 undefinedMy School

你可能會熟悉如下語法:

var me = this;
// or
var self = this;

// ...
// ...
// somewhere deep...
// me.doSomething();

你能夠把 meself 變量視爲父做用域,該做用域可用於在其中建立的每一個嵌套函數。

當使用箭頭函數時,這會自動完成,咱們再也不須要存儲 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# 那兒不是個問題。

因爲自動分號插入的緣由,上面的代碼將返回 undefinedreturn 關鍵字和表達式之間不容許使用行結束符

解決方案是用如下列方式之一去修復這個函數:

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

要麼

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

本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索