Skip to content

关键语句

名词解释
对象拥有属性和方法的数据类型
构造函数用于创建和初始化对象的函数
实例通过构造函数创建的对象
原型每个实例都有的一个特殊属性proto
原型对象什么是原型对象
原型链每个实例都有一个属性proto,会指向构造函数的原型对象,原型对象上也有一个proto属性,会继续指向原型对象,这样一层一层向上查找的过程称为原型链
浅拷贝只复制第一层属性,基本类型就复制基本类型的值,引用类型就复制引用的内存地址
深拷贝拷贝所有属性,拷贝前后的两个对象互不影响

程序题

闭包函数

javascript
function outter(){
  var num = 10;
  function inner(){
    return console.log(num)
  }
  return inner()
}
outter()

手写浅拷贝

javascript
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)

手写深拷贝

javascript
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)

手写数组去重

javascript
const arr = [1,1,2,2,3,3,4,5]
const newarr = [...new Set(arr)]
console.log(newarr)

手写数组排序

javascript
const arr = [5,4,6,1,3,2]
const newarr = arr.sort((a,b)=>a-b)
console.log(newarr)

手写promise

javascript
var p = new Promise(function(reslove,reject){
  let flag = false
  if(flag){
    reslove('成功了')
  }else{
    reject('出错了')
  }
})

手写防抖

javascript
function debounce(fn,delay){
  return function(...args){
    let timer = null
    clearTimeout(timer)
    timer = setTimeout(()=>{
      fn.apply(this,args)
    },delay)
  }
}

手写节流

javascript
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

  1. Promise 三种状态分别是什么?状态有什么特性?
  2. then、catch、finally 各自作用与区别?
  3. Promise.all / race / allSettled / any 四者区别与适用场景?
  4. 为什么 try-catch 不能直接捕获 Promise 内部异步错误?
  5. 简述 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

  1. 手写简易版 Promise 核心逻辑(状态、resolve、reject、then)
  2. 封装一个通用的延时函数 sleep(ms) 返回 Promise
  3. 用 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. 计算所有元素的平方,得到新数组 [1, 4, 9, 16, 25]。
  2. 筛选出其中的偶数,得到 [2, 4]。

reduce求和与分组

  1. 计算数组 [10, 20, 30, 40] 的总和(不得使用循环)。
  2. 根据以下对象数组,按 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],要求:

  1. 去除重复元素,得到 [3, 1, 4, 5, 9, 2, 6](顺序保持第一次出现)。
  2. 将去重后的数组按升序排序。

扁平化与条件查找

有一个嵌套数组 [1, [2, [3, 4], 5], 6],请:

  1. 将其完全扁平化为 [1, 2, 3, 4, 5, 6]。
  2. 在扁平化后的数组中查找第一个大于 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 }
];

要求:

  1. 筛选出年龄 ≥ 18 且 active 为 true 的用户。
  2. 提取他们的姓名,并转换为大写。
  3. 按照姓名排序(字母顺序)。 最终输出:['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);
 });