收藏 javascript-questions 这个仓库很久了,趁着周末来锻炼下自己的 JS 基础水平

因为逐渐也在承担一些面试工作,顺便摘录一些个人觉得比较适合面试的题目和方向

事件流(捕获、冒泡)

源链接

以下代码点击结果是啥?

<div onclick="console.log('div')">
<p onclick="console.log('p')">
Click here!
</p>
</div>
答案

-> 依次打印 pdiv

这道题考查事件流,在事件传播中,有三个阶段,捕获->目标->冒泡,按照标签来看,就是 div->p->div,但是默认只在冒泡阶段处理事件

如果需要在捕获阶段处理事件,可用 addEventLister 并且传入第三个参数为 true(默认是 false,即默认冒泡阶段处理)

<div id="div">
<p id="p">
Click here!
</p>
</div> <script>
document.getElementById('div').addEventListener('click', () => console.log('div'), true)
document.getElementById('p').addEventListener('click', () => console.log('p'), true)
</script>

call、apply、bind

源链接

以下代码输出结果是啥?

const person = { name: 'Lydia' };

function sayHi(age) {
return `${this.name} is ${age}`;
} console.log(sayHi.call(person, 21));
console.log(sayHi.bind(person, 21));
答案

-> Lydia is 21 [Function: bound sayHi]

这道题主要考查 call 和 bind,当然我们面试的时候一般会把 apply 拿出来一起考察下

call、apply 以及 bind 都是为了改变 this 指向而生,而 call 和 apply 用法比较像,都会在函数调用时改变 this 指向,唯一的区别是 apply 的第二个参数是数组,而 call 从第二个参数开始都是实际传入该函数中的值。bind 与他们不一样,它返回的还是函数

new

源链接

以下代码输出结果是啥?

function Car() {
this.make = 'Lamborghini';
return { make: 'Maserati' };
} const myCar = new Car();
console.log(myCar.make);
答案

-> Maserati

这题考查 new。如果对构造函数以及 new 比较了解的就会知道,构造函数里,如果返回一个非 null 的对象(包括数组),则将该对象值赋值给新建的对象

了解更多可以参考 一道有意思的笔试题引发的对于 new 操作符的思考

JSON.stringify

源链接

以下代码输出结果是啥?

const settings = {
username: 'lydiahallie',
level: 19,
health: 90,
}; const data = JSON.stringify(settings, ['level', 'health']);
console.log(data);
答案

-> {"level":19,"health":90}

这道题主要考查 JSON.stringify 的第二个参数,当然它还能传入第三个参数

语法:JSON.stringify(value[, replacer [, space]])。详见 JSON.stringify

replacer

replacer 参数可以是一个函数或者一个数组。作为函数,它有两个参数,键(key)和值(value),它们都会被序列化

在开始时,replacer 函数会被传入一个空字符串作为 key 值,代表着要被 stringify 的这个对象。随后每个对象或数组上的属性会被依次传入

const settings = {
username: 'lydiahallie',
level: 19,
health: 90,
}; const data = JSON.stringify(settings, (k, v) => {
console.log(k, v);
return v
}); console.log(data); /*
// 这里其实最开始打印了个空字符串。在开始时,replacer 函数会被传入一个空字符串作为 key 值,代表着要被 stringify 的这个对象
{ username: 'lydiahallie', level: 19, health: 90 }
username lydiahallie
level 19
health 90 {"username":"lydiahallie","level":19,"health":90}
*/
const settings = {
username: 'lydiahallie',
level: 19,
health: 90,
}; const data = JSON.stringify(settings, (k, v) => {
if (k === 'level') return v * 2
return v
}); console.log(data); // {"username":"lydiahallie","level":38,"health":90}

当传入数组的时候,相对比较简单,就是需要 picked 的 key(但是没法深度 pick,只能 pick 第一层)

space

用来格式化,可以传入数字或者字符串

const settings = {
username: 'lydiahallie',
level: 19,
health: 90,
}; const data = JSON.stringify(settings, null, 2); // 这时候和传入 ' '(length 2)效果一样 console.log(data); /*
{
"username": "lydiahallie",
"level": 19,
"health": 90
}
*/
const settings = {
username: 'lydiahallie',
level: 19,
health: 90,
}; const data = JSON.stringify(settings, null, 'hello'); console.log(data); /*
{
hello"username": "lydiahallie",
hello"level": 19,
hello"health": 90
}
*/

