以下题目来自掘金等其它博客,但是问题的答案都是根据笔者自己的理解做出的。如果你最近想要换工作或者巩固一下自己的前端知识基础,不妨和我一起参与到每日刷题的过程中来,如何?
第七天要刷的面试题如下:
- 什么是DOM和BOM?
- 什么时尾调用,使用尾调用有什么好处?
- use strict是什么?使用与否有什么区别?
- for...in和for..of的区别?
- 如何使用for..of遍历对象?
下面是我自己的理解:
1. 什么是DOM和BOM?
- DOM是文档对象模型,英文名为document object model,表示将文档作为一个对像对待,而这个对象上的属性和方法主要是为了用来操作网页内容。
- BOM是浏览器对象模型,英文名为browser object model,表示将浏览器作为一个对像对待,而这个对象上的属性和方法主要是为了用来和浏览器进行交互以及调用浏览器提供的api。
- BOM的核心是window对象;window本身具有双重角色:
- js访问浏览器窗口的一个接口;
- window本身是一个Global对象;
- 在网页中定义的任何对象,变量,函数都作为全局对象的一个属性或者方法存在;
- window上重要的属性有:location navigation screen document等。
2. 什么时尾调用,使用尾调用有什么好处?
- 尾调用(Tail Call)的含义就是在函数A的最后一步调用函数B
- 注意一定是最后一步,这是可以通过合理的安排函数A的结构体实现的!
- 原理:代码执行时基于执行栈的,所以在一个函数中调用另一个函数的时候,会保留调用者A的执行上下文 (保留直到函数A执行完毕! ),然后将被调用的函数B的执行上下文加入到执行栈中
- 显而易见的是,如果函数之间的相互调用层数过深,就会导致很多的函数执行上下文都被加入到执行栈中,导致栈的溢出!
- 采用尾调用优化之后的函数,根据定义,函数A只有可能在最后一步才调用函数B,既然是最后一步那么js引擎就无需将A的执行上下文保存在执行栈中了!
- 于是节省了内存
- 需要注意的是:尾调用优化只有在严格模式下才会生效
不使用尾调用优化的斐波那契数列
js
function factorial(n) {
if (n <= 1) {
return 1;
}
// 非尾调用:递归调用后仍需乘以 n
return n * factorial(n - 1);
}
使用尾调用优化的斐波那契数列
js
function factorialTail(n, acc = 1) {
if (n <= 1) {
return acc;
}
// 尾调用优化:传递累积的结果而不进行额外的乘法操作
return factorialTail(n - 1, n * acc);
}
3. use strict是什么?使用与否有什么区别?
- 本质上是一段字符串,直接写在作用域顶部
- 如果是在ES5之下的js版本中使用,值会被当成是一个普通的字符串常量处理,并不会触发严格模式
- 是ECMS5引入的一种运行模式 ,又称为严格模式
- 作用:
- 消除js中语法的不合理、不严谨的地方,减少怪异的行为
- 提升了效率(优化变量接卸,禁止意外的全局变量的创建)
- 消除了js中的不安全的行为
- 为新版本js的出现做铺垫
- 区别在于:
- 禁止了with语句的使用
- 禁止this默认指向全局对象的特性
- 对象不能有重名的属性
- 作用域:
*- 函数作用域
-
- 全局作用域
4. for...in和for..of的区别?
从以下对象、顺序、机制、迭代值
四个角度阐述其区别是比较合适和全面的
- 迭代的对象类型 :for...in 用于迭代对象的可枚举属性 ,而 for...of 用于迭代可迭代对象(比如数组、字符串、Set、Map 等)的元素。
- 迭代顺序 :for...in 循环以任意顺序 迭代对象的属性,对于数组或字符串,它会遍历索引或字符。而 for...of 循环按照对象的迭代协议依次迭代元素,通常按照添加顺序进行循环。
- 遍历机制 :for...in 会遍历对象及其原型链上的所有可枚举属性(包括继承的属性),需要使用 hasOwnProperty() 方法 来排除继承的属性。而 for...of 只能遍历可迭代对象自身的元素,不会访问对象的属性或方法。
- 迭代变量 :for...in 循环提供一个变量来表示每个属性的键或索引 。而 for...of 循环提供一个变量来表示每个元素的值。
5. 如何使用for..of遍历对象?
有两种方式,对于类数组对象
,将其转换成真正的数组之后使用for.of遍历其中的元素;另外一个是实现[Symbol.iterator]
接口:
使用方式一
javascript
const obj = {
0: 'one',
1: 'two',
length : 2
}
for(let i of Array.from(obj)){}
使用方式二
javascript
const obj = {
_count: 0,
[Symbol.iterator]: function(){
return {
next(){
return {
value: obj._count++,
done: false,
}
}
}
}
}
下面是可迭代对象实现的[Symbol.iterator]接口的格式:
typescript
interface Iterable<T> {
[Symbol.iterator](): Iterator<T>;
}
interface Iterator<T> {
next(value?: any): IteratorResult<T>;
}
interface IteratorResult<T> {
value: T;
done: boolean;
}