152期
1. 在做文件断点续传时,如何判断2次选择的是同一个文件?
2. 浏览器为什么有跨域限制,目的是什么?
3. 为什么推荐使用transform: translateX(10px);而不是left:10px;来实现动画?
上面问题的答案会在第二天的公众号(程序员每日三问)推文中公布
也可以小程序刷题,已收录500+面试题及答案
151期问题及答案
1. 说说Pomise.all和Promise.race的区别并举例?
Promise.all
和 Promise.race
是 Promise
对象的两个静态方法,它们用于处理多个 Promise
实例的不同情况。
Promise.all
Promise.all
是一个用于将多个 Promise
实例包装成一个新的 Promise
实例的方法。该方法接受一个可迭代对象(例如数组),这个可迭代对象里面的成员都是 Promise
实例。它的工作原理是:
当这个可迭代对象里的所有
Promise
实例全部进入fulfilled
状态时,Promise.all
返回的新的Promise
实例才会变为fulfilled
状态,它的结果是一个数组,包含了所有Promise
实例的结果。如果这个可迭代对象中有一个
Promise
实例进入rejected
状态,Promise.all
返回的新Promise
实例将立即变为rejected
状态,它的结果是那个第一个变为rejected
状态Promise
实例的错误。
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values); // 输出 [3, 42, "foo"]
});
在这个例子中,Promise.all
等待三个 Promise
实例完成,并且输出它们的结果。
Promise.race
Promise.race
也接受一个可迭代对象里面全是 Promise
实例的数组。与 Promise.all
方法不同的是,Promise.race
将返回这个可迭代对象中第一个变为 fulfilled
或 rejected
状态的 Promise
实例的结果。换句话说:
如果一个
Promise
实例首先变为fulfilled
状态,Promise.race
返回的新的Promise
实例也将变为fulfilled
状态。如果一个
Promise
实例首先变为rejected
状态,Promise.race
返回的新的Promise
实例也将变为rejected
状态。
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value); // 这一行不会被执行
}).catch((reason) => {
console.log(reason); // 输出 "two",因为 promise2 最先被 reject
});
在这个例子中,promise2
比 promise1
更快地变成 rejected
状态,所以 Promise.race
返回的 Promise
实例也变成 rejected
状态,并输出 two
。
总结一下,Promise.all
需要等待所有的 Promise
实例都完成,返回的结果是所有 Promise
的结果组成的数组,而 Promise.race
只关心第一个被 settled
(无论是 fulfilled
还是 rejected
)的 Promise
实例,并且返回这个 Promise
实例的结果。
2. js对象中的可枚举是什么意思,如何控制它的可枚举性?
在 JavaScript 中,对象的属性分为可枚举(enumerable)和不可枚举(non-enumerable)。可枚举属性指的是该属性可以出现在对象的属性枚举中,例如使用 for...in
循环或者 Object.keys()
方法时,可以遍历到这些属性。
控制属性的可枚举性
在 JavaScript 中,可以通过以下方法来控制和查看某个对象属性的可枚举性:
使用 Object.defineProperty() 方法定义或修改属性的可枚举性
通过
Object.defineProperty()
方法,你可以直接定义新属性或者修改现有属性的特性(包括可枚举性):let obj = {}; Object.defineProperty(obj, 'a', { value: 1, enumerable: true // 属性 "a" 是可枚举的 }); Object.defineProperty(obj, 'b', { value: 2, enumerable: false // 属性 "b" 是不可枚举的 }); for (let key in obj) { console.log(key); // 输出:"a" } console.log(Object.keys(obj)); // 输出:["a"]
在这个示例中,属性 "a" 是可枚举的,因此它会出现在
for...in
循环和Object.keys()
的输出中。而属性 "b" 是不可枚举的,所以它不会被输出。使用 Object.getOwnPropertyDescriptor() 方法查看属性的可枚举性
想要知道某个属性的可枚举性,可以使用
Object.getOwnPropertyDescriptor()
方法:let propertyDescriptor = Object.getOwnPropertyDescriptor(obj, 'a'); console.log(propertyDescriptor.enumerable); // 输出:true propertyDescriptor = Object.getOwnPropertyDescriptor(obj, 'b'); console.log(propertyDescriptor.enumerable); // 输出:false
默认的属性可枚举性
在通过普通的方式创建对象时(即使用对象字面量),对象属性的默认特性是可枚举的:
let obj = {
x: 10
};
console.log(Object.keys(obj)); // 输出:["x"]
但是,通过对象构造函数定义的内置属性通常是不可枚举的。例如,原型链中的方法 obj.toString
或者数组的 length
属性都是不可枚举的。
总结来说,JS 对象属性的可枚举性控制其在枚举对象属性时是否会出现。更改属性的可枚举性大多数时候是通过 Object.defineProperty
方法实现的。这在控制对象属性在 for...in
、Object.keys()
或者 JSON.stringify 方法中的表现时很有用。
3. 常见的左右布局有哪些实现方式,请举例说明?
左右布局是Web开发中常见的页面布局模式,意在将页面分为左右两个区域,通常用于侧边栏和主要内容区的布局设计。以下是几种常见的实现方法,每种方法都有其自身的使用场景和优缺点:
1. 浮动(Float)
浮动布局是早期最常用的左右布局实现方式之一。
<div class="container">
<div class="sidebar" style="float: left; width: 200px;">侧边栏</div>
<div class="content" style="margin-left: 200px;">主要内容</div>
</div>
浮动可能需要清除浮动(clearfix)以防止高度塌陷的问题。
2. 定位(Positioning)
绝对定位可以用来创建左右布局,将侧边栏或内容区设置为固定宽度。
<div class="container" style="position: relative;">
<div class="sidebar" style="position: absolute; left: 0; width: 200px; top: 0;">侧边栏</div>
<div class="content" style="margin-left: 200px;">主要内容</div>
</div>
这种方法可能会导致重叠,特别是当内容高度超过视窗高度时。
3. 内联块(Inline-Block)
使用 display: inline-block;
也可以实现左右布局,要确保两个内联块元素合在一起的宽度不超过其容器宽度。
<div class="container">
<div class="sidebar" style="display: inline-block; width: 200px; vertical-align: top;">侧边栏</div>
<div class="content" style="display: inline-block; vertical-align: top;">主要内容</div>
</div>
该方法可能需要解决内联块元素之间的空白间隔问题。
4. Flexbox(弹性盒布局)
Flexbox 提供了更灵活的布局选项。
<div class="container" style="display: flex;">
<div class="sidebar" style="flex: 0 0 200px;">侧边栏</div>
<div class="content" style="flex-grow: 1;">主要内容</div>
</div>
在这个例子中,侧边栏有一个固定的宽度,而主要内容区则占据剩余的空间。
5. CSS Grid(网格布局)
CSS Grid 是一个强大的布局系统,可以创建复杂的网格布局。
<div class="container" style="display: grid; grid-template-columns: 200px auto;">
<div class="sidebar">侧边栏</div>
<div class="content">主要内容</div>
</div>
这里,我们定义了两列,其中 200px
为侧边栏固定的宽度,auto
表示主要内容区占用剩余的空间。
6. 表格布局(Table)
虽然不建议用于页面布局,但表格布局也可以实现左右布局。
<div class="container" style="display: table; width: 100%;">
<div class="sidebar" style="display: table-cell; width: 200px;">侧边栏</div>
<div class="content" style="display: table-cell;">主要内容</div>
</div>
侧边栏设置为表格单元格并分配固定宽度,而主要内容区随后也是一个表格单元。
总结
以上所示的方法各有特点,不同的实现选择取决于具体的布局需求和所支持的浏览器。随着前端技术的发展,现代布局通常更推荐使用 Flexbox 和 CSS Grid,因为它们提供了更高的灵活性、更简洁的代码,且易于维护。
我要提问
如果你遇到有趣的面试题,或者有想知道的前端面试题,可以在下面的小程序提问,收到问题后会在第一时间为你解答。
我要出题
学习不打烊,充电加油只为遇到更好的自己,每天早上9点纯手工发布面试题,每天坚持花20分钟来学习与思考,在千变万化,类库层出不穷的今天,不要等到找工作时才狂刷题,提倡每日学习。