为了面试能通过,我要看完这75道面试题(下)
作者:Mark A
译者:前端小智
来源:dev
点赞再看,微信搜索 【大迁世界】 关注这个没有大厂背景,但有着一股向上积极心态人。本文
GitHub
https://github.com/qq449245884/xiaozhi 上已经收录,文章的已分类,也整理了很多我的文档,和教程资料。
编程,建网站必备的阿里云服务器竟然免费送了!
- 51. 什么是
async/await
及其如何工作? - 52. 展开运算符和Rest运算符有什么区别?
- 53. 什么是默认参数?
- 54. 什么是包装对象(wrapper object)?
- 55. 隐式和显式转换有什么区别?
- 56. 什么是NaN? 以及如何检查值是否为 NaN?
- 57. 如何判断值是否为数组?
- 58. 如何在不使用
%
模运算符的情况下检查一个数字是否是偶数? - 59. 如何检查对象中是否存在某个属性?
- 60. AJAX 是什么?
- 61. 如何在JavaScript中创建对象?
- 62. Object.seal 和 Object.freeze 方法之间有什么区别?
- 63. 对象中的 in 运算符和 hasOwnProperty 方法有什么区别?
- 64. 有哪些方法可以处理javascript中的异步代码?
- 65. 函数表达式和函数声明之间有什么区别?
- 66. 调用函数,可以使用哪些方法?
- 67. 什么是缓存及它有什么作用?
- 68. 手动实现缓存方法
- 69. 为什么typeof null返回 object? 如何检查一个值是否为 null?
- 70. new 关键字有什么作用?
- 71. 什么时候不使用箭头函数? 说出三个或更多的例子?
- 72. Object.freeze() 和 const 的区别是什么?
- 73. 如何在 JS 中“深冻结”对象?
- 74.
Iterator
是什么,有什么作用? - 75.
Generator
函数是什么,有什么作用?
51. 什么是 async/await
及其如何工作?
async/await
是 JS 中编写异步或非阻塞代码的新方法。它建立在Promises之上,让异步代码的可读性和简洁度都更高。
function callApi() {return fetch("url/to/api/endpoint").then(resp => resp.json()).then(data => {//do something with "data"}).catch(err => {//do something with "err"});
}
在async/await
,我们使用 tru/catch 语法来捕获异常。
async function callApi() {try {const resp = await fetch("url/to/api/endpoint");const data = await resp.json();//do something with "data"} catch (e) {//do something with "err"}
}
注意:使用 async
关键声明函数会隐式返回一个Promise。
const giveMeOne = async () => 1;giveMeOne().then((num) => {console.log(num); // logs 1});
const giveMeOne = async () => 1;function getOne() {try {const num = await giveMeOne();console.log(num);} catch (e) {console.log(e);}
}// Uncaught SyntaxError: await is only valid in async functionasync function getTwo() {try {const num1 = await giveMeOne(); // 这行会等待右侧表达式执行完成const num2 = await giveMeOne(); return num1 + num2;} catch (e) {console.log(e);}
}await getTwo(); // 2
52. 展开(spread )运算符和 剩余(Rest) 运算符有什么区别?
展开运算符(spread)是三个点(...
),可以将一个数组转为用逗号分隔的参数序列。说的通俗易懂点,有点像化骨绵掌,把一个大元素给打散成一个个单独的小元素。
function add(a, b) {return a + b;
};const nums = [5, 6];
const sum = add(...nums);
console.log(sum);
在本例中,我们在调用add
函数时使用了展开操作符,对nums
数组进行展开。所以参数a
的值是5
,b
的值是6
,所以sum
是11
。
function add(...rest) {return rest.reduce((total,current) => total + current);
};console.log(add(1, 2)); // 3
console.log(add(1, 2, 3, 4, 5)); // 15
在本例中,我们有一个add
函数,它接受任意数量的参数,并将它们全部相加,然后返回总数。
const [first, ...others] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(others); // [2,3,4,5]
这里,我们使用剩余操作符提取所有剩余的数组值,并将它们放入除第一项之外的其他数组中。
53. 什么是默认参数?
默认参数是在 JS 中定义默认变量的一种新方法,它在ES6或ECMAScript 2015版本中可用。
//ES5 Version
function add(a,b){a = a || 0;b = b || 0;return a + b;
}//ES6 Version
function add(a = 0, b = 0){return a + b;
}
add(1); // returns 1
function getFirst([first, ...rest] = [0, 1]) {return first;
}getFirst(); // 0
getFirst([10,20,30]); // 10function getArr({ nums } = { nums: [1, 2, 3, 4] }){return nums;
}getArr(); // [1, 2, 3, 4]
getArr({nums:[5,4,3,2,1]}); // [5,4,3,2,1]
function doSomethingWithValue(value = "Hello World", callback = () => { console.log(value) }) {callback();
}
doSomethingWithValue(); //"Hello World"
54. 什么是包装对象(wrapper object)?
我们现在复习一下JS的数据类型,JS数据类型被分为两大类,基本类型和引用类型。
基本类型:Undefined
,Null
,Boolean
,Number
,String
,Symbol
,BigInt
引用类型:Object
,Array
,Date
,RegExp
等,说白了就是对象。
其中引用类型有方法和属性,但是基本类型是没有的,但我们经常会看到下面的代码:
let name = "marko";console.log(typeof name); // "string"
console.log(name.toUpperCase()); // "MARKO"
name
类型是 string
,属于基本类型,所以它没有属性和方法,但是在这个例子中,我们调用了一个toUpperCase()
方法,它不会抛出错误,还返回了对象的变量值。
console.log(new String(name).toUpperCase()); // "MARKO"
55. 隐式和显式转换有什么区别)?
隐式强制转换是一种将值转换为另一种类型的方法,这个过程是自动完成的,无需我们手动操作。
console.log(1 + '6'); // 16
console.log(false + true); // 1
console.log(6 * '2'); // 12
第一个console.log
语句结果为16
。在其他语言中,这会抛出编译时错误,但在 JS 中,1
被转换成字符串,然后与+运
算符连接。我们没有做任何事情,它是由 JS 自动完成。
第二个console.log
语句结果为1
,JS 将false
转换为boolean
值为 0
,,true
为1
,因此结果为1
。
第三个console.log
语句结果12
,它将'2'
转换为一个数字,然后乘以6 * 2
,结果是12。
console.log(1 + parseInt('6'));
在本例中,我们使用parseInt
函数将'6'
转换为number
,然后使用+
运算符将1
和6
相加。
56. 什么是NaN? 以及如何检查值是否为NaN?
NaN
表示**“非数字”**是 JS 中的一个值,该值是将数字转换或执行为非数字值的运算结果,因此结果为NaN
。
let a;console.log(parseInt('abc')); // NaN
console.log(parseInt(null)); // NaN
console.log(parseInt(undefined)); // NaN
console.log(parseInt(++a)); // NaN
console.log(parseInt({} * 10)); // NaN
console.log(parseInt('abc' - 2)); // NaN
console.log(parseInt(0 / 0)); // NaN
console.log(parseInt('10a' * 10)); // NaN
JS 有一个内置的isNaN
方法,用于测试值是否为isNaN值,但是这个函数有一个奇怪的行为。
console.log(isNaN()); // true
console.log(isNaN(undefined)); // true
console.log(isNaN({})); // true
console.log(isNaN(String('a'))); // true
console.log(isNaN(() => { })); // true
所有这些console.log
语句都返回true
,即使我们传递的值不是NaN
。
在ES6
中,建议使用Number.isNaN
方法,因为它确实会检查该值(如果确实是NaN
),或者我们可以使自己的辅助函数检查此问题,因为在 JS 中,NaN是唯一的值,它不等于自己。
function checkIfNaN(value) {return value !== value;
}
57. 如何判断值是否为数组?
我们可以使用Array.isArray
方法来检查值是否为数组。 当传递给它的参数是数组时,它返回true
,否则返回false
。
console.log(Array.isArray(5)); // false
console.log(Array.isArray("")); // false
console.log(Array.isArray()); // false
console.log(Array.isArray(null)); // false
console.log(Array.isArray({ length: 5 })); // falseconsole.log(Array.isArray([])); // true
function isArray(value){return Object.prototype.toString.call(value) === "[object Array]"
}
let a = []
if (a instanceof Array) {console.log('是数组')
} else {console.log('非数组')
}
58. 如何在不使用%
模运算符的情况下检查一个数字是否是偶数?
我们可以对这个问题使用按位&
运算符,&
对其操作数进行运算,并将其视为二进制值,然后执行与运算。
function isEven(num) {if (num & 1) {return false} else {return true}
}
0
二进制数是 000
1
二进制数是 001
2
二进制数是 010
3
二进制数是 011
4
二进制数是 100
5
二进制数是 101
6
二进制数是 110
7
二进制数是 111
a | b | a & b |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 1 | 1 |
因此,当我们执行console.log(5&1)
这个表达式时,结果为1
。首先,&
运算符将两个数字都转换为二进制,因此5
变为101
,1
变为001
。
然后,它使用按位怀运算符比较每个位(0
和1
)。 101&001
,从表中可以看出,如果a & b
为1
,所以5&1
结果为1
。
101 & 001 |
---|
101 |
001 |
001 |
由此我们也可以算出console.log(4 & 1)
结果为0
。知道4
的最后一位是0
,而0 & 1
将是0
。如果你很难理解这一点,我们可以使用递归函数来解决此问题。
function isEven(num) {if (num < 0 || num === 1) return false;if (num == 0) return true;return isEven(num - 2);
}
59. 如何检查对象中是否存在某个属性?
const o = { "prop" : "bwahahah","prop2" : "hweasa"
};console.log("prop" in o); // true
console.log("prop1" in o); // false
第二种使用 hasOwnProperty
方法,hasOwnProperty()
方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
console.log(o.hasOwnProperty("prop2")); // true
console.log(o.hasOwnProperty("prop1")); // false
第三种使用括号符号obj["prop"]
。如果属性存在,它将返回该属性的值,否则将返回undefined
。
console.log(o["prop"]); // "bwahahah"
console.log(o["prop1"]); // undefined
60. AJAX 是什么?
即异步的 JavaScript 和 XML,是一种用于创建快速动态网页的技术,传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。使用AJAX则不需要加载更新整个网页,实现部分内容更新
- HTML - 网页结构
- CSS - 网页的样式
- JavaScript - 操作网页的行为和更新DOM
- XMLHttpRequest API - 用于从服务器发送和获取数据
- PHP,Python,Nodejs - 某些服务器端语言
61. 如何在 JS 中创建对象?
const o = {name: "前端小智",greeting() {return `Hi, 我是${this.name}`;}
};o.greeting(); // "Hi, 我是前端小智"
function Person(name) {this.name = name;
}Person.prototype.greeting = function () {return `Hi, 我是${this.name}`;
}const mark = new Person("前端小智");mark.greeting(); // "Hi, 我是前端小智"
const n = {greeting() {return `Hi, 我是${this.name}`;}
};const o = Object.create(n);
o.name = "前端小智";
62. Object.seal 和 Object.freeze 方法之间有什么区别?
Object.seal()方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要可写就可以改变。
63. in
运算符和 Object.hasOwnProperty
方法有什么区别?
hasOwnPropert()
方法返回值是一个布尔值,指示对象自身属性中是否具有指定的属性,因此这个方法会忽略掉那些从原型链上继承到的属性。
Object.prototype.phone= '15345025546';let obj = {name: '前端小智',age: '28'
}
console.log(obj.hasOwnProperty('phone')) // false
console.log(obj.hasOwnProperty('name')) // true
可以看到,如果在函数原型上定义一个变量phone
,hasOwnProperty
方法会直接忽略掉。
如果指定的属性在指定的对象或其原型链中,则in
运算符返回true
。
console.log('phone' in obj) // true
可以看到in
运算符会检查它或者其原型链是否包含具有指定名称的属性。
64. 有哪些方法可以处理 JS 中的异步代码?
65. 函数表达式和函数声明之间有什么区别?
hoistedFunc();
notHoistedFunc();function hoistedFunc(){console.log("注意:我会被提升");
}var notHoistedFunc = function(){console.log("注意:我没有被提升");
}
66. 调用函数,可以使用哪些方法?
作为函数调用——如果一个函数没有作为方法、构造函数、apply
、call
调用时,此时 this
指向的是 window
对象(非严格模式)
//Global Scopefunction add(a,b){console.log(this);return a + b;} add(1,5); // 打印 "window" 对象和 6const o = {method(callback){callback();}}o.method(function (){console.log(this); // 打印 "window" 对象});
作为方法调用——如果一个对象的属性有一个函数的值,我们就称它为方法。调用该方法时,该方法的this
值指向该对象。
const details = {name : "Marko",getName(){return this.name;}
}details.getName(); // Marko
作为构造函数的调用-如果在函数之前使用new
关键字调用了函数,则该函数称为构造函数
。构造函数里面会默认创建一个空对象,并将this
指向该对象。
function Employee(name, position, yearHired) {// 创建一个空对象 {}// 然后将空对象分配给“this”关键字// this = {};this.name = name;this.position = position;this.yearHired = yearHired;// 如果没有指定 return ,这里会默认返回 this
};const emp = new Employee("Marko Polo", "Software Developer", 2017);
使用apply
和call
方法调用——如果我们想显式地指定一个函数的this
值,我们可以使用这些方法,这些方法对所有函数都可用。
const obj1 = {result:0
};const obj2 = {result:0
};function reduceAdd(){let result = 0;for(let i = 0, len = arguments.length; i < len; i++){result += arguments[i];}this.result = result;
}reduceAdd.apply(obj1, [1, 2, 3, 4, 5]); // reduceAdd 函数中的 this 对象将是 obj1
reduceAdd.call(obj2, 1, 2, 3, 4, 5); // reduceAdd 函数中的 this 对象将是 obj2
67. 什么是缓存及它有什么作用?
68. 手动实现缓存方法]
function memoize(fn) {const cache = {};return function (param) {if (cache[param]) {console.log('cached');return cache[param];} else {let result = fn(param);cache[param] = result;console.log(`not cached`);return result;}}
}const toUpper = (str ="")=> str.toUpperCase();const toUpperMemoized = memoize(toUpper);toUpperMemoized("abcdef");
toUpperMemoized("abcdef");
这个缓存函数适用于接受一个参数。 我们需要改变下,让它接受多个参数。
const slice = Array.prototype.slice;
function memoize(fn) {const cache = {};return (...args) => {const params = slice.call(args);console.log(params);if (cache[params]) {console.log('cached');return cache[params];} else {let result = fn(...args);cache[params] = result;console.log(`not cached`);return result;}}
}
const makeFullName = (fName, lName) => `${fName} ${lName}`;
const reduceAdd = (numbers, startingValue = 0) => numbers.reduce((total, cur) => total + cur, startingValue);const memoizedMakeFullName = memoize(makeFullName);
const memoizedReduceAdd = memoize(reduceAdd);memoizedMakeFullName("Marko", "Polo");
memoizedMakeFullName("Marko", "Polo");memoizedReduceAdd([1, 2, 3, 4, 5], 5);
memoizedReduceAdd([1, 2, 3, 4, 5], 5);
69. 为什么typeof null 返回 object? 如何检查一个值是否为 null?
function isNull(value){return value === null;
}
70. new 关键字有什么作用?
function Employee(name, position, yearHired) {this.name = name;this.position = position;this.yearHired = yearHired;
};const emp = new Employee("Marko Polo", "Software Developer", 2017);
function Person() {
this.name = ‘前端小智’
}
- 创建一个空对象:
var obj = {}
- 将空对象分配给
this
值:this = obj - 将空对象的
__proto__
指向构造函数的prototype
:this.__proto__ = Person().prototype
- 返回
this
:return this
71. 什么时候不使用箭头函数? 说出三个或更多的例子?
- 当想要函数被提升时(箭头函数是匿名的)
- 要在函数中使用
this/arguments
时,由于箭头函数本身不具有this/arguments
,因此它们取决于外部上下文 - 使用命名函数(箭头函数是匿名的)
- 使用函数作为构造函数时(箭头函数没有构造函数)
- 当想在对象字面是以将函数作为属性添加并在其中使用对象时,因为咱们无法访问
this
即对象本身。
72. Object.freeze() 和 const 的区别是什么?]
const
和Object.freeze
是两个完全不同的概念。
const
声明一个只读的变量,一旦声明,常量的值就不可改变:
const person = {name: "Leonardo"
};
let animal = {species: "snake"
};
person = animal; // ERROR "person" is read-only
Object.freeze
适用于值,更具体地说,适用于对象值,它使对象不可变,即不能更改其属性。
let person = {name: "Leonardo"
};
let animal = {species: "snake"
};
Object.freeze(person);
person.name = "Lima"; //TypeError: Cannot assign to read only property 'name' of object
console.log(person);
73. 如何在 JS 中“深冻结”对象?
如果咱们想要确保对象被深冻结,就必须创建一个递归函数来冻结对象类型的每个属性:
let person = {name: "Leonardo",profession: {name: "developer"}
};
Object.freeze(person);
person.profession.name = "doctor";
console.log(person); //output { name: 'Leonardo', profession: { name: 'doctor' } }
function deepFreeze(object) {let propNames = Object.getOwnPropertyNames(object);for (let name of propNames) {let value = object[name];object[name] = value && typeof value === "object" ?deepFreeze(value) : value;}return Object.freeze(object);
}
let person = {name: "Leonardo",profession: {name: "developer"}
};
deepFreeze(person);
person.profession.name = "doctor"; // TypeError: Cannot assign to read only property 'name' of object
74. Iterator
是什么,有什么作用?
遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
- 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
- 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
- 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
- 不断调用指针对象的next方法,直到它指向数据结构的结束位置。
每一次调用next
方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value
和done
两个属性的对象。其中,value
属性是当前成员的值,done
属性是一个布尔值,表示遍历是否结束。
//obj就是可遍历的,因为它遵循了Iterator标准,且包含[Symbol.iterator]方法,方法函数也符合标准的Iterator接口规范。
//obj.[Symbol.iterator]() 就是Iterator遍历器
let obj = {data: [ 'hello', 'world' ],[Symbol.iterator]() {const self = this;let index = 0;return {next() {if (index < self.data.length) {return {value: self.data[index++],done: false};} else {return { value: undefined, done: true };}}};}
};
75. Generator
函数是什么,有什么作用?
如果说 JavaScrip 是 ECMAScript 标准的一种具体实现、Iterator
遍历器是Iterator
的具体实现,那么Generator
函数可以说是Iterator
接口的具体实现方式。
Generator
函数可以通过配合Thunk 函数更轻松更优雅的实现异步编程和控制流管理。
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
交流
文章每周持续更新,可以微信搜索「 大迁世界 」第一时间阅读和催更(比博客早一到两篇哟),本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,整理了很多我的文档,欢迎Star和完善,大家面试可以参照考点复习,另外关注公众号,后台回复福利,即可看到福利,你懂的。
为了面试能通过,我要看完这75道面试题(下)相关推荐
- Callable和Runnable的区别(面试常考),看完就懂
Callable和Runnable的区别(面试常考),看完就懂 Callable 接口 测试类 Runnable 接口 测试类 两者的区别 补充Executor框架 Callable 接口 publi ...
- python语法基础学习-Python基础语法精心总结!看完都知道的可以往下继续学习了...
原标题:Python基础语法精心总结!看完都知道的可以往下继续学习了 这应该是最详细的Python入门基础语法总结! 定义变量,使用变量 1. input 用户自己输入值 2. print 打印值 可 ...
- 看完这几道 JavaScript 面试题,让你与考官对答如流(中)
作者:Mark A 译者:前端小智 来源:dev 由于篇幅过长,我将此系列分成上中下三篇,上篇: 看完这几道 JavaScript 面试题,让你与考官对答如流(上) 26. 什么是IIFE,它的用途是 ...
- nodejs redis 过期时间_别在为Redis面试而烦恼了?看完暴答【面试管】
Redis面试官喜欢问的,小伙伴们看完暴答面试官!!! Redis 是什么?都有哪些使用场景?Redis 是一个使用 C 语言开发的高性能键值对(key-value)的内存数据库,性能优秀,数据在内 ...
- 面试5家公司,我发现这80道面试题最好用,直中要害
Java集合10题 ArrayList 和 Vector 的区别. 说说 ArrayList,Vector, LinkedList 的存储性能和特性. 快速失败 (fail-fast) 和安全失败 ( ...
- 14年的面试官经验分享,看完必有收获
面试,是找到好工作的过程中,最最重要的一环. 在我14年的职业生涯中,亲自面试的人应该不下1000人了. 看过的简历还要更多,尤其是微软上海早期扩张的时候. 所以今天,我就从自身经历出发,给你分享一些 ...
- 蚂蚁金服面试题泄露,看完这十道面试必问真题,稳拿Offer
最近编程讨论群有位小伙伴去蚂蚁金服面试了,以下是面试的真题,跟大家一起来讨论怎么回答. 1. 用到分布式事务嘛?为什么用这种方案,有其他方案嘛? 什么是分布式事务 谈到事务,我们就会想到数据库事务,很 ...
- 捡漏!蚂蚁金服面试题泄露,看完这十道面试必问真题,冲刺金九银十,稳拿大厂Offer!!
前言 最近编程讨论群有位小伙伴去蚂蚁金服面试了,以下是面试的真题,跟大家一起来讨论怎么回答. 1. 用到分布式事务嘛?为什么用这种方案,有其他方案嘛? 什么是分布式事务 谈到事务,我们就会想到数据库事 ...
- 2021一线互联网校招面试真题解析,看完这一篇你就懂了
前言 JavaScript是面向 Web 的编程语言,获得了所有网页浏览器的支持,是目前使用最广泛的脚本编程语言之一,也是网页设计和 Web 应用必须掌握的基本工具. JavaScript主要用途 嵌 ...
最新文章
- Git log、diff、config 进阶
- hibernate逆向工程生成的实体映射需要修改
- 这些好用的网站,看看你都收藏了没!
- HDU 1005 Number Sequence
- Expression Bland 入门视频(五) 了解对象面板和属性面板
- 回顾:我们从2次主要API中断中汲取的经验教训
- 刚写完的商城erp + 这个商城前台,新鲜出炉。自己1个人写, 包括php框架和前端html页面....
- android不同应用程序之间启动Activity
- Spring @AutoWired实现原理
- 软件测试:等价类划分-----EditBox问题增加文本框
- MongoDB 将Json数据直接写入MongoDB的方法
- 【html5和css3】transition属性整理
- Mac os 进行Android开发笔记(2)
- plsql32位链接64位oracle,32位PLsql连接64位Oracle问题
- linux下c语言编程实例
- 电子签章(Electronic Signature)在C#中的实现方法
- bp神经网络训练流程图,bp神经网络训练样本
- BaseRecyclerViewAdapterHelper开源项目之BaseSectionQuickAdapter 实现Expandable And collapse效果的源码学习...
- 该怎么压缩ppt大小
- 计算机专业英语问卷调查,关于英语调查问卷的总结
热门文章
- SDNU_ACM_ICPC_2019_Winter_Practice_9th题解
- 论文精读: MapReduce
- 怎样用python计算π的值_IV.python初探日记:python实现蒙特卡洛方法计算π值
- 基因家族进化分析之DNA序列批量获取
- android t9搜索算法,T9拨号盘搜索和排序算法
- 小米商城网页版(js+css)
- Ian Goodfellow回忆GAN诞生故事:几杯啤酒喝出“20年来最酷的深度学习想法”
- MPEG音频编码三十年
- polyline与polygon
- 高校最低分数录取线c语言,全国: 2018年普通高等学校招生录取最低控制分数线...