這兩天的GitHub Trending repositories
被一個名叫 javascript-questions
的項目霸榜了,項目中記錄了一些JavaScript
題目。javascript
我大概從頭至尾看了一遍,都是一些基礎的題目,我大概花了半個小時(有些題很簡單,能夠一掃而過)把這些題作完了,雖然題目很簡單,可是每道題都對應一個知識點,若是這個知識點你沒有接觸過,那確定會作錯,若是你接觸過這些知識點,那麼這些題對你來講就很容易。html
建議你們也花半個小時來作一作,以便查漏補缺。前端
爲方便你們可以更快的作題,而不把時間浪費在翻譯上,我又花了幾個小時把它們翻譯成了中文,固然已經得到了做者受權。java
文中有些點做者解釋的不太完整,爲了更好的理解,我在文中添加了一些我的解釋。git
倉庫地址:github.com/lydiahallie…github
我在個人Instagram上發佈了每日JavaScript
選擇題,我也會在這裏發佈!面試
從基礎到高級:測試您對JavaScript
的瞭解程度,刷新您的知識,或爲您的編碼面試作好準備!💪 🚀我每週用新問題更新這個項目。數組
答案位於問題下方的摺疊部分,只需單擊它們便可展開。 祝你好運❤️瀏覽器
function sayHi() {
console.log(name);
console.log(age);
var name = "Lydia";
let age = 21;
}
sayHi();
複製代碼
Lydia
和 undefined
Lydia
和 ReferenceError
ReferenceError
和 21
undefined
和 ReferenceError
答案: D微信
在函數中,咱們首先使用var
關鍵字聲明瞭name
變量。 這意味着變量在建立階段會被提高(JavaScript
會在建立變量建立階段爲其分配內存空間),默認值爲undefined
,直到咱們實際執行到使用該變量的行。 咱們尚未爲name
變量賦值,因此它仍然保持undefined
的值。
使用let
關鍵字(和const
)聲明的變量也會存在變量提高,但與var
不一樣,初始化沒有被提高。 在咱們聲明(初始化)它們以前,它們是不可訪問的。 這被稱爲「暫時死區」。 當咱們在聲明變量以前嘗試訪問變量時,JavaScript
會拋出一個ReferenceError
。
譯者注:
關於let
的是否存在變量提高,咱們何以用下面的例子來驗證:
let name = 'ConardLi'
{
console.log(name) // Uncaught ReferenceError: name is not defined
let name = 'code祕密花園'
}
複製代碼
let
變量若是不存在變量提高,console.log(name)
就會輸出ConardLi
,結果卻拋出了ReferenceError
,那麼這很好的說明了,let
也存在變量提高,可是它存在一個「暫時死區」,在變量未初始化或賦值前不容許訪問。
變量的賦值能夠分爲三個階段:
undefined
關於let
、var
和function
:
let
的「建立」過程被提高了,可是初始化沒有提高。var
的「建立」和「初始化」都被提高了。function
的「建立」「初始化」和「賦值」都被提高了。for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
複製代碼
0 1 2
and 0 1 2
0 1 2
and 3 3 3
3 3 3
and 0 1 2
答案: C
因爲JavaScript
中的事件執行機制,setTimeout
函數真正被執行時,循環已經走完。 因爲第一個循環中的變量i
是使用var
關鍵字聲明的,所以該值是全局的。 在循環期間,咱們每次使用一元運算符++
都會將i
的值增長1
。 所以在第一個例子中,當調用setTimeout
函數時,i
已經被賦值爲3
。
在第二個循環中,使用let
關鍵字聲明變量i
:使用let
(和const
)關鍵字聲明的變量是具備塊做用域的(塊是{}
之間的任何東西)。 在每次迭代期間,i
將被建立爲一個新值,而且每一個值都會存在於循環內的塊級做用域。
const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => 2 * Math.PI * this.radius
};
shape.diameter();
shape.perimeter();
複製代碼
20
and 62.83185307179586
20
and NaN
20
and 63
NaN
and 63
答案: B
請注意,diameter
是普通函數,而perimeter
是箭頭函數。
對於箭頭函數,this
關鍵字指向是它所在上下文(定義時的位置)的環境,與普通函數不一樣! 這意味着當咱們調用perimeter
時,它不是指向shape
對象,而是指其定義時的環境(window)。沒有值radius
屬性,返回undefined
。
+true;
!"Lydia";
複製代碼
1
and false
false
and NaN
false
and false
答案: A
一元加號會嘗試將boolean
類型轉換爲數字類型。 true
被轉換爲1
,false
被轉換爲0
。
字符串'Lydia'
是一個真值。 咱們實際上要問的是「這個真值是假的嗎?」。 這會返回false
。
const bird = {
size: "small"
};
const mouse = {
name: "Mickey",
small: true
};
複製代碼
mouse.bird.size
mouse[bird.size]
mouse[bird["size"]]
答案: A
在JavaScript
中,全部對象鍵都是字符串(除了Symbol
)。儘管有時咱們可能不會給定字符串類型,但它們老是被轉換爲字符串。
JavaScript
解釋語句。當咱們使用方括號表示法時,它會看到第一個左括號[
,而後繼續,直到找到右括號]
。只有在那個時候,它纔會對這個語句求值。
mouse [bird.size]
:首先它會對bird.size
求值,獲得small
。 mouse [「small」]
返回true
。
可是,使用點表示法,這不會發生。 mouse
沒有名爲bird
的鍵,這意味着mouse.bird
是undefined
。 而後,咱們使用點符號來詢問size
:mouse.bird.size
。 因爲mouse.bird
是undefined
,咱們其實是在詢問undefined.size
。 這是無效的,並將拋出Cannot read property "size" of undefined
。
let c = { greeting: "Hey!" };
let d;
d = c;
c.greeting = "Hello";
console.log(d.greeting);
複製代碼
Hello
undefined
ReferenceError
TypeError
答案: A
在JavaScript
中,當設置它們彼此相等時,全部對象都經過引用進行交互。
首先,變量c
爲對象保存一個值。 以後,咱們將d
指定爲c
與對象相同的引用。
更改一個對象時,能夠更改全部對象。
let a = 3;
let b = new Number(3);
let c = 3;
console.log(a == b);
console.log(a === b);
console.log(b === c);
複製代碼
true
false
true
false
false
true
true
false
false
false
true
true
答案: C
new Number()
是一個內置的函數構造函數。 雖然它看起來像一個數字,但它並非一個真正的數字:它有一堆額外的功能,是一個對象。
當咱們使用==
運算符時,它只檢查它是否具備相同的值。 他們都有3
的值,因此它返回true
。
譯者注:
==
會引起隱式類型轉換,右側的對象類型會自動拆箱爲Number
類型。
然而,當咱們使用===
操做符時,類型和值都須要相等,new Number()
不是一個數字,是一個對象類型。二者都返回 false
。
class Chameleon {
static colorChange(newColor) {
this.newColor = newColor;
}
constructor({ newColor = "green" } = {}) {
this.newColor = newColor;
}
}
const freddie = new Chameleon({ newColor: "purple" });
freddie.colorChange("orange");
複製代碼
orange
purple
green
TypeError
答案: D
colorChange
方法是靜態的。 靜態方法僅在建立它們的構造函數中存在,而且不能傳遞給任何子級。 因爲freddie
是一個子級對象,函數不會傳遞,因此在freddie
實例上不存在freddie
方法:拋出TypeError
。
let greeting;
greetign = {}; // Typo!
console.log(greetign);
複製代碼
{}
ReferenceError: greetign is not defined
undefined
答案: A
控制檯會輸出空對象,由於咱們剛剛在全局對象上建立了一個空對象! 當咱們錯誤地將greeting
輸入爲greetign
時,JS解釋器實際上在瀏覽器中將其視爲global.greetign = {}
(或window.greetign = {}
)。
爲了不這種狀況,咱們可使用「use strict」
。 這能夠確保在將變量賦值以前必須聲明變量。
function bark() {
console.log("Woof!");
}
bark.animal = "dog";
複製代碼
SyntaxError
. You cannot add properties to a function this way.undefined
ReferenceError
答案: A
這在JavaScript
中是可能的,由於函數也是對象!(原始類型以外的全部東西都是對象)
函數是一種特殊類型的對象。您本身編寫的代碼並非實際的函數。 該函數是具備屬性的對象,此屬性是可調用的。
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
const member = new Person("Lydia", "Hallie");
Person.getFullName = () => this.firstName + this.lastName;
console.log(member.getFullName());
複製代碼
TypeError
SyntaxError
Lydia Hallie
undefined
undefined
答案: A
您不能像使用常規對象那樣向構造函數添加屬性。 若是要一次向全部對象添加功能,則必須使用原型。 因此在這種狀況下應該這樣寫:
Person.prototype.getFullName = function () {
return `${this.firstName} ${this.lastName}`;
}
複製代碼
這樣會使member.getFullName()
是可用的,爲何樣作是對的? 假設咱們將此方法添加到構造函數自己。 也許不是每一個Person
實例都須要這種方法。這會浪費大量內存空間,由於它們仍然具備該屬性,這佔用了每一個實例的內存空間。 相反,若是咱們只將它添加到原型中,咱們只需將它放在內存中的一個位置,但它們均可以訪問它!
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
const lydia = new Person("Lydia", "Hallie");
const sarah = Person("Sarah", "Smith");
console.log(lydia);
console.log(sarah);
複製代碼
Person {firstName: "Lydia", lastName: "Hallie"}
and undefined
Person {firstName: "Lydia", lastName: "Hallie"}
and Person {firstName: "Sarah", lastName: "Smith"}
Person {firstName: "Lydia", lastName: "Hallie"}
and {}
Person {firstName: "Lydia", lastName: "Hallie"}
and ReferenceError
答案: A
對於sarah
,咱們沒有使用new
關鍵字。 使用new
時,它指的是咱們建立的新空對象。 可是,若是你不添加new
它指的是全局對象!
咱們指定了this.firstName
等於'Sarah
和this.lastName
等於Smith
。 咱們實際作的是定義global.firstName ='Sarah'
和global.lastName ='Smith
。 sarah
自己的返回值是undefined
。
答案: D
在捕獲階段,事件經過父元素向下傳遞到目標元素。 而後它到達目標元素,冒泡開始。
答案: B
除基礎對象外,全部對象都有原型。 基礎對象能夠訪問某些方法和屬性,例如.toString
。 這就是您可使用內置JavaScript
方法的緣由! 全部這些方法均可以在原型上找到。 雖然JavaScript
沒法直接在您的對象上找到它,但它會沿着原型鏈向下尋找並在那裏找到它,這使您能夠訪問它。
譯者注:基礎對象指原型鏈終點的對象。基礎對象的原型是null
。
function sum(a, b) {
return a + b;
}
sum(1, "2");
複製代碼
NaN
TypeError
"12"
3
答案: C
JavaScript
是一種動態類型語言:咱們沒有指定某些變量的類型。 在您不知情的狀況下,值能夠自動轉換爲另外一種類型,稱爲隱式類型轉換。 強制從一種類型轉換爲另外一種類型。
在此示例中,JavaScript
將數字1
轉換爲字符串,以使函數有意義並返回值。 在讓數字類型(1
)和字符串類型('2'
)相加時,該數字被視爲字符串。 咱們能夠鏈接像「Hello」+「World」
這樣的字符串,因此這裏發生的是「1」+「2」
返回「12」
。
let number = 0;
console.log(number++);
console.log(++number);
console.log(number);
複製代碼
1
1
2
1
2
2
0
2
2
0
1
2
答案: C
後綴一元運算符++
:
0
)1
)前綴一元運算符++
:
2
)2
)因此返回0 2 2
。
function getPersonInfo(one, two, three) {
console.log(one);
console.log(two);
console.log(three);
}
const person = "Lydia";
const age = 21;
getPersonInfo`${person} is ${age} years old`;
複製代碼
Lydia
21
["", "is", "years old"]
["", "is", "years old"]
Lydia
21
Lydia
["", "is", "years old"]
21
答案: B
若是使用標記的模板字符串,則第一個參數的值始終是字符串值的數組。 其他參數獲取傳遞到模板字符串中的表達式的值!
function checkAge(data) {
if (data === { age: 18 }) {
console.log("You are an adult!");
} else if (data == { age: 18 }) {
console.log("You are still an adult.");
} else {
console.log(`Hmm.. You don't have an age I guess`);
}
}
checkAge({ age: 18 });
複製代碼
You are an adult!
You are still an adult.
Hmm.. You don't have an age I guess
答案: C
在比較相等性,原始類型經過它們的值進行比較,而對象經過它們的引用進行比較。JavaScript
檢查對象是否具備對內存中相同位置的引用。
咱們做爲參數傳遞的對象和咱們用於檢查相等性的對象在內存中位於不一樣位置,因此它們的引用是不一樣的。
這就是爲何{ age: 18 } === { age: 18 }
和 { age: 18 } == { age: 18 }
返回 false
的緣由。
function getAge(...args) {
console.log(typeof args);
}
getAge(21);
複製代碼
"number"
"array"
"object"
"NaN"
答案: C
擴展運算符(... args
)返回一個帶參數的數組。 數組是一個對象,所以typeof args
返回object
。
function getAge() {
"use strict";
age = 21;
console.log(age);
}
getAge();
複製代碼
21
undefined
ReferenceError
TypeError
答案: C
使用「use strict」
,能夠確保不會意外地聲明全局變量。 咱們從未聲明變量age
,由於咱們使用``use strict',它會引起一個
ReferenceError。 若是咱們不使用
「use strict」,它就會起做用,由於屬性
age`會被添加到全局對象中。
const sum = eval("10*10+5");
複製代碼
105
"105"
TypeError
"10*10+5"
答案: A
eval
會爲字符串傳遞的代碼求值。 若是它是一個表達式,就像在這種狀況下同樣,它會計算表達式。 表達式爲10 * 10 + 5
計算獲得105
。
sessionStorage.setItem("cool_secret", 123);
複製代碼
答案: B
關閉選項卡後,將刪除存儲在sessionStorage
中的數據。
若是使用localStorage
,數據將永遠存在,除非例如調用localStorage.clear()
。
var num = 8;
var num = 10;
console.log(num);
複製代碼
8
10
SyntaxError
ReferenceError
答案: B
使用var
關鍵字,您能夠用相同的名稱聲明多個變量。而後變量將保存最新的值。
您不能使用let
或const
來實現這一點,由於它們是塊做用域的。
const obj = { 1: "a", 2: "b", 3: "c" };
const set = new Set([1, 2, 3, 4, 5]);
obj.hasOwnProperty("1");
obj.hasOwnProperty(1);
set.has("1");
set.has(1);
複製代碼
false
true
false
true
false
true
true
true
true
true
false
true
true
true
true
true
答案: C
全部對象鍵(不包括Symbols
)都會被存儲爲字符串,即便你沒有給定字符串類型的鍵。 這就是爲何obj.hasOwnProperty('1')
也返回true
。
上面的說法不適用於Set
。 在咱們的Set
中沒有「1」
:set.has('1')
返回false
。 它有數字類型1
,set.has(1)
返回true
。
const obj = { a: "one", b: "two", a: "three" };
console.log(obj);
複製代碼
{ a: "one", b: "two" }
{ b: "two", a: "three" }
{ a: "three", b: "two" }
SyntaxError
答案: C
若是對象有兩個具備相同名稱的鍵,則將替前面的鍵。它仍將處於第一個位置,但具備最後指定的值。
答案: A
基本執行上下文是全局執行上下文:它是代碼中隨處可訪問的內容。
for (let i = 1; i < 5; i++) {
if (i === 3) continue;
console.log(i);
}
複製代碼
1
2
1
2
3
1
2
4
1
3
4
答案: C
若是某個條件返回true
,則continue
語句跳過迭代。
String.prototype.giveLydiaPizza = () => {
return "Just give Lydia pizza already!";
};
const name = "Lydia";
name.giveLydiaPizza();
複製代碼
"Just give Lydia pizza already!"
TypeError: not a function
SyntaxError
undefined
答案: A
String
是一個內置的構造函數,咱們能夠爲它添加屬性。 我剛給它的原型添加了一個方法。 原始類型的字符串自動轉換爲字符串對象,由字符串原型函數生成。 所以,全部字符串(字符串對象)均可以訪問該方法!
譯者注:
當使用基本類型的字符串調用giveLydiaPizza
時,實際上發生了下面的過程:
String
的包裝類型實例substring
方法const a = {};
const b = { key: "b" };
const c = { key: "c" };
a[b] = 123;
a[c] = 456;
console.log(a[b]);
複製代碼
123
456
undefined
ReferenceError
答案: B
對象鍵自動轉換爲字符串。咱們試圖將一個對象設置爲對象a
的鍵,其值爲123
。
可是,當對象自動轉換爲字符串化時,它變成了[Object object]
。 因此咱們在這裏說的是a["Object object"] = 123
。 而後,咱們能夠嘗試再次作一樣的事情。 c
對象一樣會發生隱式類型轉換。那麼,a["Object object"] = 456
。
而後,咱們打印a[b]
,它其實是a["Object object"]
。 咱們將其設置爲456
,所以返回456
。
const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"));
const baz = () => console.log("Third");
bar();
foo();
baz();
複製代碼
First
Second
Third
First
Third
Second
Second
First
Third
Second
Third
First
答案: B
咱們有一個setTimeout
函數並首先調用它。 然而卻最後打印了它。
這是由於在瀏覽器中,咱們不僅有運行時引擎,咱們還有一個叫作WebAPI
的東西。WebAPI
爲咱們提供了setTimeout
函數,例如DOM
。
將callback
推送到WebAPI
後,setTimeout
函數自己(但不是回調!)從堆棧中彈出。
如今,調用foo
,並打印First
。
foo
從堆棧彈出,baz
被調用,並打印Third
。
WebAPI
不能只是在準備就緒時將內容添加到堆棧中。 相反,它將回調函數推送到一個稱爲任務隊列
的東西。
這是事件循環開始工做的地方。 事件循環查看堆棧和任務隊列。 若是堆棧爲空,則會佔用隊列中的第一個內容並將其推送到堆棧中。
bar
被調用,Second
被打印,它從棧中彈出。
<div onclick="console.log('first div')">
<div onclick="console.log('second div')">
<button onclick="console.log('button')">
Click!
</button>
</div>
</div>
複製代碼
div
外部div
內部button
答案: C
致使事件的最深嵌套元素是事件的目標。 你能夠經過event.stopPropagation
中止冒泡
<div onclick="console.log('div')">
<p onclick="console.log('p')">
Click here!
</p>
</div>
複製代碼
p
div
div
p
p
div
答案: A
若是咱們單擊p
,咱們會看到兩個日誌:p
和div
。在事件傳播期間,有三個階段:捕獲,目標和冒泡。 默認狀況下,事件處理程序在冒泡階段執行(除非您將useCapture
設置爲true
)。 它從最深的嵌套元素向外延伸。
const person = { name: "Lydia" };
function sayHi(age) {
console.log(`${this.name} is ${age}`);
}
sayHi.call(person, 21);
sayHi.bind(person, 21);
複製代碼
undefined is 21
Lydia is 21
function
function
Lydia is 21
Lydia is 21
Lydia is 21
function
答案: D
使用二者,咱們能夠傳遞咱們想要this
關鍵字引用的對象。 可是,.call
方法會當即執行!
.bind
方法會返回函數的拷貝值,但帶有綁定的上下文! 它不會當即執行。
function sayHi() {
return (() => 0)();
}
typeof sayHi();
複製代碼
"object"
"number"
"function"
"undefined"
答案: B
sayHi
函數返回當即調用的函數(IIFE
)的返回值。 該函數返回0
,類型爲數字
。
僅供參考:只有7種內置類型:null
,undefined
,boolean
,number
,string
,object
和symbol
。 function
不是一個類型,由於函數是對象,它的類型是object
。
0;
new Number(0);
("");
(" ");
new Boolean(false);
undefined;
複製代碼
0
, ''
, undefined
0
, new Number(0)
, ''
, new Boolean(false)
, undefined
0
, ''
, new Boolean(false)
, undefined
答案: A
JavaScript
中只有6個假值:
undefined
null
NaN
0
''
(empty string)false
函數構造函數,如new Number
和new Boolean
都是真值。
console.log(typeof typeof 1);
複製代碼
"number"
"string"
"object"
"undefined"
答案: B
typeof 1
返回 "number"
. typeof "number"
返回 "string"
const numbers = [1, 2, 3];
numbers[10] = 11;
console.log(numbers);
複製代碼
[1, 2, 3, 7 x null, 11]
[1, 2, 3, 11]
[1, 2, 3, 7 x empty, 11]
SyntaxError
答案: C
當你爲數組中的元素設置一個超過數組長度的值時,JavaScript
會建立一個名爲「空插槽」的東西。 這些位置的值其實是undefined
,但你會看到相似的東西:
[1, 2, 3, 7 x empty, 11]
這取決於你運行它的位置(每一個瀏覽器有可能不一樣)。
(() => {
let x, y;
try {
throw new Error();
} catch (x) {
(x = 1), (y = 2);
console.log(x);
}
console.log(x);
console.log(y);
})();
複製代碼
1
undefined
2
undefined
undefined
undefined
1
1
2
1
undefined
undefined
答案: A
catch
塊接收參數x
。當咱們傳遞參數時,這與變量的x
不一樣。這個變量x
是屬於catch
做用域的。
以後,咱們將這個塊級做用域的變量設置爲1
,並設置變量y
的值。 如今,咱們打印塊級做用域的變量x
,它等於1
。
在catch
塊以外,x
仍然是undefined
,而y
是2
。 當咱們想在catch
塊以外的console.log(x)
時,它返回undefined
,而y
返回2
。
答案: A
JavaScript
只有原始類型和對象。
原始類型是boolean
,null
,undefined
,bigint
,number
,string
和symbol
。
[[0, 1], [2, 3]].reduce(
(acc, cur) => {
return acc.concat(cur);
},
[1, 2]
);
複製代碼
[0, 1, 2, 3, 1, 2]
[6, 1, 2]
[1, 2, 0, 1, 2, 3]
[1, 2, 6]
答案: C
[1,2]
是咱們的初始值。 這是咱們開始執行reduce
函數的初始值,以及第一個acc
的值。 在第一輪中,acc
是[1,2]
,cur
是[0,1]
。 咱們將它們鏈接起來,結果是[1,2,0,1]
。
而後,acc
的值爲[1,2,0,1]
,cur
的值爲[2,3]
。 咱們將它們鏈接起來,獲得[1,2,0,1,2,3]
。
!!null;
!!"";
!!1;
複製代碼
false
true
false
false
false
true
false
true
true
true
true
false
答案: B
null
是假值。 !null
返回true
。 !true
返回false
。
""
是假值。 !""
返回true
。 !true
返回false
。
1
是真值。 !1
返回false
。 !false
返回true
。
setInterval
方法的返回值什麼?setInterval(() => console.log("Hi"), 1000);
複製代碼
id
undefined
答案: A
它返回一個惟一的id
。 此id
可用於使用clearInterval()
函數清除該定時器。
[..."Lydia"];
複製代碼
["L", "y", "d", "i", "a"]
["Lydia"]
[[], "Lydia"]
[["L", "y", "d", "i", "a"]]
答案: A
字符串是可迭代的。 擴展運算符將迭代的每一個字符映射到一個元素。
文中若有錯誤,歡迎在評論區指正,若是這篇文章幫助到了你,歡迎點贊和關注。
想閱讀更多優質文章、可關注個人github
博客,你的star✨、點贊和關注是我持續創做的動力!
推薦你們使用Fundebug,一款很好用的BUG監控工具~
推薦關注個人微信公衆號【code祕密花園】,天天推送高質量文章,咱們一塊兒交流成長。
關注公衆號後回覆【加羣】拉你進入優質前端交流羣。