函数参数解构

源链接

以下代码输出结果是啥?

const myFunc = ({ x, y, z }) => {
console.log(x, y, z);
}; myFunc(1, 2, 3);
答案

-> undefined undefined undefined

这道题比较简单,myFunc 函数需要的是一个对象参数,并且有 key x yz,但是传入的并不是对象,所以都取了他们的默认值 undefined

如果传入对象,但是并没有对应的 key,也同样是 undefined

const myFunc = ({ x, y, z }) => {
console.log(x, y, z);
}; myFunc({ x: 1 }); // 1 undefined undefined

函数中的剩余参数

源链接

以下代码输出结果是啥?

function getItems(fruitList, ...args, favoriteFruit) {
return [...fruitList, ...args, favoriteFruit]
} getItems(["banana", "apple"], "pear", "orange")
答案

-> SyntaxError

这道题就比较脑经急转弯了,剩余参数只能放在最后,其实我觉得像上面代码那样其实也有使用场景,不知道未来会不会支持这样的写法

展开运算符

源链接

以下代码输出结果是啥?

const person = {
name: 'Lydia',
age: 21,
}; const changeAge = (x = { ...person }) => (x.age += 1);
const changeAgeAndName = (x = { ...person }) => {
x.age += 1;
x.name = 'Sarah';
}; changeAge(person);
changeAgeAndName(); console.log(person);
答案

-> { name: 'Lydia', age: 22 }

这道题的考点是展开运算符在对象中的使用。一般我们会用展开运算符来复制一个对象

当调用 changeAge(person) 时,参数传入了 person,所以 (x.age += 1) 实际操作的和 person 是一个对象引用。而调用 changeAgeAndName() 时,因为没有传入参数,所以 x 其实是 { ...person },而这个其实是 person 的一个浅拷贝

可以考查下将 (x = { ...person }) 改成 (x = person)

||

源链接

以下代码输出结果是啥?

const one = false || {} || null;
const two = null || false || '';
const three = [] || 0 || true; console.log(one, two, three);
答案

-> {} "" true

这道题的考点是 || 和假值。 || 运算符会返回第一个真值,如果都为假值,则返回最后一个值

这里可以顺便考查 &&&& 操作符,一旦遇到了假值,便会停止往后

console.log(true && 0); // 0
console.log(true && 0 && true); // 0
console.log(1 && 2); // 2
console.log(1 && false); // false
console.log('' && false); // ''

falsy

源链接

以下哪些值是假值?

0;
new Number(0);
('');
(' ');
new Boolean(false);
undefined;
答案

-> 0 '' undefined

JS 中的假值有以下几种:

  • false
  • ''
  • NaN
  • undefined
  • null
  • 0 / -0
  • 0n(BigInt(0))

除此之外,new Numbernew Boolean 创建的其实都是对象,都是真值

对象中 key 重复

源链接

以下代码输出结果是啥?

const obj = { a: 'one', b: 'two', a: 'three' };
console.log(obj);
答案

-> { a: 'three', b: 'two' }

这其实更像是一个规范,当对象中 key 重复的时候,value 会被后面的替换,但是 key 的位置会是第一次出现的位置

一般是对象合并的时候会用到:

const oldObj = {
name: 'fish',
age: 30
} const coverdObj = { name: 'lessfish' } const newObj = {
...oldObj,
...coverdObj
} console.log(newObj); // { name: 'lessfish', age: 30 }

Array Operators

有好几道和数组操作有关的题

这题 主要考查 push 操作返回 push 后的数组长度这题 也是类似

这题 主要考查哪些数组操作会改变原来的数组(splice)

这题 主要考查 reduce 的使用

[1, 2, 3, 4].reduce((x, y) => console.log(x, y));

这题还是比较有意思的,reduce 函数调用中如果有第二个参数,则会被当作第一次迭代中的 previous 值(也就是第一个参数 x),如果没有第二个参数,则数组第一个元素会被当作第一次迭代的 previous

