这两天的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秘密花园】,天天推送高质量文章,咱们一块儿交流成长。
关注公众号后回复【加群】拉你进入优质前端交流群。