前段时间总结的部分面试题,有需要的可以看下哈~~😁
什么是构造函数
用 new 关键字来调用的函数,称为构造函数。构造函数首字母一般大写
function Person4() {
this.gender = '男';
// return { gender: '中性' };
}
var p4 = new Person4();
console.log(p4.gender); // '中性'
什么是继承
继承指的是一个对象可以共享父级对象的一些属性。
什么是原型链
对于对象而言,每个 JS 对象一定对应一个原型对象,并从原型对象继承属性和方法。对象proto属性的值就是它所对应的原型对象。对象的proto指向自己构造函数的 prototype。所以对象的原型链就是obj.proto.proto__....。
function Person() {
return { };
}
var p = new Person();
console.log(p)
// {}
[[Prototype]]: Object
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
__proto__: (...)
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()
对于函数而言,只有函数才有 prototype 属性,Person.prototype 是一个对象,并且有两个属性, 一个是 constructor 指向其构造函数 Person, 一个是 proto 属性:是一个对象,指向上一层的原型。
console.log(Person.prototype)
// {constructor: ƒ}
// constructor: ƒ Person()
// [[Prototype]]: Object
所有的对象会一层层往上找原型,最终点是 Object,而 Object 的上一层原型就是 null 了。
this的指向
- 箭头函数的 this 是在创建它时外层 this 的指向
- 当使用 new 关键字调用函数时,函数中的 this 一定是 JS 创建的新对象(箭头函数不能当做构造函数)
cookie、localStorage和sessionStorage 三者之间的区别
- cookie 可设置失效时间/4KB左右/每次都会携带在HTTP头中/只能保存字符串类型/同域名不同页面的数据共享
- localStorage 除非被手动清除,否则将会永久保存/可以保存5MB的信息。/可以用来夸页面传递参数
- sessionStorage 仅在当前网页会话下有效,关闭页面或浏览器后就会被清除/可以保存5MB的信息。
ES6常用语法
- 解构赋值
let [a,b] = [1,2]
let {a,b} = {a:1,b:2}
- 模板字符串
let str = `${name}的女朋友`;
- 去除空格 .trim()
let str = ' 10 10 ';
console.log(str); // ' 10 10 '
console.log(str.trim()); // '10 10'
// 如果要去除所有空格
let str = ' 10 10 ';
console.log(str.replace(/ /g, '')); // 1010
- 箭头函数
(1)箭头函数没有自己的`this`对象,内部的`this`就是定义时上层作用域中的`this`。。
(2)不可以当作构造函数,也就是说,不可以对箭头函数使用`new`命令,否则会抛出一个错误。
(3)不可以使用`arguments`对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用`yield`命令,因此箭头函数不能用作 Generator 函数。
- 扩展运算符 ...
let obj = {...obj1}
let arr = [...arr1,...arr2] //合并数组 对象类似
[...'hello']
// [ "h", "e", "l", "l", "o" ]
find() ,findIndex() 查找数据/返回下标
includes() 方法返回一个布尔值,表示某个数组是否包含给定的值,返回布尔值。
.flat() 一维数组转换
let arr = [1,2,[3,4],[5,6,[7,8]]]
console.log(arr.flat(1)); //[1, 2, 3, 4, 5, 6, Array(2)]
console.log(arr.flat(2)); //[1, 2, 3, 4, 5, 6, 7, 8]
数组去重方法
- 利用ES6 Set去重(ES6中最常用)
Array.from(new Set(arr))
- 利用for嵌套for,然后splice去重(ES5中最常用)
var arr = [1, 1, 8, 8, 12, 12, 15, 15, 16, 16];
function unlink(arr) {
for (var i = 0; i < arr.length; i++) { // 首次遍历数组
for (var j = i + 1; j < arr.length; j++) { // 再次遍历数组
if (arr[i] == arr[j]) { // 判断连个值是否相等
arr.splice(j, 1); // 相等删除后者
j--;
}
}
}
return arr
}
console.log(unlink(arr));
- 利用includes
var arr = [1, 1, 8, 8, 12, 12, 15, 15, 16, 16];
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array =[];
for(var i = 0; i < arr.length; i++) {
if( !array.includes( arr[i]) ) {//includes 检测数组是否有某个值
array.push(arr[i]);
}
}
return array
}
console.log(unique(arr))
数组排序
- sort()
var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return a - b});
// 1,5,10,25,40,100 升序 反之 b-a 降序
类型判断
基本数据类型:Undefined、Null、Boolean、Number、String,Symbol
引用数据类型 :Object
let bool = true;
let num = 1;
let str = 'abc';
let und= undefined;
let nul = null;
let arr = [1,2,3,4];
let obj = {name:'xiaoming',age:22};
let fun = function(){console.log('hello')};
let s1 = Symbol();
- typeof判断
console.log(typeof bool); //boolean
console.log(typeof num);//number
console.log(typeof str);//string
console.log(typeof und);//undefined
console.log(typeof nul);//object
console.log(typeof arr);//object
console.log(typeof obj);//object
console.log(typeof fun);//function
console.log(typeof s1); //symbol
- instanceof判断
console.log(bool instanceof Boolean);// false
console.log(num instanceof Number);// false
console.log(str instanceof String);// false
console.log(und instanceof Object);// false
console.log(nul instanceof Object);// false
console.log(arr instanceof Array);// true
console.log(obj instanceof Object);// true
console.log(fun instanceof Function);// true
console.log(s1 instanceof Symbol);// false
- constructor判断
null、undefined没有construstor方法,因此constructor不能判断undefined和null。 但是他是不安全的,因为contructor的指向是可以被改变。
console.log(bool.constructor === Boolean);// true
console.log(num.constructor === Number);// true
console.log(str.constructor === String);// true
console.log(arr.constructor === Array);// true
console.log(obj.constructor === Object);// true
console.log(fun.constructor === Function);// true
console.log(s1.constructor === Symbol);//true
- Object.prototype.toString.call 判断
console.log(Object.prototype.toString.call(bool));//[object Boolean]
console.log(Object.prototype.toString.call(num));//[object Number]
console.log(Object.prototype.toString.call(str));//[object String]
console.log(Object.prototype.toString.call(und));//[object Undefined]
console.log(Object.prototype.toString.call(nul));//[object Null]
console.log(Object.prototype.toString.call(arr));//[object Array]
console.log(Object.prototype.toString.call(obj));//[object Object]
console.log(Object.prototype.toString.call(fun));//[object Function]
console.log(Object.prototype.toString.call(s1)); //[object Symbol]
vue v-on绑定多个事件
<div v-on="{mousedown:onInput,mouseup:onFocus,click:onBlur}"></div>
防抖和节流
-
防抖(debounce)
所谓防抖,就是指触发事件后 n 秒后才执行函数,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
防抖函数分为非立即执行版和立即执行版,此处为 非立即执行版
function debounce(func, wait) {
let timeout;
return function () {
const context = this;
const args = [...arguments];
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args)
}, wait);
}
}
-
节流(throttle)
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。 节流会稀释函数的执行频率。
一般有两种方式可以实现,分别是时间戳版和定时器版,此处为 定时器版
function throttle(func, wait) {
let timeout;
return function() {
let context = this;
let args = arguments;
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
前端性能优化
- 使用服务端渲染
- 静态资源使用 CDN(前端只需要引入,静态资源放在这url下面 然后以CDN 厂商哪里指定这个URL)
- 使用字体图标 iconfont 代替图片图标
- 善用缓存,不重复加载相同的资源
- 降低图片质量( webpack打包配置)
- 尽可能利用 CSS3 效果代替图片
- 使用 webp 格式的图片
WebP 的优势体现在它具有更优的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量;同时具备了无损和有损的压缩模式、Alpha 透明以及动画的特性,在 JPEG 和 PNG 上的转化效果都相当优秀、稳定和统一。
- 使用 requestAnimationFrame 来实现视觉变化
如果采取 setTimeout 或 setInterval 来实现动画的话,回调函数将在帧中的某个时点运行,可能刚好在末尾,而这可能经常会使我们丢失帧,导致卡顿。
- 降低 CSS 选择器的复杂性
怎样理解 Vue 的单向数据流?
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。
或者通过 .sync
去实现双向通信
// 子组件
props:{
msg:String
}
...
computed:{
msgData:{
get(){
return this.msg
},
set(val){
this.$emit('update:msg',val)
}
}
}
//父组件
<children :msg.sync="data" />
父组件可以监听到子组件的生命周期吗?
可以
// Parent.vue
<Child @mounted="doSomething"/>
// Child.vue
mounted() {
this.$emit("mounted");
}
组件中 data 为什么是一个函数?
因为组件是用来复用的,且 JS 里对象是引用关系,如果组件中 data 是一个对象,那么这样作用域没有隔离,子组件中的 data 属性值会相互影响,如果组件中 data 选项是一个函数,那么每个实例可以维护一份被返回对象的独立的拷贝,组件实例之间的 data 属性值不会互相影响;而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。
Vue 组件间通信有哪几种方式?
props / $emit
适用 父子组件通信
ref 与 $parent / $children
适用 父子组件通信
EventBus ($emit / $on)
适用于 父子、隔代、兄弟组件通信
Vue 是如何实现数据双向绑定的?
1.实现一个监听器 Observer:对数据对象进行遍历,包括子属性对象的属性,利用 Object.defineProperty() 对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。
2.实现一个解析器 Compile:解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,调用更新函数进行数据更新。
3.实现一个订阅者 Watcher:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。
4.实现一个订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。
虚拟 DOM 实现原理?
虚拟dom的比较,就是找出新节点(vnode)和旧节点(oldVnode)之间的差异,然后对差异进行打补丁(patch)
虚拟 DOM 的实现原理主要包括以下 3 部分:
- 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
- diff 算法 — 比较两棵虚拟 DOM 树的差异;
- pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
Vue 中的 key 有什么作用?
key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速。
你有对 Vue 项目进行哪些优化?
- 代码层面的优化
v-if 和 v-show 区分使用场景
computed 和 watch 区分使用场景
v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
长列表性能优化
事件的销毁
图片资源懒加载
路由懒加载
第三方插件的按需引入
优化无限列表性能
服务端渲染 SSR or 预渲染
- Webpack 层面的优化
Webpack 对图片进行压缩
减少 ES6 转为 ES5 的冗余代码
提取公共代码
模板预编译
提取组件的 CSS
优化 SourceMap
构建结果输出分析
Vue 项目的编译优化
vue有哪些优势
- 轻量级框架
- 简单易学
- 双向数据绑定
- 组件化开发
- 视图,数据,结构分离
- 虚拟DOM
- 提供了丰富的
api
供开发者使用(computed,watch,$set,#parent,生命周期钩子,mixin等
)
为什么要用vuex而不直接定义全局变量
- 方便集中管理
- 不会造成命名污染
- 提供统一的方法修改数据