文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
真题模拟
var、let、const 区别
- var 是 es5 语法,let const 是 es6 语法;var 有变量提升
- var let 是变量,可修改;const 是常量,不可修改
- let const 有块级作用域,var 没有
typeof 能判断哪些类型
- string、number、boolean、undefined、symbol
- object (typeof null === 'object')
- function
列举强制类型转换和隐式类型转换
- 强制类型转换:parseInt、parseFloat、toString 等
- 隐式类型转换:if、逻辑运算、==、+ 拼接字符串
手写深度比较,模拟 lodash isEqual
function isObject(obj) {
return typeof obj === "object" && obj !== null;
}
function isEqual(obj1, obj2) {
if (!isObject(obj1) || !isObject(obj2)) {
// 值类型(注意:参与 equal 的一般不会是函数)
return obj1 === obj2;
}
if (obj1 === obj2) {
return true;
}
// 两个都是对象或数组,而且不相等
// 1. 先取出 obj1 和 obj2 的 keys,比较个数
const obj1Keys = Object.keys(obj1);
const obj2Keys = Object.keys(obj2);
if (obj1Keys.length !== obj2Keys.length) {
return false;
}
// 2. 以 obj1 为基础,和 obj2 依次递归比较
for (let key in obj1) {
// 比较当前 key 的 val
const res = isEqual(obj1[key], obj2[key]);
if (!res) {
return false;
}
}
// 3. 全相等
return true;
}
split() 和 join() 的区别
数组的 pop、push、shift、unshift 分别是什么
- 功能是什么
- 返回值是什么
- 是否会对原数组造成影响
// const arr = [10, 20, 30, 40]
// // pop
// const popRes = arr.pop()
// console.log(popRes, arr)
// // shift
// const shiftRes = arr.shift()
// console.log(shiftRes, arr)
// // push
// const pushRes = arr.push(50) // 返回 length
// console.log(pushRes, arr)
// // unshift
// const unshiftRes = arr.unshift(5) // 返回 length
// console.log(unshiftRes, arr)
数组的 API,有哪些是纯函数
// // 纯函数:1. 不改变源数组(没有副作用);2. 返回一个新的数组
// const arr = [10, 20, 30, 40]
// // concat
// const arr1 = arr.concat([50, 60, 70])
// // map
// const arr2 = arr.map(num => num * 10)
// // filter
// const arr3 = arr.filter(num => num > 25)
// // slice
// const arr4 = arr.slice()
数组的 API,有哪些是非纯函数
// // push pop shift unshift
// // forEach
// // some every
// // reduce
// splice
数组 slice 和 splice 区别
- slice-切片 splice-剪接
- 参数和返回值
- 是否是纯函数
// const arr = [10, 20, 30, 40, 50]
// // slice 纯函数
// const arr1 = arr.slice()
// const arr2 = arr.slice(1, 4) // startIndex endIndex
// const arr4 = arr.slice(-3) // 从最后开始截取
var myFish = ["angel", "clown", "drum", "mandarin", "sturgeon"];
var removed = myFish.splice(3, 1); // 从索引 3 位置开始删除 1 个元素
var myFish = ["angel", "clown", "mandarin", "sturgeon"];
var removed = myFish.splice(2, 0, "drum", "guitar"); // 从索引 2 位置开始添加两个元素
[10, 20, 30].map(parseInt) 返回结果是什么
[10, 20, 30].map((num, index) => {
return parseInt(num, index);
});
答案:[10, NaN, NaN]
ajax 请求 get 和 post 的区别
- get 一般用于查询操作,post 一般用于用户提交操作
- get 参数拼接在 url 上,post 放在请求体内
- post 易于防止 xsrf
函数 call 和 apply 的区别
事件代理是什么
闭包是什么?有什么特性?有什么负面影响
- 回顾作用域和自由变量
- 回顾闭包应用场景:作为参数被传入,作为返回值被返回
- 回顾:自由变量的查找,要在函数定义的地方(而不是执行的地方)
- 影响:变量会常驻内存,得不到释放(不一定导致内存泄漏)
如何阻止事件冒泡和默认行为
- event.stopPropagation()
- event.preventDefault()
查找、添加、删除、移动 DOM 节点的方法
- 回顾之前内容
如何减少 DOM 操作
- 缓存 DOM 查询结果
- 多次 DOM 操作合并到一次插入
解析 jsonp 的原理,为何它不是真正的 ajax
- 浏览器的同源策略(服务端没有同源策略) 和跨域
- 哪些 html 标签能绕过跨域
- jsonp 的原理
window.load 和 DOMContentLoaded 的区别
== 和 === 的不同
- == 会尝试类型转换
- === 严格相等
- 哪些场景才用 == 如:if (null == undefined)
函数声明和函数表达式的区别
- 函数声明 function fn() {...}
- 函数表达式 const fn = function () {...}
- 函数声明会有变量提升,函数表达式没有
new Object() 和 Object.create() 的区别
- {} 等同于 new Object(),原型是 Object.prototype
- Object.create(null) 没有原型
- Object.create({...}) 可指定原型
关于 this 的场景题
答案:1 window
关于作用域和自由变量的场景题
答案:4
答案:100 10 10
判断字符串以字母开头,后面字母数字下划线,长度 6-30
答案:/^[a-zA-Z]\w{5, 29}$/ \w 字母数字下划线 . 字符。
// 邮政编码
/\d{6}/
// 小写英文字母
/^[a-z]+$/
// 英文字母
/^[a-zA-Z]+$/
// 日期格式 2019.12.1
/^\d{4}-\d{1,2}-\d{1,2}$/
// 用户名
/^[a-zA-Z]\w{5, 17}$/
// 简单的 IP 地址匹配
/\d+\.\d+\.\d+\.\d+/
手写字符串 trim 方法,保证浏览器兼容性
如何获取多个数字中的最大值
如何用 js 实现继承
- class 继承
- prototype 继承
如何捕获 js 程序中的异常
什么是 JSON
- 是一种数据格式,本质是一段字符串
- 和 js 对象结构一致,对 js 语言更好
- JSON.parse JSON.stringify
获取当前页面的 url 参数
- 传统方式 location.search
- 新 API,URLSearchParams
function query(name) {
const search = location.search.substr(1); // 类似 array.slice(1)
// search: 'a=10&b=20&c=30'
const reg = newRegExp(`(^|&)${name}=([^&]*)(&|$)`, "i");
const res = search.match(reg);
if (res === null) {
return null;
}
return res[2];
}
将 url 参数解析为 JS 对象
手写数组 flatern,考虑多层级
function flat(arr) {
// 验证 arr 中,还有没有深层数组
const isDeep = arr.some((item) => item instanceof Array);
if (!isDeep) {
return arr;
}
const res = Array.prototype.concat.apply([], arr);
return flat(res);
}
数组去重
- 传统方式,遍历元素挨个比较、去重
- 使用 Set
function unique(arr) {
const res = [];
arr.forEach((item) => {
if (res.indexOf(item) === -1) {
res.push(item);
}
});
return res;
}
function unique(arr) {
const set = newSet(arr);
return [...set];
}
手写深拷贝
介绍一下 RAF requestAnimatioFrame
- 要想动画流畅。更新频率要 60 帧/s,即 16.67ms 更新一次视图
- setTimeout 要手动控制频率,RFA 浏览器会自动控制
- 后台标签或隐藏 iframe 中,RFA 会暂停,而 setTimeout 依然执行
// 3s 把宽度从 100px 变为 640px ,即增加 540px
// 60 帧/s ,3s 180 帧 ,每次变化 3px
const $div1 = $("#div1");
let curWidth = 100;
const maxWidth = 640;
// // setTimeout
// function animate() {
// curWidth = curWidth + 3
// $div1.css('width', curWidth)
// if (curWidth < maxWidth) {
// setTimeout(animate, 16.7) // 自己控制时间
// }
// }
// animate()
// RAF
function animate() {
curWidth = curWidth + 5;
$div1.css("width", curWidth);
if (curWidth < maxWidth) {
window.requestAnimationFrame(animate); // 时间不用自己控制
}
}
animate();
前端性能如何优化?一般从几个地方考虑
Map 和 Set 有序和无序
有序:顺序,增删查改慢(数组)
无序:散乱,增删查改快(对象)
Map 和 Object 的区别
- API 不同,Map 可以以任意类型为 key
- Map 是有序结构(重要)
- Map 操作同样很快
Set 和数组的区别
- API 不同
- Set 元素不能重复
- Set 是无序结构,操作很快
weakMap 和 weakSet
- 弱引用,防止内存泄漏
- weakMap 只能用对象作为 key,weakSet 只能用对象作为 value
- 没有 forEach 和 size,只能用 add delete has
数组 reduce 用法
- 求和
constarr = [10, 20, 30, 40, 50];
constres = arr.reduce((sum, curVal) => sum + curVal, 0);
- 计数
constarr = [10, 20, 30, 40, 50, 10, 20, 30, 20];
constn = 30;
constcount = arr.reduce((count, val) => {
return val === n ? count + 1 : count;
}, 0);
- 输出字符串
constarr = [
{ name: "张三", age: "20" },
{ name: "李四", age: "21" },
{ name: "小明", age: "22" },
];
conststr = arr.reduce((s, item) => {
return `${s}${item.name} - ${item.age}\n`;
}, "");
console.log(str);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论