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<array.length-1;i++){
for(let j=i;j>=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; i<arr.length;i++){
if(arr[i]>pivot){
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
组件内的守卫
beforeRouteEnterbeforeRouteUpdatabeforeRouteLeave
完整的解析过程
- 导航被触发
- 上一个导航的组件里调用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<strArr.length;i++){
if(stack.indexOf(strArr[i]) === -1){
stack.push(strArr[i])
}else{
if(stack[stack.length-1] === strArr[i]){
stack.pop()
}
}
}
if(stack.length !== 0 ){
return false
}else{
return true
}
}
isValied(str)