es5原型继承的例子
// 组合继承function Father(value){ this.val = value}Father.prototype.getVal = function(){ return this.val}function Son(value){ Father.apply(this,arguments)}Son.prototype = new Father() var son = new Son(1234)console.log(son)// 寄生组合继承function Father(value){ this.val = value}Father.prototype.getVal = function(){ console.log(this.val)}function Son(){ Father.apply(this,arguments)}Son.prototype = Object.create(Father.prototype)Son.prototype.constructor = Son// Son.prototype = Object.create(Parent.prototype,{ // constructor:{ // value:Son,// enumerable:false,// writeable:true,// configurable:true// }// })//es6的写法 class Person { constructor(value) { this.val = value } get() { console.log(this.val) } } class son extends Person { constructor(value,name) { super(value) this.name = name } }复制代码
手写promise
const PENDING = 'pedeing' const RESOLVED = 'resolved' const REJECTED = 'rejected' function myPromise(fn) { const that = this that.state = PENDING that.value = null that.reslovedCallbacks = [] that.rejectedCallbacks = [] function resolve(value) { if (that.state === PENDING) { that.state = RESOLVED that.value = value // 完整then里面的第一个回调 that.reslovedCallbacks.map(thenResolve => thenResolve(that.value)) } } function reject(value) { if (that.state === PENDING) { that.state = REJECTED that.value = value // 完整then里面的第一个回调 that.rejectedCallbacks.map(thenReject => thenReject(that.value)) } } fn(resolve, reject) } myPromise.prototype.then = function(onFullfilled, onRejected){ const that = this onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : v => v onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r } if(that.state === PENDING){ that.reslovedCallbacks.push(onFullfilled) that.rejectedCallbacks.push(onRejected) } if(that.state === RESOLVED){ onFullfilled(that.value) } if(that.state === REJECTED){ onRejected(that.value) } }复制代码
原生XHR
var xhr = new XMLHttpRequest() xhr.open('GET','api',false) xhr.onreadystatechange = function(){ if(xhr.readyState === 4){ if(xhr.status === 200){ } } } xhr.send(null)复制代码
原生实现事件代理
function bindEvent(elem, type, selecter, fn) { if (!fn) { fn = selecter selecter = null } elem.addEventListener(type, (e) => { var target if (selecter) { target = e.target if (target.matches(selecter)) { fn.call(target, e) } } else { fn(e) } }) }复制代码
节流和防抖
1、防抖就是控制函数在高频触发的状态下,在最后一次事件触发后延迟一定时间执行
var debounce = function(time , func){ let lastTimer = 0 return function(...args){ clearTimeout(lastTimer) lastTimer = setTimeout(()=>{ func.apply(this,args) },time) }}复制代码
2、节流就是在高频请求中,将请求控制在时间范围之外,以减少请求次数
var throttle = function(func, time){ let lastTime = 0 return function(...args){ let now = +new Date() if(now-lastTime > time){ lastTime = now func.apply(this,args) } }}复制代码
手动实现前端路由
function Router(){ this.currentUrl=''; this.routes={};}Router.prototype.route = function(path,callback){ this.routes[path] = callback || function(){}}Router.prototype.refresh = function(){ this.currentUrl = location.hash.slice(1) || '/'; this.routes[this.currentUrl]();}Router.prototype.init = function(){ window.addEventListener('load',this.refresh.bind(this),false); window.addEventListener('hashchange',this.refresh.bind(this),false); // console.log(location.hash) // if(location.hash.slice(1)!=='/') // location.hash = '#/';} // hash hashChage// history pushState replaceState复制代码
vue实现数据响应式的原理
vue在2.0时代使用object.definedProperty()实现数据的响应,通过此函数监听get() 和 set() 事件,3.0时代将采用proxy实现,一下是代码
function observe(obj){ // 边界 if(!obj || typeof obj !== 'object') return Object.keys(obj).forEach(key => { definedReacted(obj,key,obj[key]) })}function definedReacted(obj,key,value){ observe(value) Object.definedProperty(obj,key,{ // 可枚举 enumerabeke:true, //可配置 configurable:true, get:()=>{ console.log(value) return value }, set:(newValue)=>{ console.log(newValue) val = newValue } })}function observer(obj){ // 递归边界 if(!obj || typeof obj !== 'object'){ return } Object.keys(obj).forEach((item,index,arr)=>{ defineReactive(obj,item,obj[item]) observer(obj[item]) })}function defineReactive(data,key,val){ Object.defineProperty(data,key ,{ enumerable:true, configurale:true, get:function(){ // 需要在这里添加订阅者 return val }, set:function(newValue){ val = newValue console.log('属性'+key+'被监听了'+'现在的值为'+newValue) // 在这里通知订阅者去更新视图 } })}var library = { book1: { name: '' }, book2: ''};observer(library)library.book1.name = 'vue权威指南'; // 属性name已经被监听了,现在值为:“vue权威指南”library.book2 = '没有此书籍';复制代码
两个数不使用四则运算得出和
function sum(a, b) { if (a == 0) return b if (b == 0) return a let newA = a ^ b // 获得个数值 let newB = (a & b) << 1 // 获得进位的数值 return sum(newA, newB) // 最后执行自己 }复制代码
冒泡排序
function isArray(array) { if (Object.prototype.toString.call(array) !== '[object Array]') { return array } } function swap(array, left,right) { var temp = array[left] array[left] = array[right] array[right] = temp } function bubble(arr) { isArray(arr) for (let i = arr.length - 1; i > 0; i--) { for (let j = 0; j < i; j++) { if (arr[j] > arr[j + 1]) swap(arr,j,j+1) } } return arr }复制代码
插入排序
function insert(array){ isArray(array) for(let i = 0 ;i=0&&array[j]>array[j+1];j--){ swap(array,j,j+1) } } return array}复制代码
选择排序
const choose = (arr) => { isArray(arr) for (let i = 0; i < arr.length - 1; i++) { let minIndex = i for (let j = i + 1; j < arr.length; j++) { minIndex = arr[j] < arr[minIndex] ? j : minIndex } if (i !== minIndex) { swap(arr, i, minIndex) } } return arr}复制代码
快速排序
// 阮一峰版本function quicksort(arr){ isArray(arr) if(arr.length<=1) return arr // const pivotIndex = Math.floor(Math.random()*arr.length) const pivotIndex = Math.floor(arr.length/2) const pivot = arr.splice(pivotIndex,1)[0] console.log(pivot,arr) const left = [] const right = [] for(let i = 0; ipivot){ right.push(arr[i]) }else{ left.push(arr[i]) } } return quicksort(left).concat([pivot],quicksort(right))}console.log(quicksort([2,4,1,88,2,5,90,564,32]))复制代码
手写call apply bind
let a = { name: 'leolei', fn: function (a, b) { console.log(this.name + a + b) }}const b = { name: 'cuisiyao'}Function.prototype.test = function (){ // 查看在prototype上添加方法 在调用时this是什么 console.log(this === a.fun.__proto__)}Function.prototype.Mycall = function () { if (typeof this === 'Function') { throw new TypeError('Error') } // 处理没有参数的默认情况 const context = arguments[0] || window console.log(this) context.fn = this const args = [...arguments].slice(1) console.log(args) const results = context.fn(...args) delete context.fn return results}Function.prototype.Myapply = function () { if (typeof this === 'Function') { throw new TypeError('Error') } const context = arguments[0] || window console.log(this) context.fn = this const args = arguments[1] console.log(args) const results = context.fn(...args) delete context.fn return results}Function.prototype.Mybind = function () { const context = arguments[0] || window const args1 = [...arguments].slice(1) const _this = this return function F(...args) { // 处理new function 的情况 if (this instanceof F) { return new _this(...args, ...args1) } return _this.Myapply(context, args.concat(args1)) }}a.fn.Mycall(b, 123, 456)a.fn.Myapply(b, [123, 456])// 当方法执行a.fn.Mybind(b, 123, 456)()a.fn.Mybind(b)(123, 456)a = { name: 'leolei', fn: function (a, b) { console.log(a + b) }}// 使用new执行new a.fn(123, 456)const test = new (a.fn.Mybind(b))(123, 456)复制代码
讲述一个new的过程
- 先创建一个空的obj
- 然后将需要构造的函数的绑定到空对象的obj原型原型上
- 在新建空对象的环境下执行构造函数,绑定this为这个空对象
- 返回this,并确保this为Object
function creat(){ const obj = {} const con = [].shift.call(arguments) obj.__proto__ = con const results = con.aplly(obj,arguments) return results instanceof Object ? results : obj}复制代码
常见的浏览器安全漏洞
- XSS攻击,分为两种。
- 一种是持久行的,持久型的XSS攻击主要是通过可执行的网页代码,将数据写到后台数据库中,比如评论时写入
<script>aler(1)</script>
,将此评论注入到数据库中,如果不做处理,页面在访问时会受到攻击。 - 第二种非持久型的,主要通过导航栏工具
http://www.domain.com?name=<script>alert(1)</script>
. 解决方案:1. 一般采用转义字符来解决,比如转义<
为<
。
- 一种是持久行的,持久型的XSS攻击主要是通过可执行的网页代码,将数据写到后台数据库中,比如评论时写入
- CSRP 跨站伪造请求。
- 当用户登录A页面时,已登录网站,未关闭,此时存在了cookie。用户在此时打开了另外一个攻击网站B,B盗取A的cookie后对A页面的后台进行请求,并攻击。
- 解决方案:在http头中设置SameSite,让cookie不随跨域请求发送。验证refrer字段 判断 请求来源,禁止第三方请求发送。使用token通过服务器验证用户登录是否有效。
- 点击劫持。解决方案,在响应头设置X—FRSME—OPTIONS。
- 中间人攻击 容易出现在公用产所的 wifi,解决方案就是使用https协议。
vue路由守卫
全局守卫
beforeEnter(to,from,next)
afterEnter(....)
beforeResolve
路由独享守卫
beforeEnter
组件内的守卫
beforeRouteEnter
beforeRouteUpdata
beforeRouteLeave
完整的解析过程
- 导航被触发
- 上一个导航的组件里调用beaforeRouteLeave
- 激活全局beforeEnter
- 如果是重用组件,那就会调用beforeRouteUpdata
- 然后进入路由配置的beforEnter
- 解析异步路由组件
- 调用全局的beforeResolve
- 导航被确认
- 调用全局的afterEnter
- 触发更新dom
- 用创建好的实例调用beforeRouteEnter,并把组件实例作为使用next的回调
设计模式
- 工厂模式 隐藏对象创建的过程
- 单例模式 js可以借助闭包的方式完成
- 适配器模式 在不对原有接口做任何改动的情况下,包装一层新的接口,返回最终数据
- 代理模式 proxy 在vue3.0中正在使用这个特性实现数据的双向绑定,现在是使用Object.definedProperty实现的,
- 观察者模式
- 发布-订阅者模式,这两种模式看似相同其实不同 观察者模式是观察者直接通知对象,双方知道对方的存在,发布-订阅者模式,双方不知道对方存在,使用中间对象对发布的信息进行删选然后通知订阅者。
- 装饰模式 在不改变以后接口,对方法进行包装。
- 外观模式,比如说写一个原生函数创建个浏览器环境下的XHR对象
vue生命周期
- beforeCreate
- created
- beforeMount
- mounted
- beforeupdate
- updated
- beforeDestroy
- disrtoryed
对于使用keep-alive的组件 有独有的deactived和actived 生命周期,在切换组件时此组件不会被销毁,而是缓存到内存并执行deactived ,命中缓存之后会调用actived
js中的原始类型
- boolean
- null
- undfined
- Number
- String
- Symbol
typeof有几种结果
- undefined
- boolean
- Object
- Number
- String
- Function
JS中有哪些内置函数
上面的这几种加上 Array Regexp Date Error
移动端首屏优化
- 采用服务器渲染ssr
- 按需加载配合webpack分块打包
- 很有必要将script标签➕异步
- 有轮播图 最好给个默认 另外要处理图片懒加载
- 打包线上也要注意去掉map 文件
- 组件懒加载
- 路由懒加载
- webpack的一切配置 肯定是必须的 这个百度去 做到js css 以及依赖库分离
- 强烈建议不要在应用依赖里面去下载jQuery库和一些Ui库
- 压缩图片 https://tinypng.com/
- 建议还是用webpack的图片压缩插件
- 使用pagespeed看看有哪些可优化的选项
最优二叉树
class Node { constructor(value) { this.value = value this.left = null this.right = null }}class BST { constructor() { this.root = null this.size = 0 } getSize() { return this.size } isEmpty() { return this.size === 0 } addNode(value) { this.root = this._addchild(this.root, value) } _addchild(node, value) { if (!node) { this.size++ return new Node(value) } if (node.value > value) { node.left = this._addchild(node.left, value) } else{ node.right = this._addchild(node.right, value) } return node }}复制代码
栈
class Stack{ constructor(){ this.stack = [] } push(val){ this.stack.unshift(val) } pop(){ this.stack.shift() } peek(){ return this.stack[this.getCount()-1] } getCount(){ return this.stack.length }}// 这里其实可以使用数组直接模拟栈 队列其实也是一样的// 检测下列字符串是否是回文字符串var str = 'leel'function isValied(str){ var strArr = str.split('') var stack = [] for(let i =0;i