前言
都是本人笔试遇到的一些看似简单但需要留意的摸底题......
1. 说出运行结果(1)基础逻辑
let number = 0;
console.log(number++); // 输出 0;
// 先执行number,再执行number = number + 1
console.log(++number); // 输出 2;
// 由于前面number++,此时number=1,先执行number + 1,再执行number
console.log(number); // 输出 2;
// 只执行number
2. 说出运行结果(2)类型转换
function getAge(...args) {
console.log(typeof args);
}
function getAge2(args) {
console.log(typeof args);
}
getAge(18); // 输出 object
getAge(null); // 输出 object
// (...args)会将传入函数的所有参数收集到一个数组中,typeof 判断引用类型都为object
getAge2(() => {}); // 输出 function
// typeof 判断引用类型都为object,但是function这种引用类型可以判断,
getAge2(null); // 输出 object
// 此外null也会判断为object,这是js的历史遗留问题
(...args)会将传入函数的所有参数收集到一个数组中,typeof 判断引用类型都为object,typeof 判断引用类型都为object,但是function这种引用类型可以判断,此外null也会判断为object,这是js的历史遗留问题
3. 说出运行结果(3)事件循环
// 宏任务 - setTimeout
setTimeout(() => {
console.log('2');
}, 0);
// 输出数字,同步代码
console.log('1');
// 微任务 - async/await
(async () => {
console.log('3');
await new Promise(resolve => {
console.log('4');
resolve();
});
console.log('5');
})();
// 微任务 - Promise.then
new Promise(resolve => {
console.log('6');
resolve();
}).then(() => {
console.log('7');
});
console.log('8');
// 输出:1 3 4 6 8 5 7 2
1、3、4是同步任务,但是await会阻塞后面代码执行进入微任务队列,所以5放入微任务等着,此时同步任务还没走完继续走到6和8,同步任务走完了就走微任务,执行5,再执行.then(7),最后执行定时器宏任务,所以468572
4. 说出运行结果(4)ES6
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 0);
}
// 输出 3 3 3
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 0);
}
// 输出 1 2 3
for (const i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 0);
}
// 报错,const变量无法改变
使用 var 声明的变量:
在第一个循环中使用 var i = 0,这里的 i 是在全局作用域中声明的。当 setTimeout 回调函数执行时,i 的值已经变成了 3,因为在循环结束后,i 的值变为 3。因此,输出结果为 3 3 3。
使用 let 声明的变量:
在第二个循环中使用 let i = 0,这里的 i 是在每次循环中都会重新声明和赋值的。
每次循环中的 i 都有自己的作用域,因此 setTimeout 回调函数中可以正确地捕获到每次循环中的 i 的值。因此,输出结果为 1 2 3。
使用 const 声明的常量:
在第三个循环中使用 const i = 0,这里的 i 被声明为一个常量,在循环中不能改变其值。由于 i 是一个常量,无法在循环中递增,所以会导致报错。因此,会抛出错误,无法输出任何值。
所以,使用 let 声明的变量解决了使用 var 时由于变量提升和闭包导致的问题,让循环中的异步操作能够正确捕获每次循环中的值,而使用 const 声明的常量则不允许重新赋值。。
5. 列举内联元素和块级元素分别有哪些,它们有什么区别?
内联元素
内联元素通常用来包裹文本或者其他内联元素,它们不会导致新的块级框生成。内联元素的特点包括:
- 在水平方向上排列,多个内联元素会在同一行显示。
- 内联元素只能容纳文本或其他内联元素,设置宽度和高度对内联元素没有效果。
- 常见的内联元素包括
<span>、<a>、<strong>、<em>、<img>等。
块级元素
块级元素通常用来表示页面上的结构,它们会导致一个新的块级框生成,独占一行显示。块级元素的特点包括:
- 会在垂直方向上占据一整行,因此会导致元素前后有换行。
- 可以容纳内联元素和其他块级元素,也可以设置宽度和高度。
- 常见的块级元素包括
<div>、<p>、<h1>-<h6>、<ul>、<li>、<table>、<form>等。
6. 请介绍 get 与 post 的区别?
-
参数传递方式:
- GET:通过 URL 的查询字符串传递参数,参数以键值对的形式出现在 URL 中,例如
https://baidu.com/page?id=5173。 - POST:参数传递是通过请求体进行传递,参数不会暴露在 URL 中,而是作为请求体的一部分发送给服务器,例如
https://baidu.com/page。
- GET:通过 URL 的查询字符串传递参数,参数以键值对的形式出现在 URL 中,例如
-
数据传输大小限制:
- GET:由于参数是附加在 URL 中的,所以传输的数据量有限,受浏览器和服务器的限制,一般不能超过 2048 字节。
- POST:由于参数是包含在请求体中的,所以可以传输大量数据,理论上没有大小限制。
-
安全性:
- GET:参数暴露在 URL 中,因此不适合传输敏感信息,如密码等,容易被拦截和篡改。
- POST:参数作为请求体的一部分发送,相对来说比 GET 方法更安全,适合传输敏感信息。
-
可缓存性:
- GET:请求可被缓存,可以被书签保存,可以被历史记录保存,可能会被浏览器缓存下来。
- POST:默认情况下不可被缓存,不会被保存在浏览器历史记录中。
-
幂等性:
- GET:请求是幂等的,多次请求返回的结果应该是一致的,不会对服务器产生影响。
- POST:请求不是幂等的,多次请求可能会对服务器产生副作用,如数据库写入等。
7. 事件传播的三个阶段执行顺序分别是什么?
-
捕获阶段:事件从最外层的元素开始向内部元素逐级传播,直到达到触发事件的目标元素。在捕获阶段,事件从 document 向目标元素传播。
-
目标阶段:事件达到目标元素后,在目标元素上触发,即执行绑定在目标元素上的事件处理函数。
-
冒泡阶段:事件从目标元素开始向外部元素逐级传播,直到传播到最外层的元素(一般是 document 或 window)。在冒泡阶段,事件从目标元素向 document 传播。
8. 请解释一下CSS盒子模型?
-
在标准盒模型下,盒子总宽度计算公式为:width + padding + border + margin
-
在怪异盒模型下(IE 盒模型),盒子总宽度计算公式为: width + margin,内边距和边框的宽度会被包含在 width 中,使用
box-sizing: border-box;可触发。 -
关于CSS盒子模型详细可看 请说说你对css盒模型的理解
9. css长度单位 px、em、rem、vw、vh的区别?
-
px(像素):像素是相对于显示器屏幕分辨率而言的长度单位,通常用来精确地定义元素的大小。1px 等于显示器上的一个物理像素。
-
em:em 是相对长度单位,它是相对于父元素的字体大小来计算的。例如,如果父元素的字体大小是 16px,1em 等于 16px。如果子元素的字体大小设置为 0.5em,那么它的字体大小将是父元素字体大小的一半。
-
rem:rem 也是相对长度单位,不同的是它是相对于根元素(html 元素)的字体大小来计算的。这使得 rem 单位更容易控制整个页面的布局,特别是在响应式设计中很有用。
-
vw(View Width):vw 是相对于视口宽度的百分比单位,1vw 等于视口宽度的 1%。使用 vw 单位可以根据视口宽度来调整元素的大小,适应不同设备的屏幕宽度。
-
vh(View Height):vh 是相对于视口高度的百分比单位,1vh 等于视口高度的 1%。类似于 vw,vh 可以根据视口高度来调整元素的大小。
10. 如何让一个div 上下左右居中?
内容:
<div class="con">
<div class="center">实现居中</div>
</div>
最常见的三种:
- 使用 Flexbox 属性:
.center{
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 垂直居中时需要指定容器的高度 */
}
- 使用 Grid 布局:
.center{
display: grid;
place-items: center;
height: 100vh; /* 垂直居中时需要指定容器的高度 */
}
- 绝对定位和 transform 属性:
.center{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
关于水平垂直居中的更详细内容可看 当面试官问你使内容水平垂直居中的方式有哪些时,你可以回答出几种?如何说出加分项的答案?
11. 实现冒泡排序
冒泡排序
function bubbleSort(arr) {
const n = arr.length;
for (let i = 0; i < n - 1; i++) {
for (let j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// 交换 arr[j] 和 arr[j + 1]
const temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
// 冒泡排序算法
const unsortedArray = [64, 34, 25, 12, 22, 11, 90];
console.log(bubbleSort(unsortedArray));
上点压力,实现一个二分查找
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
// 向下取整,即返回小于或等于给定数字的最大整数
let mid = Math.floor((left + right) / 2);
if(arr[mid] === target) {
return mid;
}
// 如果找到目标值,直接返回索引
else if (arr[mid] < target) {
// 如果中间元素小于目标值,在右半部分继续查找
left = mid + 1;
} else {
// 如果中间元素大于目标值,在左半部分继续查找
right = mid - 1;
}
}
// 如果未找到目标值,返回 -1
return -1;
}
// 测试二分查找算法
const sortedArray = [11, 22, 34, 45, 56, 67, 78, 89];
const target = 34;
const index = binarySearch(sortedArray, target);
if (index !== -1) {
console.log(`目标值 ${target} 在数组中的索引为:${index}`);
} else {
console.log(`未找到目标值 ${target}`);
}
再上点压力,实现一个快速排序算法
// 定义快速排序算法函数
function quickSort(arr) {
// 如果数组长度小于等于1,无需排序,直接返回数组
if (arr.length <= 1) {
return arr;
}
// 选择数组中的第一个元素作为枢轴(pivot)
const pivot = arr[0];
const left = []; // 用来存放比枢轴小的元素
const right = []; // 用来存放比枢轴大的元素
// 从数组第二个元素开始遍历
for (let i = 1; i < arr.length; i++) {
if (arr[i] < pivot) {
// 小于枢轴的元素放入left数组
left.push(arr[i]);
} else {
// 大于等于枢轴的元素放入right数组
right.push(arr[i]);
}
}
// 递归地对left和right数组进行快速排序,然后将左、枢轴、右三部分连接起来
return [...quickSort(left), pivot, ...quickSort(right)];
}
// 测试快速排序算法
const array = [64, 34, 25, 12, 22, 11, 90];
console.log(quickSort(array));
12. 删除数组中包含age:xx的JSON对象
// 方法一:splice
function foo1(arr, age) {
const res = arr;
arr.forEach((item, index) => {
if (item.age == age) {
res.splice(index, 1);
}
});
return res;
}
// 方法二:过滤器
function foo2(arr, age) {
return arr.filter((item) => item.age !== age);
}
const arr = [
{ name: "aaa", age: 18 },
{ name: "bbb", age: 19 },
{ name: "ccc", age: 20 },
];
参考资料:字节一面,丢了闪现,被拿一血