面试官主要还是针对简历上的内容进行提问的,所以一定要把写在简历上的内容自己进行深挖并拓展不仅要有广度,更要有深度,以下是我的面试题以及自己整理出来的答案,有不同意见可以评论区交流一下,我写的答案仅供参考。
题目
带连接符的字符串转驼峰的方法
css实现一个宽度为页面宽度的正方形,几种方法
bootstrap实现栅格话布局原理
移动端适配方案
构造函数重写,指针指向,实例化构造函数的时候都做了什么
手写一个复选框列表的组件,实现全选和取消效果<check-list v-model="checkIds" :checkList="checkList"></check-list>
promise的原理手动实现一个简单的promise、 promise.all、 promise.race、promise实现一个原生ajax、promise实现一个图片加载
webpack了解多少,自己做了哪些配置
loader和plugins的区别
有没有手写过loader
nodejs
-
react
- this.setState是怎么实现异步的
- 宏任务/微任务
- hook
promise的原理,是怎么实现的(同7)
seo优化的过程是什么样的(自己项目上的,有兴趣可以了解一下,每一个操作的原因是什么, 为什么不直接用js,反而用jsp代替了(服务端渲染ssr)
es6常用的方法
有没有用canvas做过截图
函数式编程
柯里化?compose?
vue 组件 data为什么必须是函数?
设计模式的实现,工厂者模式、发布者订阅者模式手写代码说明
代码中有很多console.log,如何做到不改动代码的提前下,做到log内容的上报
正则实现首单享受<hightLight>50</highLight>元福利
转换成
首单享受<span class='highLight'>50</span>元福利-
flex实现以下布局
rem适配怎么设置0.01rem =1px
typescript
自己觉得印象最深的项目,然后都做了什么事情
-
跨端项目:如何实现与端之间的通信,
如何让客户端知道我需要拍照
另外canvas实现一个手动马赛克的效果 函数防抖和节流
31.笔试题:求连续子数组的最大和javascript实现继承的6种方式和其优缺点
jquery链式调用的实现方式
实现一个Array.filter
vuex的使用和原理
小程序是如何实现视图层和逻辑层的联系的
uniapp的跨端方案是如何实现的
单元测试怎么查看覆盖率的
V8引擎垃圾回收机制:导致内存泄漏的原因 -> 规避递归导致的内存泄漏:蹦床
A网站请求B网站的多个js文件,可以同时获取吗(HTTP2多路复用)
Set、WeakSet、Map、WeakMap的区别
内存中的变量是如何分配存储的
var和let的区别
查找链表的倒数第N个节点
flexible适配的原理,rem和em区别
this指针的理解和应用场景,构造函数中的this指针问题
jquery中的链式调用是怎么实现的
proxy相对于defineproperty的优势
jsBridge的回调,以及客户端实现
webpack的treeShaking与其他打包工具之间的差异
服务端渲染的深入了解,nodejs返回页面之后是如何加载其他的script和css资源的
call, apply, bind的区别
事件冒泡和捕获了解吗?先冒泡还是先捕获
axios做了哪些封装
http和https的区别,https相对于http的优点和缺点
http2相对于http1的优化
cookies和session的区别
浏览器缓存
vue的通信方式
vuex的常用的属性,多模块的情况下和单模块的异同
mvvm和mvc的区别
animation和transition的区别,以及如何知道这个动画执行完毕
position和transform的区别和优缺点
async返回什么,setTimeout和promise的执行顺序,为什么
输出结果是什么
var n = 0
function a() {
var n = 10
function b() {
n++
console.log(n)
}
b()
return b
}
var c = a()
c()
console.log(n)
64.js实现深度拷贝
Javascript的事件流模型都有什么?
promise 实现一个图片加载,完成loadImg
loadImg('/a.png').then( res=>{
***
})
300px div
内容一行内容居中显示多行居左显示打印输出
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');
}).then(function() {
console.log('promise3');
})
new Promise(function(resolve) {
console.log('promise4');
resolve();
}).then(function() {
console.log('promise5');
});
console.log('script end');
- 打印输出
var a = 10;
function a() { };
console.log(a);
(function () {
console.log(a)
a = 5
console.log(window.a)
var a = 20
})()
console.log(a)
- 父元素宽高未知,子元素图片的宽高未知,实现图片居中显示的多种方式(grid布局了解吗,margin和padding分别是相对于谁的)
- 多种方法实现数组的乱排序
- 多种方式实现去除数组的空元素
- 如何实现a==1&&a==2&&a==3(结合defineProperty和proxy来做,考察对数据劫持和隐式转换函数重写的理解)
- nextTick的实现原理(考察vue异步批量更新)
- 浏览器缓存读取规则:可以分成 Service Worker、Memory Cache、Disk Cache 和 Push Cache,那请求 的时候 from memory cache 和 from disk cache 的依据是什么,哪些数据什么 时候存放在 Memory Cache 和 Disk Cache 中?
- 原生操作dom的方法有哪些
- 求输出结果(字节跳动)
new Promise(function(resolve) {
for (var i = 0; i < 10; i++) {
resolve(i);
}
}).then(function(i) {
console.log(i);
});
new Promise(function(resolve) {
for (var i = 0; i < 10; i++) {
function a() {
resolve(i);
}
}
a();
}).then(function(i) {
console.log(i);
});
// 0
// 10
- 实现一个柯里化函数
// 实现 currying 函数,使得 curryingSum 函数输出正确
const currying = (func) => {
var args = Array.prototype.slice.call(arguments, 1) // 除却第一个参数
var curry = function () {
if (arguments.length === 0) {
return func.apply(this, args) // 无参数时直接返回求和的值
} else {
args = args.concat(Array.prototype.slice.call(arguments)) // 如果后续继续有参数,直接返回该函数
// console.log(args)
return curry
}
}
return curry
}
const sum = (...args) => args.reduce((prev, cur) => prev + cur, 0)
sum(1, 2, 3) // 6
const curryingSum = currying(sum)
console.log(curryingSum(1)(2)(3)())
console.log(curryingSum(1, 2)(3)())
看到题目之后先别着急看答案,自己思考一下
解答:
1. 带连接符的字符串转驼峰的方法 (如get-element-by-id)
- 方法1. 正则匹配(面试官想要的最优解)
let str = 'get-element-by-id'
let res = str.replace(/-\w/g, (a) => {
return a.toUpperCase()
}).replace(/-/g, '')
console.log(res)
- 方法2. 字符串分割拼接
let str = 'get-element-by-id'
function toCamelCase (str) {
let str1 = str.split('-')
for (let i = 1; i < str1.length; i++) {
str1[i][0].toUpperCase()
}
return str1.join('')
}
console.log(toCamelCase(str))
2. css实现一个宽度为页面宽度的正方形
- 方法1:vw
.child {
width: 50%;
height: 50vw;
background: #ccc;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
- 方法2:百分比
.child {
width: 50%;
height: 0;
padding-bottom:50%;
background: #ccc;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
- 方法3
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.child {
display: flex;
width: 50%;
height: 50vw;
background: yellow;
}
3. bootstrap实现栅格话布局原理
栅格化列的种类,一行根据百分比分为12列,当col相加大于12时,超出部分当作下一行展示
.col-xs-* 针对超小屏幕 手机(<768px)
.col-sm-* 小屏幕 平板 (≥768px)
.col-md-* 中等屏幕 桌面显示器 (≥992px)(栅格参数)
.col-lg-* 针对特大的(≥1200px)
通过媒体查询根据不同的屏幕适配对应的栅格化样式,添加对应的类,比如
/*超小设备(手机:小于768px)*/
@media(max-width:768px){
.col-xs-1{ width: 8.33333333%;}
.col-xs-2{ width: 16.66666667%;}
.col-xs-3{ width: 25%;}
.col-xs-4{ width: 33.33333333%;}
.col-xs-5{ width: 41.66666667%;}
.col-xs-6{ width: 50%;}
.col-xs-7{ width: 58.33333333%;}
.col-xs-8{ width: 66.66666667%;}
.col-xs-9{ width: 75%;}
.col-xs-10{ width: 83.33333333%;}
.col-xs-11{ width: 91.66666667%;}
.col-xs-12{ width: 100%;}
}
/*小型设备 (平板电脑:768px起)0*/
@media(min-width:768px){
.col-sm-1{ width: 8.33333333%;}
...
}
/*中型设备(台式电脑:992px起)*/
@media(min-width:992px){
.col-md-1{ width: 8.33333333%;}
...
}
/*大型设备(台式电脑:1200px起)*/
@media(min-width:1200px){
.col-lg-1{ width: 8.33333333%;}
...
}
4. 移动端适配方案
通过postcss-px-to-viewport插件实现px->vw的转化,安装插件之后进行如下配置
loaderOptions: { // css预设器配置项
postcss: {
plugins: [
require('postcss-px-to-viewport')({
unitToConvert: 'px',
viewportWidth: 750,
viewportHeight: 1334,
unitPrecision: 5,
propList: [
'*'
],
viewportUnit: 'vw',
fontViewportUnit: 'vw',
selectorBlackList: [],
minPixelValue: 1,
mediaQuery: false,
replace: true,
exclude: [/(\/|\\)(node_modules)(\/|\\)/]
})
]
},
stylus: {}
}
5. 实例化构造函数, 求输出结果
function A() {
this.a = 1
return {
a: 2,
b: 3
}
}
A.prototype.b = 4
A.prototype.c = 5
let newObj = new A()
console.log(newObj.a)
console.log(newObj.b)
console.log(newObj.c)
输出:
2
3
undefined
考察点:new一个构造函数时具体执行了什么操作?
- 在内存中新建一个空对象;
- this指向这个内存中的空对象;
- 根据定义的键值和传入的参数,依次给这个空对象添加上键值对;
- 返回这个新的对象
6. 手写一个复选框列表的组件,实现全选和取消效果<check-list v-model="checkIds" :checkList="checkList"></check-list>
考察点:v-model语法糖
父组件
<template>
<div class="list">
<input type="checkbox" v-model="chooseAll">全选
<check-list :checkIds="checkIds" :checkList="checkList" @update="arr => checkIds=arr"></check-list>
</div>
</template>
<script>
import CheckList from '@/components/CheckList'
export default {
name: 'list',
components: {
'check-list': CheckList
},
data () {
return {
chooseAll: false,
checkIds: [],
checkList: [{
id: 1,
name: '苹果'
}, {
id: 2,
name: '梨'
}, {
id: 3,
name: '橘子'
}]
}
},
watch: {
chooseAll () {
if (this.chooseAll) {
this.checkIds = this.checkList.map(item => { return item.id })
} else if (!this.chooseAll && this.checkIds.length === this.checkList.length) {
this.checkIds = []
}
},
checkIds () {
this.chooseAll = this.checkIds.length === this.checkList.length
}
}
}
</script>
子组件
<template>
<div class="hello">
<ul>
<li v-for="item in checkList" :key="item.id">
<input type="checkbox" v-model="ids" :value="item.id" @change="$emit('update', ids)">{{item.name}}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'CheckList',
props: {
checkList: Array,
checkIds: Array
},
data () {
return {
ids: []
}
},
watch: {
checkIds () {
console.log(this.checkIds)
this.ids = this.checkIds
}
}
}
</script>
7. 手动实现一个简单的promise, promise.all/promise.race
promise
class Promise1 {
constructor (executor) {
this.state = 'pending'
this.result = null
this.reason = null
const resolve = value => {
this.state = 'fulfilled'
this.result = value
}
const reject = reason => {
this.state = 'rejected'
this.reason = reason
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then (onFullfilled, onRejected) {
if (this.state === 'fulfilled') {
onFullfilled(this.result)
}
if (this.state === 'rejected') {
onRejected(this.reason)
}
}
}
const a = new Promise1((resolve, reject) => {
resolve('888888')
// reject('888888')
})
a.then(data => {
console.log(data)
})
promise.all
Promise1.all = function(promiseArr) {
let length = promiseArr.length
let result = []
let hasErr = false
return new Promise1((resolve, reject) => {
for (i = 0; i < length; i++) {
promiseArr[i].then(data => {
result[i] = data
if (i === length) resolve(result)
}, error => {
!hasErr && reject(error)
hasErr = true
})
}
})
}
promise.race
Promise1.race = function(promiseArr) {
let hasValue = false
let hasErr = false
return new Promise1((resolve, reject) => {
for (let i = 0; i < promiseArr.length; i++) {
promiseArr[i].then(data => {
if (!hasValue && !hasErr) resolve(data)
hasValue = true
}, error => {
if (!hasValue && !hasErr) reject(error)
hasErr = true
})
}
})
}
promise实现一个原生的ajax请求
let getJSON = function () {
let promise = new Promise((resolve, reject) => {
let client = new XMLHttpRequest()
client.open('get', url)
client.onreadystatechange = handler
clent.responseType = 'json'
client.setRequestHeader('Content-Type', 'application/json')
client.send()
function handler () {
if (this.readyState === 4) {
if (this.status === 200) {
resolve(this.response)
} else {
reject(new Error(this.statusText))
}
}
}
})
return promise
}
getJSON('/getJson').then((data) => {
console.log(data)
}, (err) => {
consoel.log('出错了')
})
给定一张图片的url,通过promise实现一个图片加载
const url1 = '***.png'
const url2 = '***2.png'
loadImg(url1).then(img=>{
console.log(img.width)
return img
}).then(img=>{
console.log(img.height)
return loadImg(url2)
}).then(img2=>{
console.log(img2.width)
return img2
}).then(img2=>{
console.log(img2.height)
})
.catch(err=>{
console.log(err)
})
- webpack了解多少,自己做了哪些配置
- loader和plugins的区别
- 有没有手写过loader
- nodejs
- react
- this.setState是怎么实现异步的
- 宏任务/微任务
- hook
- promise的原理,是怎么实现的(同7)
- seo优化的过程是什么样的(自己项目上的,有兴趣可以了解一下,每一个操作的原因是什么, 为什么不直接用js,反而用jsp代替了(服务端渲染ssr)
- es6常用的方法
- seo优化
- 设计模式的实现,工厂者模式、发布者订阅者模式手写代码说明
- 一个对象作为特定任务或是另一对象的活动的观察者,并且在这个任务或活动发生时,通知观察者。观察者也被叫作订阅者(Subscriber),它指向被观察的对象,既被观察者(Publisher 或 subject)。当事件发生时,被观察者(Publisher)就会通知观察者(subscriber)。
// 发布者订阅者模式
let observer = {
callbacks: [],
add: function (fn) {
this.callbacks.push(fn)
},
trigger: function () {
this.callbacks.forEach((fn) => {
fn()
})
}
}
observer.add(function() {
console.log('我是订阅者1')
})
observer.add(function() {
console.log('我是订阅者2')
})
observer.trigger()
- 工厂模式:所谓工厂模式就是像工厂一样重复的产生类似的产品,工厂模式只需要我们传入正确的参数,就能生产类似的产品;
工厂模式根据抽象程度依次分为简单工厂模式、工厂方法模式、抽象工厂模式;
三种模式的代码实现:https://www.cnblogs.com/dengyao-blogs/p/11646810.html
- javascript实现继承的6种方式和其优缺点
https://blog.csdn.net/weixin_38343894/article/details/79214821 - 在使用jQuery库的时候,是可以连续调用多个方法的,这是怎么实现的呢
// 方法1,通过对象属性的方式
let A = {
name: 'hello',
get: function () {
console.log(this.name)
return this
},
set: function () {
console.log(this.name)
return this
}
}
A.get().set()
// 方法2,通过函数的形式
function A () {
this.name = 'wyn'
}
A.prototype.get = function () {
console.log(this.name)
return this
}
A.prototype.set = function () {
this.name = 'www'
return this
}
let b = new A()
- 实现一个Array.filter
Array.prototype.filter = Array.prototype.filter || function (func) {
let arr = this
let r = []
for (let i = 0; i < arr.length; i++) {
if (func(arr[i])) {
r.push(arr[i])
}
}
return r
}
vuex的使用和原理
-
uniapp的跨端方案
uin-app 和原生开发是有很大差别的,至少在性能和需求覆盖度上会差很多。uin-app 框架使用的其实是 cordova 的进阶版,也就是把 web 代码打包到本地,本地实质上还是通过 WebView 运行,那性能的瓶颈不言而喻。另外 uni-app 支持使用 Weex 框架拓展性能,本质上是通过桥的功能把 Vue 控件映射为原生控件进行渲染,效果和 react-native 差不多,虽然性能有所提升,但是和原生相比差距还是有的。
jsBridge的回调,以及客户端实现
webpack的treeShaking与其他打包工具之间的差异
服务端渲染的深入了解,nodejs返回页面之后是如何加载其他的script和css资源的
事件冒泡和捕获了解吗?先冒泡还是先捕获
axios做了哪些封装
-
http和https的区别,https相对于http的优点和缺点
http2相对于http1的优化
[cookies和session的区别]s(https://www.cnblogs.com/l199616j/p/11195667.html)
浏览器缓存
vue的通信方式
vuex的常用的属性,多模块的情况下和单模块的异同
mvvm和mvc的区别
animation和transition的区别,以及如何知道这个动画执行完毕
position和transform的区别和优缺点
async返回什么,setTimeout和promise的执行顺序,为什么