1澈蟆、this指向問題
(1)全局作用域下 this指向window
(2)箭頭函數(shù)中的this指向上下文
(3)構(gòu)造函數(shù)中的this指向調(diào)用者
(4)當某個函數(shù)為對象的?個屬性時启搂,在這個函數(shù)內(nèi)部this指向這個對象
(5)當?個元素被綁定事件處理函數(shù)時狈孔,this指向被點擊的這個元素
(6)嚴格模式下全局作用域中this指向undefined
2岭妖、改變this指向的三個方法
call apply bind
相同點:
都是用來改變函數(shù)的this對象的指向的,第一個參數(shù)都是this要指向的對象叼风,都可以利用后續(xù)參數(shù)傳參
不同點:
call/apply 可以直接執(zhí)行該函數(shù)帖世,而 bind 不會立刻執(zhí)行休蟹。
bind 與前兩者作用類似,都是改變函數(shù)內(nèi)部的 this 指向日矫,區(qū)別在于 bind 會創(chuàng)建一個新的函數(shù)實例赂弓,每次調(diào)用該實例時,都會在被綁定的環(huán)境中運行哪轿。簡單來說就是盈魁,bind方法返回一個新函數(shù),以后調(diào)用了才會執(zhí)行窃诉,但apply杨耙、call會立即執(zhí)行。
call和apply的區(qū)別在于飘痛,call可以傳遞多個參數(shù)珊膜,而apply只能傳遞兩個參數(shù),第二個參數(shù)以數(shù)組的形式進行接收敦冬。
call和apply的第一個參數(shù)如果是null和underfined this指向window。
3唯沮、什么是閉包脖旱,閉包的優(yōu)缺點?
閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)介蛉,在本質(zhì)上萌庆,閉包是將函數(shù)內(nèi)部和函數(shù)外部連接起來的橋梁。只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量币旧,所以閉包可以理解成“定義在一個函數(shù)內(nèi)部的函數(shù)”践险。
閉包的用途:
1.可訪問函數(shù)內(nèi)部的變量
2.在內(nèi)存中維持一個變量。防止函數(shù)內(nèi)部的變量執(zhí)行完成后,被銷毀巍虫,使其一直保存在內(nèi)存中彭则。
閉包的缺點:
濫用閉包會造成內(nèi)存泄露
因為閉包中引用到的包裹函數(shù)中定義的變量永遠不會被釋放
所以我們不再改變量或函數(shù)的時候應該及時釋放這個閉包函數(shù)。(使該函數(shù)等于null)
//1. 用最外層的函數(shù)來包裹內(nèi)層函數(shù)和受保護的變量
function parents(){
var total=1000;
//2. 將內(nèi)部的函數(shù)對象return到外部
return function(num){
total-=num;
document.write(`花了${num}元占遥,還剩下${total}元<br>`);
}
}
//3. 調(diào)用外部函數(shù)來獲得內(nèi)層函數(shù)俯抖,并保存在一個外部變量中
var child=parents();
console.log(child);
child(100);
child(200);
4、如何解決內(nèi)存泄漏瓦胎?
內(nèi)存泄漏(Memory Leak)是指程序中己動態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無法釋放芬萍,造成系統(tǒng)內(nèi)存的浪費,導致程序運行速度減慢甚至系統(tǒng)崩潰等嚴重后果搔啊。
通俗點就是指由于疏忽或者錯誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存柬祠,不再用到的內(nèi)存卻沒有及時釋放,從而造成內(nèi)存上的浪費负芋。
造成內(nèi)存泄漏的幾種情況:
- 定義全局變量
解決方式:使用 var let const 來定義變量漫蛔。或者在js文件開頭添加 ‘use strict'示罗,開啟嚴格模式惩猫。
2.閉包 在使用閉包的時候,就會造成嚴重的內(nèi)存泄漏蚜点,因為閉包中的局部變量轧房,會一直保存在內(nèi)存中。
解決方式:使該函數(shù)等于null绍绘。
3.定時器
定時器setInterval或者setTimeout在不需要使用的時候奶镶,沒有被clear,導致定時器的回調(diào)函數(shù)及其內(nèi)部依賴的變量都不能被回收陪拘,這就會造成內(nèi)存泄漏厂镇。
解決方式:當不需要interval或者timeout的時候,調(diào)用clearInterval或者clearTimeout
4.事件監(jiān)聽 DOM.addEventListener("click", callback)
垃圾回收機制不好判斷該事件是否需要被解除左刽,導致 callback 不能被釋放捺信,此時需要手動解除綁定:DOM.removeEventListener(callback)
5.元素引用沒有清理
var a = document.getElementById('id');
document.body.removeChild(a);
// 不能回收,因為存在變量a對它的引用欠痴。雖然我們用removeChild移除了迄靠,但是還在對象里保存著#的引用,即DOM元素還在內(nèi)存里面喇辽。
解決方法: a = null;
6.console
控制臺日志記錄對總體內(nèi)存內(nèi)置文件的影響掌挚,也是個重大的問題,同時也是容易被忽略的菩咨。記錄錯誤的對象梳侨,可以將大量的數(shù)據(jù)保留在內(nèi)存中。
傳遞給console.log的對象是不能被垃圾回收灭必,所以沒有去掉console.log可能會存在內(nèi)存泄漏
5、如何解決跨域糙置?
首先,在不同源的情況下才會發(fā)生跨域摩钙,不同源是指協(xié)議罢低、域名、端口不同胖笛,解決跨域的方案有以下幾種:
1.JSONP跨域
jsonp的原理就是利用<script>標簽沒有跨域限制网持,通過<script>標簽src屬性,發(fā)送帶有callback參數(shù)的GET請求长踊,服務端將接口返回數(shù)據(jù)拼湊到callback函數(shù)中功舀,返回給瀏覽器,瀏覽器解析執(zhí)行身弊,從而前端拿到callback函數(shù)返回的數(shù)據(jù)辟汰。
jsonp的缺點:只能發(fā)送get一種請求。
2.跨域資源共享(CORS)
CORS是一個W3C標準阱佛,全稱是"跨域資源共享"(Cross-origin resource sharing)帖汞。
它允許瀏覽器向跨源服務器,發(fā)出XMLHttpRequest請求凑术,從而克服了AJAX只能同源使用的限制翩蘸。
CORS需要瀏覽器和服務器同時支持。
3.nginx代理跨域
nginx代理跨域淮逊,實質(zhì)和CORS跨域原理一樣催首,通過配置文件設置請求響應頭Access-Control-Allow-Origin…等字段。
6泄鹏、深拷貝和淺拷貝
淺拷貝:
Object.assign()
函數(shù)庫lodash的 _.clone 方法
es6的展開運算符 …
Array.prototype.concat()
Array.prototype.slice()
深拷貝:
JSON.parse(JSON.stringify())
函數(shù)庫lodash的 _.cloneDeep 方法
jQuery.extend()方法
手寫遞歸方法
7郎任、webpack是怎么打包的,babel又是什么备籽?
Webpack:把所有依賴打包成一個 bundle.js文件舶治,通過代碼分割成單元片段并按需加載。Webpack是以公共JS的形式來書寫腳本的车猬,但對AMD/CMD的支持也很全面霉猛,方便舊項目進行代碼遷移。
把項目當做一個整體诈唬,通過一個給定的主文件(如:index.js)韩脏,Webpack將從這個文件開始找到項目的所有依賴文件缩麸,使用loaders處理它們铸磅,最后打包為一個(或多個)瀏覽器可識別的JavaScript文件。
babel將es6、es7阅仔、es8等語法轉(zhuǎn)換成瀏覽器可識別的es5或es3語法吹散。
8、vue路由參數(shù)的傳遞和接收的方式八酒?
router-link 標簽跳轉(zhuǎn)
this.$router.push()
this.$router.replace()
this.$router.go(n):(0:當前頁空民,-1上一頁,+1下一頁羞迷,n代表整數(shù))
一界轩、聲明式傳參:
//路由參數(shù)配置(顯示)
const router = new VueRouter({
routes: [{
path: '/about/:id',
component: User
}]
})
//聲明式導航使用
<router-link to="/about/12">跳轉(zhuǎn)</router-link>
//路由參數(shù)配置
const router = new VueRouter({
routes: [{
name: 'user1',
path: '/about/:id',
component: User
}]
})
//聲明式導航使用(不顯示)
<router-link :to="{ name: 'user1', params: { id: 123 } }">跳轉(zhuǎn)</router-link>
二、編程式傳參
//傳參
this.$router.push({
path: '/deviceInfo',
query: { deviceId: '202101075343' }
});
//接收參數(shù)
this.$route.query.deviceId
//傳參
router.push({
name: 'device',
params: { deviceId: '202101075343' }
})
//接收參數(shù)
this.$route.params.deviceId
9衔瓮、watch浊猾、methods 和 computed 的區(qū)別?
watch 為了監(jiān)聽某個響應數(shù)據(jù)的變化。computed 是自動監(jiān)聽依賴值的變化热鞍,從而動態(tài)返回內(nèi)容葫慎,主要目的是簡化模板內(nèi)的復雜運算。所以區(qū)別來源于用法薇宠,只是需要動態(tài)值偷办,那就用 computed ;需要知道值的改變后執(zhí)行業(yè)務邏輯澄港,才用 watch椒涯。
methods是一個方法,它可以接受參數(shù)慢睡,而computed 不能逐工,computed 是可以緩存的,methods 不會漂辐。computed 可以依賴其他 computed泪喊,甚至是其他組件的 data。
10髓涯、去重
方法1袒啼、雙重for循環(huán)
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 數(shù)組去重:
// 方法1: 雙重for 循環(huán)
function newArrFn (arr) {
// 創(chuàng)建一個新的空數(shù)組
let newArr = []
for(let i = 0;i<arr.length;i++){
// 設置一個開關(guān),如果是true纬纪,就存進去蚓再,不是就不存
let flag = true
for(let j = 0;j<newArr.length;j++){
// 原數(shù)組和新數(shù)組作比較,如果一致包各,開關(guān)變?yōu)?false
arr[i] === newArr[j] ? flag = false : flag
};
flag ? newArr.push(arr[i]) : newArr
};
return newArr
}
console.log(newArrFn(arr));
方法二摘仅、Set
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 數(shù)組去重:
// 方法4: set
function newArrFn (arr) {
// .new Set方法,返回是一個類數(shù)組问畅,需要結(jié)合 ...運算符娃属,轉(zhuǎn)成真實數(shù)組
return ([...new Set(arr)])
}
console.log(newArrFn(arr));
方法三六荒、set + Array.from
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 數(shù)組去重:
// 方法5: set + Array.from
function newArrFn (arr) {
// .new Set方法,返回是一個類數(shù)組矾端,需要結(jié)合 Array.from 掏击,轉(zhuǎn)成真實數(shù)組
return (Array.from(new Set(arr)) )
}
console.log(newArrFn(arr));
方法四、filter + indexOf
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 數(shù)組去重:
// 方法6 :filter + findIndex
function newArrFn (arr) {
// 利用indexOf檢測元素在數(shù)組中第一次出現(xiàn)的位置是否和元素現(xiàn)在的位置相等秩铆,
// 如果相等砚亭,說明數(shù)組中沒有重復的
return Array.prototype.filter.call(arr, function (item, index) {
return arr.indexOf(item) === index
})
}
console.log(newArrFn(arr));
方法五、Map
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 數(shù)組去重:
// 方法11 :Map
function newArrFn (arr) {
let newArr = []
let map = new Map()
for(let i = 0;i<arr.length;i++){
// 如果 map里面不包含殴玛,就設置進去
if (!map.has(arr[i])) {
map.set(arr[i], true)
newArr.push(arr[i])
}
};
return newArr
}
console.log(newArrFn(arr));
方法六捅膘、reduce
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
// 數(shù)組去重:
// 方法12 :reduce
function newArrFn (arr) {
let newArr = []
return arr.reduce((prev, next,index, arr) => {
// 如果包含,就返回原數(shù)據(jù)滚粟,不包含篓跛,就把新數(shù)據(jù)追加進去
return newArr.includes(next) ? newArr : newArr.push(next)
}, 0)
}
console.log(newArrFn(arr));