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
元件內的守衛
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<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)
複製程式碼