所以上面的代码,如果 reduce 有第二个参数,会被迭代 4 次,如果没有,则是迭代三次

再看代码,因为没有第二个参数,所以第一次迭代参数是 12,reduce 迭代中的返回会被当作下次迭代的 previous,但是这里没返回,所以就是 undefined,而第二个参数 y 就是数组元素

Object Operators

这题 主要考查用 Object.defineProperty 定义的对象中的属性默认不可枚举,不能用 Object.keys 拿到

这题 主要考查 Object.freeze,顾名思义它能冰冻住对象,使得对象不能增、删、修改键值对(但是注意,它只是 freeze 了第一层,可以参考 这题

这题 考查 Object.seal,它能阻止对象新增、删除属性,但是对于已有的属性依然可以修改其值(注意和 freeze 一样同样只是第一层)

delete

源链接

以下代码输出结果是啥?

const name = 'Lydia';
age = 21; console.log(delete name);
console.log(delete age);
答案

-> false true

这题考查 delete 操作

首先 delete 返回一个布尔值,代表是否删除成功。然后 var const let 定义的变量,都不能被删除,只有全局变量才能被删除

这里要注意下 name,因为浏览器中默认挂了个全局变量 name,所以 delete name 是 ok 的

暂时性死区

这两题都是暂时性死区相关,注意下 varlet const 是有差异的,var 的话会变量声明提升(但是是 undefined),但是 letconst 并不会初始化

Object toString

源链接

以下代码输出结果是啥?

const animals = {};
let dog = { emoji: '' }
let cat = { emoji: '' } animals[dog] = { ...dog, name: "Mara" }
animals[cat] = { ...cat, name: "Sara" } console.log(animals[dog])
答案

-> { emoji: "", name: "Sara" }

当对象的 key 也是对象的时候,会自动调用 toString 转为 [object Object]

const animals = {};
let dog = { emoji: '' }
let cat = { emoji: '' } animals[dog] = { ...dog, name: "Mara" }
animals[cat] = { ...cat, name: "Sara" } console.log(animals[dog] === animals[cat]) // true

这题 大同小异

对象引用

源链接

以下代码输出结果是啥?

let person = { name: 'Lydia' };
const members = [person];
person = null; console.log(members);
答案

-> [ { name: 'Lydia' } ]

这题就属于会者不难了,理解了 JS 中的对象指针引用就行

进阶可以看下 纠结的连等赋值

标签函数

源链接

以下代码输出结果是啥?

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`;
答案

-> ["", " is ", " years old"] Lydia 21

这个叫做标签函数,函数调用后跟一个模版字符串,函数中第一个参数是数组,返回模版字符串中根据 ${xxx} 分割的字符元素,其余参数就是 ${xxx} 的值

暂时没想到有什么用,据说 styled-components 内部就是使用的它实现。可以参考下 这篇文章

String.raw

源链接

以下代码输出结果是啥?

console.log(String.raw`Hello\nworld`);
答案

-> Hello\nworld

顾名思义,会展示 raw string

Number.isNaN & isNaN

源链接

以下代码输出结果是啥?

const name = 'Lydia Hallie';
const age = 21; console.log(Number.isNaN(name));
console.log(Number.isNaN(age)); console.log(isNaN(name));
console.log(isNaN(age));
答案

可以参考 这里

简单说,Number.isNaN 只有传入 NaN 的时候,才返回 true。而 isNaN 会强制先将参数转为 Number 类型(调用 Number(xxx)

比如 isNaN('Lydia Hallie'),其实就是 isNaN(Number('Lydia Hallie')),而 Number('Lydia Hallie') 返回 NaN

ES6 Module

源链接

以下代码输出结果是啥?

// index.js
console.log('running index.js');
import { sum } from './sum.js';
console.log(sum(1, 2)); // sum.js
console.log('running sum.js');
export const sum = (a, b) => a + b;
答案

-> running sum.js running index.js 3

这题主要考查 ES6 模块是编译时输出接口,而依赖的代码会被先执行(CommonJS 模块是运行时加载,所以可以在任何地方 require

源链接

以下代码输出结果是啥?

// counter.js
let counter = 10;
export default counter;
// index.js
import myCounter from './counter'; myCounter += 1; console.log(myCounter);
答案

-> Error

ES6 导出的内容是只读的,不能被修改,只能在所导出模块中修改

关于 js modules 更多可参考 这里

宏任务、微任务

源链接

以下代码输出结果是啥?

const myPromise = Promise.resolve(Promise.resolve('Promise'));

function funcOne() {
setTimeout(() => console.log('Timeout 1!'), 0);
myPromise.then(res => res).then(res => console.log(`${res} 1!`));
console.log('Last line 1!');
} async function funcTwo() {
const res = await myPromise;
console.log(`${res} 2!`)
setTimeout(() => console.log('Timeout 2!'), 0);
console.log('Last line 2!');
} funcOne();
funcTwo();
答案

简单点说,await 后的代码其实可以理解成 Promise.then 后的代码

先理解下以下代码输出:

const myPromise = Promise.resolve(Promise.resolve('Promise'));

function funcOne() {
myPromise.then(res => console.log(`${res} 1!`));
} async function funcTwo() {
const res = await myPromise;
console.log(`${res} 2!`)
} funcOne();
funcTwo();

console.log(`${res} 1!`)console.log(`${res} 2!`) 可以理解为微任务队列的内容,依次执行

稍作修改:

const myPromise = Promise.resolve(Promise.resolve('Promise'));

function funcOne() {
myPromise.then(res => res).then(res => console.log(`${res} 1!`));
} async function funcTwo() {
const res = await myPromise;
console.log(`${res} 2!`)
} funcOne();
funcTwo();

这时微任务队列依次是 res => resconsole.log(`${res} 2!`),然后前者执行后,将 console.log(`${res} 1!`) 加入微任务队列中,所以其实是 console.log(`${res} 2!`) 先执行

更多可参考 我以前的总结

箭头函数

先明确下箭头函数和普通函数的几个区别:(参考 箭头函数

其中最重要的特性是,箭头函数没有自己的 this 对象,它的 this 是定义时上层作用域中的 this

源链接

以下代码输出结果是啥?

const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => 2 * Math.PI * this.radius,
}; console.log(shape.diameter());
console.log(shape.perimeter());
答案

根据 它的 this 是定义时上层作用域中的 this,原题可以改写成这样:

var that = this

const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => 2 * Math.PI * that.radius,
}; console.log(shape.diameter());
console.log(shape.perimeter());

这时候答案就比较清晰了

我们可以更进一步出题:

const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => {
return () => 2 * Math.PI * this.radius
}
}; console.log(shape.diameter());
console.log(shape.perimeter()());

这个时候答案其实没区别,毕竟第二个箭头函数 this 来自上层作用域,而上层作用域来自顶层作用域,层层传递

但是如果改写成这样:

const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: function () {
return () => 2 * Math.PI * this.radius
}
}; console.log(shape.diameter());
console.log(shape.perimeter()());

这就有意思了,因为上层并不是箭头函数,它的 this 指向 shape,所以箭头函数的 this 也指向 shape

这道题的考点可以是这个改写,需要对箭头函数中的 this 有着深入了解

92 这题的考点是箭头函数不能作为构造函数,所以它并没有 prototype 属性

98 这题比较脑经急转弯,箭头函数如果返回一个对象,需要用 () 包下

151 还是 this 相关,和第一题类似

这些 JavaScript 笔试题你能答对几道?的更多相关文章

  1. 10道javascript笔试题

    1.考察this JavaScript var length = 10; function fn() { console.log(this.length); } var obj = { length: ...

  2. 这10道javascript笔试题你都会么

    1.考察this var length = 10; function fn() { console.log(this.length); } var obj = {   length: 5, metho ...

  3. javascript 笔试题之删除数组重复元素

    笔试时紧张没写出来,静下心后发现简单的要死. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" & ...

  4. ThoughtWorks西邮暑期特训营 -- JavaScript在线笔试题

    ThoughtWorks 公司在西邮正式开办的只教女生前端开发的女子卓越实验室已经几个月过去了,这次计划于暑期在西邮内部开展面向所有性别所有专业的前端培训. 具体官方安排请戳:ThoughtWorks ...

  5. 你应该知道的25道Javascript面试题

    题目来自 25 Essential JavaScript Interview Questions.闲来无事,正好切一下. 一 What is a potential pitfall with usin ...

  6. JavaScript面试题链接汇总

    最新JavaScript笔试题(含答案) - 爱思资源网 前端工程师面试问题列表 - 爱思资源网 腾讯最新前端面试题记录分享 - 爱思资源网 优酷前端JS部分面试题 - 爱思资源网 百度校园招聘web ...

  7. 从阿里巴巴笔试题看Java加载顺序

    一.阿里巴巴笔试题: public class T implements Cloneable { public static int k = 0; public static T t1 = new T ...

  8. 我设计的ASP.NET笔试题,你会多少呢

    本笔试题考查范围包括面向对象基础.HTML.CSS.JS.EF.jQuery.SQL.编码思想.算法等范围. 第1题:接口和抽象类有何区别? 第2题:静态方法和实例方法有何区别? 第3题:什么是多态? ...

  9. 也许你需要点实用的-Web前端笔试题

    之前发的一篇博客里没有附上答案,现在有空整理了下发出来,希望能帮助到正在找工作的你,还是那句话:技术只有自己真正理解了才是自己的东西,共勉. Web前端笔试题 Html+css 1.对WEB标准以及w ...

  10. C/C++ 笔试题

    /////转自http://blog.csdn.net/suxinpingtao51/article/details/8015147#userconsent# 微软亚洲技术中心的面试题!!! 1.进程 ...

随机推荐

  1. Python:灵活的开发环境

    以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「englyf」https://mp.weixin.qq.com/s/WTl7BPAhX5VuK-gmHaErMg 本文大概 1667 个 ...

  2. Django视图层/FBV与CBV/jsonResponse对象/form表单上传文件/request对象获取文件

    目录 虚拟环境 视图层views 三板斧 jsonResponse对象 form如何上传文件/request对象获取文件 request对象方法 FBV与CBV CBV源码解析 虚拟环境 每创建一个虚 ...

  3. (admin.E104) 'XXXX' must inherit from 'InlineModelAdmin'.

    代码: class CaseStepAdmin(admin.ModelAdmin): list_display = ('id', 'casetep', 'casedata', 'webcase', ' ...

  4. Python使用pipreqs生成requirements.txt

    当一个Python完成后,若要在新环境下运行,往往需要重新安装各种包依赖,这就需要记录当前环境下所用到的包.包的版本等,非常麻烦,这里介绍一种方法,可以较为快速便捷地生成requirements.tx ...

  5. JavaScript:输出语法

    主要有三种,如下所示:

  6. Linux基础 文件和目录

    文件和目录 前言 本章讨论文件属性和文件系统内容.除了上一章讨论的普通文件,Linux的文件概念还包括:目录.设备等.在Linux系统中,文件的种类包括:普通文件.目录.符号链接.块设备.字符设备.管 ...

  7. k3s安装kubernetes环境

    官方文档:https://docs.rancher.cn/k3s/ 官方文档:https://rancher.com/docs/k3s/latest/en/installation/install-o ...

  8. [机器学习] Yellowbrick使用笔记3-特征分析可视化

    特征分析可视化工具设计用于在数据空间中可视化实例,以便检测可能影响下游拟合的特征或目标.因为ML操作高维数据集(通常至少35个),可视化工具将重点放在聚合.优化和其他技术上,以提供对数据的概述.这是Y ...

  9. [OpenCV实战]44 使用OpenCV进行图像超分放大

    图像超分辨率(Image Super Resolution)是指从低分辨率图像或图像序列得到高分辨率图像.图像超分辨率是计算机视觉领域中一个非常重要的研究问题,广泛应用于医学图像分析.生物识别.视频监 ...

  10. MongoDB分片副本集生产环境部署-Windows版本

    title: MongoDB分片副本集生产环境部署(Windows版本) date: 2022-10-29 17:21:11 tags: - 运维 系统架构 配置环境 系统都是windows 10 专 ...