年后第一面 —— 被遗忘的基础所击垮
前记
可谓是 “岁月蹉跎,遗忘成尘埃的痕迹”。最近在机缘巧合下投递了一家互联网大厂的实习,秉承着面试就是一次不错的学习机会的思想接下了这次时隔两三个月的再一次面试。不面不知道,一面就好像自己不是做前端的一样了。面试官问的问题和我给出的答案总是背道而驰,那些之前熟能生巧的题目再次出现就跟看到陌生人一样,就此写下这次总结,反省自己。
面试题
盒模型
很经典的一道面试题,但是面试的时候语言组织的磕磕碰碰。
盒模型,是用于描述网页中元素布局和定位的一种模型,将每个HTML元素看作是一个矩形盒子,这个盒子由内容区域(content)、内边距(padding)、外边距(margin)、边框(border)组成,这些部分共同决定了元素在页面中的尺寸和位置。可以分为以下几部分:
- 内容区域(Content Area):内容区域指的是盒子中用于显示实际内容的部分,例如文本、图像等。
- 内边距(Padding):内边距是内容区域与边框之间的空间,同于控制内容与边框之间的距离。内边框的大小可以通过padding属性进行设置。
- 外边距(Margin):外边距是盒子与其他元素之间的空白区域,用于控制元素之间的距离。外边距的大小可以通过margin属性进行设置。
- 边框(Border):边框是围绕内容和内边距的线条或样式,用于界定元素的边界。边框的样式、宽度和颜色可以通过border属性进行设置。
盒模型分为:标准盒模型和怪异盒模型(IE盒模型)
区别:
- 标准盒模型总宽度:width + padding + border + margin
- 怪异(IE)盒模型总宽度:width + margin
标准盒模型和怪异(IE)盒模型的使用
可以通过在css代码中设置 box-sizing来让浏览器使用需要的盒模型:
box-sizing:border-box; /*设置浏览器以怪异(IE)盒模型来加载容器*/
box-sizing:content-box; /*设置浏览器以标准盒模型来加载容器*/
box-sizing:inherit; /*规定应从父元素上继承box-sizing的值*/
元素的显隐:display、visibility、opacity
没错,这道题也是前端面试基础的典中典的题目了,但是其中涉及到的细节却一直让我熟视无睹(看了就忘)。
-
display(显隐):该属性控制元素在页面中的布局方式以及是否显示。它的取值:
- block:元素以块级元素的形式显示,在页面中独占一行。
- inline:元素以内联元素的形式显示,不会独占一行,允许其他元素与其在同一行内。
- none:元素将不显示在页面上,占据的空间也会被其他元素填充。
从浏览器重排重绘的角度: 修改元素的"display"属性会触发重排重绘,当从"none",切换到其他任何值,或者从其他值切换到"none"时,都会导致元素的重排重绘。因为该表元素的显示属性会影响到元素的布局和页面的结构。
-
visibility(可见性):该属性控制元素是否可见,但不会影响其在页面中的布局。有两个取值选项:
- visible:元素是可见的,默认值
- hidden:元素是不可见的,但仍会占据在页面中的空间。
从浏览器重排重绘的角度: 只会触发重绘,不会触发重排。
-
opacity(透明度): 该属性控制元素的透明级别,即元素的可见度。它的取值范围是0到1之间,其中0表示完全透明(不可见),1表示完全不透明(完全可见)。中间的值表示不同程度的透明。
从浏览器重排重绘的角度: 只会触发重绘,不会触发重排。
intanceof的实现原理
intanceof 用于构造函数的 prototype 属性是否出现在对象的原型链上的任何位置
function myInstanceof(left,right){
// 获取对象的原型
let proto = Object.getPrototypeOf(left);
// 获取构造函数的 prototype 对象
let prototype = right.prototype;
// 判断构造函数的 prototype 对象是否在对象的原型链上
while(true){
if(!proto) return false;
if(proto === prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}
拓展运算符实现的是深拷贝还是浅拷贝,原理?
直接看一段代码:
const o1 = { a:1 };
const o2 = {...o1};
o1.a = 2;
console.log(o1); // { a:2 }
console.log(o2); // { a:1 }
很明显这里进行了深拷贝,但是你再看下面这段代码:
const o1 = { a: 1, b: { c: 1 } };
const o2 = { ...o1 };
o1.a = 2;
o1.b.c = 2;
console.log(o1); // { a: 2, b: { c: 2 } }
console.log(o2); // { a: 1, b: { c: 2 } }
看出来了吗,拓展运算符只是把对象的第一层进行了深拷贝,后面如果有嵌套对象的话进行还是浅拷贝。
原理: 拓展运算符通过遍历数组或对象的元素或属性,将他们复制到新的数组或对象中,但在嵌套的对象中只深拷贝第一层,后面的嵌套对象中复制的引用地址而不是创建新的对象(浅拷贝)。
Promise 的代码题
看代码:
new Promise((resolve,reject) => {
throw new Error("error");
});
console.log(1);
问题:
-
这个promise的状态会变成什么? 答案:reject
-
后续的
console.log(1)会不会执行?为什么?答案:在js中,错误抛出只会中断当前的代码执行,并且会导致程序控制流转移到最近的错误处理机制,例如
try-catch块或Promise的catch方法。错误的抛出并不会完全停止整个程序的执行。
总结
基础面试题系列会持续更新的,为了我这地动山摇的地基...