最近在複習面試中常見的JS手寫函數,順便進行代碼註釋和總結,方便本身回顧也加深記,內容也會陸陸續續進行補充和改善。面試
<script> const obj1 = { name: 'Leise', age: 23, address: { country: 'China', city: 'Guanzhou' } } const obj2 = deepClone(obj1) obj2.address.city = 'Hangzhou' console.log(obj1.address.city); console.log(obj2.address.city); function deepClone(obj) { //判斷是否爲非對象或者是null if (typeof obj !== 'object' || typeof pbj == null) { return obj } // 初始化拷貝結果 let result // 判斷是數組仍是對象 if (obj instanceof Array) { result = [] } else { result = {} } for (let key in obj) { //保證key不是原型的屬性 if (obj.hasOwnProperty(key)) { // 遞歸調用深拷貝 防止多重嵌套 result[key] = deepClone(obj[key]) } } // 最後返回結果 return result } </script>
<script> Function.prototype.mybind = function () { //原型添加方法mybind const args = Array.prototype.slice.call(arguments) //將得到參數拆解成數組 const t = args.shift() //獲取this(數組第一項,同時剔除第一項,shift能夠實現) const self = this //當前fn1.bind(...)中的fn1 //console.log(this); //function fn1(a, b, c) { //console.log("this", this); //定義一個變量保留this指向 //console.log(a, b, c); } return function () { //console.log(this);window return self.apply(t, args) //這個函數須要執行 } } function fn1(a, b, c) { console.log("this", this); console.log(a, b, c); } const fn2 = fn1.mybind({ x: 1, y: 2 }, 10, 20, ) //bind以後須要執行 const res = fn2() //保存運行後的結果並打印出來 console.log(res); </script>
<script> function bindEvent(elem, type, selcetor, fn) { //判斷三個仍是四個,四個則是事件代理 if (fn == null) { fn = selcetor selcetor = null } //開始綁定事件 elem.addEventListener(type, event => { const target = event.target //判斷是事件代理仍是普通綁定 if (selector) { //事件代理 if (target.matches(selcetor)) { fn.call(target, event) } else { fn.call(target.event) } } }) } function bindEvent(elem, type, selector, fn) { // 三個參數和四個參數的判斷處理 if (fn == null) { fn = selector selector = null } elem.addEventListener(type, event => { const target = event.target if (selector) { // 有selector就是代理 if (target.matches(selector)) { fn.call(target, event) } } else { fn.call(target, event) } }) } const div3 = document.getElementById('div3') bindEvent(div3, 'click', 'a', function (event) { event.preventDefault() alert(this.innerHTML) }) </script>
<script> function createCache() { // 閉包隱藏數據,只提供 API let obj = {} return { set: function (key, value) { obj[key] = value }, get: function (key) { return obj[key] } } } const c = createCache() c.set('a', 100) console.log(c.get('a')) obj.d = 100 //undefined,必須使用get或者set </script>
<script> function loadImg(url) { return new Promise((resolve, reject) => { const img = document.createElement('img') img.src = url img.onload = () => { resolve(img) } img.onerror = () => { reject(new Error("圖片加載失敗")) } }) } const url1 = 'http://img.mukewang.com/5e5c85e1000116c505400720-156-88.jpg' const url2 = 'https://img.mukewang.com/szimg/5dba8cee0969880506000338.jpg' loadImg(url1).then((img1) => { console.log(img1.width); return img1 }).then((img1) => { console.log(img1.height); return loadImg(url2) }).then(img2 => { console.log(img2.width); }) </script>
<script> function ajax(url) { return new Promise((resolve, reject) => { //判斷谷歌等仍是IE let xhr if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari xhr = new XMLHttpRequest() } else { // code for IE6, IE5 xhr = new ActiveXObject("Microsoft.XMLHTTP") } // xhr 具備一個 open 方法,這個方法的做用相似於初始化,並不會發起真正的請求 // open 方法具備 5 個參數,可是經常使用的是前 3 個 // method: 請求方式 —— get / post // url:請求的地址 // async:是否異步請求,默認爲 true(異步) xhr.open("get", url, true) // send 方法發送請求,並接受一個可選參數 // 當請求方式爲 post 時,能夠將請求體的參數傳入 // 當請求方式爲 get 時,能夠不傳或傳入 null // 無論是 get 仍是 post,參數都須要經過 encodeURIComponent 編碼後拼接 xhr.send(null) //當readyStatus的狀態發生改變時,會觸發 xhr 的事件onreadystatechange xhr.onreadystatechange = () => { //readyStatus: 請求/響應過程的當前活動階段 if (xhr.readyState == 4) { //HTTP 狀態在 200-300 之間表示請求成功 // HTTP 狀態爲 304 表示請求內容未發生改變,可直接從緩存中讀取 if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) { let obj = JSON.parse(xhr.responseText) // console.log(obj) // callBack(obj) resolve(obj) } else { reject(new Error("錯誤")) } } } }) } const url1 = "http://jsonplaceholder.typicode.com/users" const url2 = "/a.json" const url3 = "/b.json" ajax(url1).then(res => { console.log(res); return ajax(url2) }).then(res => { console.log(res); return ajax(url3) }).then(() => { console.log("ok"); }).catch((res) => { console.log(res) //設置一個統一出口 若是出現錯誤就終止 }) </script>
<script> const input1 = document.getElementById('input1') function debounce(fn, delay) { //timer必須在閉包中 纔不會被外面修改 let timer = null return function () { if (timer) { clearTimeout(timer) } timer = setTimeout(() => { fn.apply(this, arguments) timer = null }, delay); } } input1.addEventListener('keyup', debounce(function () { console.log(input1.value); }, 500)) </script>
<script> function throttle(fn, delay) { let timer = null return function () { if (timer) { return } timer = setTimeout(() => { fn.apply(this, arguments) timer = null++ }, delay); } } const one = document.getElementById('one') one.addEventListener('drag', throttle(function (e) { console.log(e.offsetX, e.offsetY); }, 1000)) </script>