关键语句
| 名词 | 解释 |
|---|---|
| 对象 | 拥有属性和方法的数据类型 |
| 构造函数 | 用于创建和初始化对象的函数 |
| 实例 | 通过构造函数创建的对象 |
| 原型 | 每个实例都有的一个特殊属性proto |
| 原型对象 | 什么是原型对象 |
| 原型链 | 每个实例都有一个属性proto,会指向构造函数的原型对象,原型对象上也有一个proto属性,会继续指向原型对象,这样一层一层向上查找的过程称为原型链 |
| 浅拷贝 | 只复制第一层属性,基本类型就复制基本类型的值,引用类型就复制引用的内存地址 |
| 深拷贝 | 拷贝所有属性,拷贝前后的两个对象互不影响 |
程序题
闭包函数
function outter(){
var num = 10;
function inner(){
return console.log(num)
}
return inner()
}
outter()手写浅拷贝
const oldobj = {
name: "张三",
age: 25,
hobbies: ["读书", "游泳"],
address: {
city: "北京",
district: "朝阳区",
},
};
const newobj = {...oldobj}
newobj.age = 18
newobj.hobbies.push("跑步")
newobj.address.city = '深圳'
newobj.address.district = '宝安区'
console.log(oldobj)
console.log(newobj)手写深拷贝
const oldobj = {
name: "张三",
age: 25,
hobbies: ["读书", "游泳"],
address: {
city: "北京",
district: "朝阳区",
},
};
const newobj = JSON.parse(JSON.stringify(oldobj))
newobj.age = 18
newobj.hobbies.push("跑步")
newobj.address.city = '深圳'
newobj.address.district = '宝安区'
console.log(oldobj)
console.log(newobj)手写数组去重
const arr = [1,1,2,2,3,3,4,5]
const newarr = [...new Set(arr)]
console.log(newarr)手写数组排序
const arr = [5,4,6,1,3,2]
const newarr = arr.sort((a,b)=>a-b)
console.log(newarr)手写promise
var p = new Promise(function(reslove,reject){
let flag = false
if(flag){
reslove('成功了')
}else{
reject('出错了')
}
})手写防抖
function debounce(fn,delay){
return function(...args){
let timer = null
clearTimeout(timer)
timer = setTimeout(()=>{
fn.apply(this,args)
},delay)
}
}手写节流
function throttle(fn,interval){
let lastTime = 0
return function(...args){
const now = Date.now()
if(now - lastTime >= interval){
fn.apply(this,args)
lastTime = now
}
}
}简答题
Promise
- Promise 三种状态分别是什么?状态有什么特性?
- then、catch、finally 各自作用与区别?
- Promise.all / race / allSettled / any 四者区别与适用场景?
- 为什么 try-catch 不能直接捕获 Promise 内部异步错误?
- 简述 Promise 链式调用的原理。
闭包的优缺点
优点:
- 变量持久化
- 创建私有变量
- 模块封装
缺点:
- 内存泄漏
- 性能开销大
继承方式有哪些
- 原型链继承
- extends 和 super 继承
后台管理权限
RBAC模型:基于角色的访问控制
用户-角色-权限-角色权限
cookie、localstorage和sectionstorage的区别
- cookie 一般只有4kb,定期失效,窗口间可共享,请求自动携带,用于存储会话标识,用户数据追踪和服务器校验
- localstorage 一般有5mb,永久存储,窗口间可共享,不自动发送,用于长期存储主题、用户偏好、离线数据
- sectionstorage 一般有mb,当前页面有效,窗口间不共享,不自动发送,用于暂存表单、滚动位置、中间状态
this的指向有哪些
- 普通函数指向 window
- 定时器指向 window
- 箭头函数没有 this
- 事件中指向调用者
- 构造函数中指向实例
- 自调用函数指向 window
性能优化方式
- 减少请求次数
- 打包压缩上线
- 懒加载
- 动态渲染组件
- CDN加载
JS的执行机制是什么
JS是一个单线程、异步、非阻塞I/O,事件循环的执行机制
http请求有哪些
- get
- put
- post
- delete
ES6性特性
- const 和 let
- 箭头函数
- 模板字符串
- 剩余参数
- 类
- promise
如何实现图片懒加载
- loading = 'lazy'
vue 中 computed 和 watch 的区别是什么
- 基于原值的派生值要在模板中展示用computed
- 数据变化时行动用watch
vue组件传值
父传子:prop
子传父:$emit
兄弟传值:事件总线
类型判断有哪些方法
- 基本类型:typeof
- NaN:Number.isNaN()
- 数组:Array.isAarray()
- 对象:Object.prototype.toString.call()
- null:x == null
盒子模型
盒子由内容、内边距、边框、外边距组成
标准盒子的内容区域不包括内边距和边框,怪异盒子包括
什么是promise
promise是一个异步解决方案,代表一个未完成但是未来会完成的操作结果
什么是同源策略
域名、协议、端口一致
场景题
promise
- 手写简易版 Promise 核心逻辑(状态、resolve、reject、then)
- 封装一个通用的延时函数 sleep(ms) 返回 Promise
- 用 Promise 实现异步请求串行依次执行
问题
有一个数组 const arr = [1, 2, 3];,使用 push() 方法在数组末尾添加数字 4,并输出修改后的数组。
问题
数组 const numbers = [5, 10, 15, 20];,使用 pop() 方法删除数组的最后一个元素,并输出删除的元素和修改后的数组。
问题
给定数组 const letters = ['a', 'b', 'c'];,使用 shift() 方法删除数组的第一个元素,并输出删除的元素和修改后的数组。
问题
数组 const fruits = ['banana', 'apple'];,使用 unshift() 方法在数组开头添加 'orange',并输出修改后的数组。
问题
有数组 const nums = [1, 2, 3];,使用 forEach() 方法将数组中的每个元素乘以 2 并输出。
问题
给定数组 const ages = [20, 25, 30];,使用 map() 方法创建一个新数组,新数组中的每个元素是原数组对应元素加 5 的结果。
问题
数组 const numbersList = [1, 2, 3, 4, 5, 6];,使用 filter() 方法创建一个新数组,新数组中只包含偶数。
问题
有数组 const values = [1, 2, 3, 4];,使用 reduce() 方法计算数组所有元素的总和。
问题
数组 const users = [ { name: 'Alice', age: 25 }, { name: 'Bob', age: 30 }, { name: 'Charlie', age: 35 } ];,使用 find() 方法找到年龄为 30 的用户对象。
问题
给定数组 const colors = ['red', 'green', 'blue', 'yellow'];,使用 findIndex() 方法找到 'blue' 元素的索引。
遍历与映射
给定一个整数数组 [1, 2, 3, 4, 5],使用数组方法实现:
- 计算所有元素的平方,得到新数组 [1, 4, 9, 16, 25]。
- 筛选出其中的偶数,得到 [2, 4]。
reduce求和与分组
- 计算数组 [10, 20, 30, 40] 的总和(不得使用循环)。
- 根据以下对象数组,按 category 分组,得到格式 { food: [...], tool: [...] }。
const items = [
{ name: 'apple', category: 'food' },
{ name: 'hammer', category: 'tool' },
{ name: 'banana', category: 'food' },
{ name: 'screwdriver', category: 'tool' }
];去重与排序
给定数组 [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5],要求:
- 去除重复元素,得到 [3, 1, 4, 5, 9, 2, 6](顺序保持第一次出现)。
- 将去重后的数组按升序排序。
扁平化与条件查找
有一个嵌套数组 [1, [2, [3, 4], 5], 6],请:
- 将其完全扁平化为 [1, 2, 3, 4, 5, 6]。
- 在扁平化后的数组中查找第一个大于 3 的元素及其索引。
链式调用与复杂转换
有一个用户数据数组:
const users = [
{ name: 'Alice', age: 25, active: true },
{ name: 'Bob', age: 17, active: false },
{ name: 'Charlie', age: 30, active: true },
{ name: 'David', age: 16, active: true }
];要求:
- 筛选出年龄 ≥ 18 且 active 为 true 的用户。
- 提取他们的姓名,并转换为大写。
- 按照姓名排序(字母顺序)。 最终输出:['ALICE', 'CHARLIE']。
reduce实现复杂聚合
给定订单数组,每个订单包含 userId 和 amount,请计算每个用户的总金额,并返回格式 { userId: total },且只保留总金额 > 100 的用户。
const orders = [
{ userId: 1, amount: 50 },
{ userId: 2, amount: 120 },
{ userId: 1, amount: 80 },
{ userId: 3, amount: 40 },
{ userId: 2, amount: 30 }
];// 预期输出:
单选题
1
以下关于 Promise 描述错误的是?
A. Promise 有三种状态:pending、fulfilled、rejected B. Promise 状态一旦改变,就不会再变 C. 可以通过 then 监听成功,catch 监听失败 D. 新建 Promise 时,传入的函数会异步执行
2
下列代码输出顺序是?
console.log(1)
const p = new Promise((resolve) => {
console.log(2)
})
console.log(3)
p.then(() => console.log(4))A. 1 2 3 4 B. 1 3 2 4 C. 2 1 3 4 D. 1 2 4 3
3
Promise 状态改变说法正确的是? A. 只能 resolve B. 只能 reject C. resolve / reject 二选一,且只能变一次 D. 可以多次调用 resolve 反复改变状态
4
捕获 Promise 异步异常最规范的方式是? A. try/catch 直接包裹 Promise 实例 B. then 第二个回调参数 或 catch 方法 C. finally 捕获 D. 全局 window.onerror 必能捕获
5
Promise.all 特点描述正确的是? A. 所有 Promise 串行执行 B. 全部成功才 resolve,一个失败立即 reject C. 第一个完成就返回结果 D. 无论成败都收集所有结果
6
Promise.race 的作用是? A. 等待所有异步完成 B. 返回第一个状态改变的 Promise(成功/失败都算) C. 只返回第一个成功的 D. 过滤掉失败的 Promise
7
Promise.allSettled 特点是? A. 一失败就整体失败 B. 等待所有完成,统一返回每个的状态和结果 C. 只收集成功结果 D. 串行依次执行
8
Promise.any 特点是? A. 第一个成功就返回,全部失败才报错 B. 和 race 完全一样 C. 必须全部成功才返回 D. 只捕获第一个失败
9
以下代码输出什么?
Promise.resolve(1).then(2).then(res => console.log(res))
A. 1 B. 2 C. undefined D. 报错
10
Promise.finally 执行时机是? A. 仅成功后执行 B. 仅失败后执行 C. 无论成功失败,都会执行 D. 微任务最先执行
二、代码输出题
1
console.log('start')
new Promise(resolve => {
console.log('promise')
resolve()
}).then(() => {
console.log('then')
})
console.log('end')2
setTimeout(() => {
console.log('setTimeout')
}, 0)
Promise.resolve().then(() => {
console.log('promise then')
})
console.log('sync')3
let p = Promise.resolve(10)
p.then(res => {
console.log(res)
return res * 2
}).then(res => {
console.log(res)
})4
Promise.reject('err')
.then(() => console.log('ok'))
.catch(e => console.log(e))
.finally(() => console.log('finally'))5
Promise.all([
Promise.resolve(1),
Promise.resolve(2)
]).then(res => console.log(res))6
Promise.all([
Promise.resolve(1),
Promise.reject('fail')
]).then(res => console.log(res))
.catch(e => console.log(e))7
function fn() {
return new Promise(resolve => {
setTimeout(() => resolve(100), 1000)
})
}
fn().then(console.log)
console.log('先执行我')8
let a = Promise.resolve()
let b = a.then(() => {
console.log(1)
})
b.then(() => {
console.log(2)
})
console.log(3)输出
function Person() {}
let p = new Person();
console.log(p.__proto__ === Person.prototype);
console.log(Person.prototype.__proto__ === Object.prototype);
console.log(Object.prototype.__proto__);输出
function Cat() {}
Cat.prototype.name = "小猫";
let c = new Cat();
console.log(c.name);输出
function Dog() {}
Dog.prototype.say = function(){
console.log("汪汪");
};
let d1 = new Dog();
let d2 = new Dog();
console.log(d1.say === d2.say);输出
function Student(name) {
this.name = name;
}
Student.prototype.name = "默认学生";
let s = new Student("张三");
console.log(s.name);输出
function A(){}
function B(){}
B.prototype = new A();
let b = new B();
console.log(b.__proto__ === B.prototype);
console.log(b.__proto__.__proto__ === A.prototype);输出
function Foo() {
this.a = 1;
}
Foo.prototype.a = 2;
let f = new Foo();
console.log(f.a);
delete f.a;
console.log(f.a);输出
console.log({}.__proto__);
console.log([].__proto__);
console.log([].__proto__.__proto__);输出
var foo = 1;
function fn() {
foo = 3;
return;
function foo() {
// todo
}
}
fn();
console.log(foo);输出
var a = 10;
function test() {
console.log(a);
var a = 20;
console.log(a);
}
test();输出
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function () {
console.log('setTimeout');
}, 0);
async1();
new Promise(function (resolve) {
console.log('promise1');
resolve();
}).then(function () {
console.log('promise2');
});
console.log('script end');输出
async function test() {
console.log(1);
await new Promise((resolve) => {
console.log(2);
resolve();
}).then(() => {
console.log(3);
});
console.log(4);
}
test();
console.log(5);输出
setTimeout(function () {
console.log('1');
}, 0);
async function async1() {
console.log('2');
const data = await async2();
console.log('3');
return data;
}
async function async2() {
return new Promise((resolve) => {
console.log('4');
resolve('async2 的结果');
}).then((data) => {
console.log('5');
return data;
});
}
async1().then((data) => {
console.log('6');
console.log(data);
});
new Promise(function (resolve) {
console.log('7');
// resolve()
}).then(function () {
console.log('8');
});输出
async function testAwait() {
console.log('1. async 函数开始');
// 遇到 await,先执行 promise 同步代码,再暂停函数
const result = await new Promise((resolve) => {
console.log('2. promise 内部同步代码');
// 模拟异步操作(如接口请求)
setTimeout(() => {
console.log('5. promise 异步操作完成');
resolve('数据');
}, 1000);
});
// 这部分代码会被包装成微任务,等 promise 完成后执行
console.log('6. await 恢复,拿到结果:', result);
}
// 执行 async 函数
testAwait();
// 3. await 暂停时,主线程执行后面的同步代码
console.log('3. 主线程处理同步代码');
// 4. 主线程处理宏任务(setTimeout)
setTimeout(() => {
console.log('4. 主线程处理其他宏任务');
}, 500);输出
const p = new Promise((resolve, reject) => {
console.log(0);
reject();
console.log(1);
resolve();
console.log(2);
});
p.then((res) => {
console.log(3);
})
.then((res) => {
console.log(4);
})
.catch((res) => {
console.log(5);
})
.then((res) => {
console.log(6);
})
.catch((res) => {
console.log(7);
})
.then((res) => {
console.log(8);
});