2020-07-23
web前端培訓
好程序員web前端培訓分享JS面試題總結一,準備參加面試的小伙伴們一起看一看吧,希望本篇文章能夠對從事web前端工作的小伙伴們有所幫助。
一、說說你對閉包的認識
(一)什么是閉包
一句話解釋:
能夠讀取其他函數內部變量的函數。
稍全面的回答:
在js中變量的作用域屬于函數作用域, 在函數執行完后,作用域就會被清理,內存也會隨之被回收,但是由于閉包函數是建立在函數內部的子函數, 由于其可訪問上級作用域,即使上級函數執行完, 作用域也不會隨之銷毀, 這時的子函數(也就是閉包),便擁有了訪問上級作用域中變量的權限,即使上級函數執行完后作用域內的值也不會被銷毀。
這里涉及到對函數作用域的認識: js變量分為全局變量和局部變量;函數內部可以直接讀取全局變量,而在函數外部自然無法讀取函數內的局部變量
(二)閉包解決了什么問題
1. 可以讀取函數內部的變量
2. 讓這些變量的值始終保持在內存中。不會在函數調用后被清除
可以通過下面的代碼來幫助理解上面所說的:
function addCounter() {
let counter = 0
const myFunction = function () {
counter = counter + 1
return counter
}
return myFunction
}
const increment = addCounter()
const c1 = increment()
const c2 = increment()
const c3 = increment()
console.log('increment:', c1, c2, c3);
// increment: 1 2 3
在這段代碼中increment實際上就是閉包函數myFunction, 它一共運行了三次,diyi次的值是1,第二次的值是2,第三次的值是3。這證明了,函數addCounter中的局部變量counter一直保存在內存中,并沒有在addCounter調用后被自動清除。
(三)閉包的應用場景
在開發中, 其實我們隨處可見閉包的身影, 大部分前端 JavaScript 代碼都是“事件驅動”的,即一個事件綁定的回調方法; 發送ajax請求成功|失敗的回調;setTimeout的延時回調;或者一個函數內部返回另一個匿名函數,這些都是閉包的應用。
下面是具體應用的栗子:
1. 老掉牙的取正確值問題
for (var i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i) //10個10
}, 1000)
}
怎么取到每一次循環的正確值呢? 閉包這樣用:
for (var i = 0; i < 10; i++) {
((j) => {
setTimeout(function () {
console.log(j) //1-10
}, 1000)
})(i)
}
聲明了10個自執行函數,保存當時的值到內部
2.使用閉包模擬私有變量
私有變量在java里使用private聲明就可以了, 但是在js中還沒有,但是我們可以使用閉包模擬實現。
var counter = (function () {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val
}
return {
increment: function () {
changeBy(1)
},
decrement: function () {
changeBy(-1)
},
value: function () {
return privateCounter
}
}
})();
counter.value() //0
counter.increment() //1
counter.increment() //2
counter.decrement() //1
匿名函數已經定義就立即執行, 創建出一個詞法環境包含counter.increment、counter.decrement、counter.value三個方法,還包含了兩個私有項:privateCounter變量和changeBy函數。這兩個私有項無法在匿名函數外部直接訪問,必須通過匿名包裝器返回的對象的三個公共函數訪問。
(四)閉包的缺點
1. 由于閉包會是的函數中的變量都被保存到內存中,濫用閉包很容易造成內存消耗過大,導致網頁性能問題。解決方法是在退出函數之前,將不再使用的局部變量全部刪除。
2. 閉包可以使得函數內部的值可以在函數外部進行修改。所有,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變量的值。
二、跨域問題有哪些處理方式
跨域解決方案
1. 通過jsonp跨域
2. 跨域資源共享(CORS)
3. nodejs中間件代理跨域
4. nginx反向代理中設置proxy_cookie_domain
Ⅰ.通過jsonp跨域
通常為了減輕web服務器的負載,我們把js、css,img等靜態資源分離到另一臺獨立域名的服務器上,在html頁面中再通過相應的標簽從不同域名下加載靜態資源,而被瀏覽器允許,基于此原理,我們可以通過動態創建script,再請求一個帶參網址實現跨域通信。
1. 原生實現
服務器端返回如下(返回即執行全局函數)
jsonCallback({"status": 0, "user": "admin"})
2. jquery方式實現
$.ajax({
url: 'http://www.domain2.com:8080/login',
type: 'get',
dataType: 'jsonp', // 請求方式為jsonp
jsonpCallback: "handleCallback", // 自定義回調函數名
data: {}
});
?、?跨域資源共享(CORS)
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)跨域資源共享 CORS 詳解。看名字就知道這是處理跨域問題的標準做法。CORS有兩種請求,簡單請求和非簡單請求。
· 簡單請求
只要同時滿足以下兩大條件,就屬于簡單請求:
1. 請求方法是以下三種方法之一:
· HEAD
· GET
· POST
2. HTTP請求頭的信息不超出以下幾種字段:
· Accept
· Accept-Language
· Content-Language
· Last-Event-ID
· Content-Type:只限于三個值application/x-www-form-urlencoded、multipart/form-data、text/plain
如果是簡單請求, 后端處理即可, 前端什么也不用干; 這里注意的是如果前端要帶cookie, 前端也需要單獨設置
· 原生ajax (前端)
var xhr = new XMLHttpRequest();
// 前端設置是否帶cookie
xhr.withCredentials = true;
...
· jquery (前端)
$.ajax({
...
xhrFields: {
withCredentials: true // 前端設置是否帶cookie
},
crossDomain: true, // 會讓請求頭中包含跨域的額外信息,但不會含cookie
...
});
· vue中使用axios (前端)
axios.defaults.withCredentials = true
· 后端node
可以借助koa2-cors快速實現
const path = require('path')
const Koa = require('koa')
const koaStatic = require('koa-static')
const bodyParser = require('koa-bodyparser')
const router = require('./router')
const cors = require('koa2-cors')
const app = new Koa()
const port = 9871
...
// 處理cors
app.use(cors({
origin: function (ctx) {
return 'http://localhost:9099'
},
credentials: true,
allowMethods: ['GET', 'POST', 'DELETE'],
allowHeaders: ['t', 'Content-Type']
}))
// 路由
app.use(router.routes()).use(router.allowedMethods())
// 監聽端口
...
?、?nodejs中間件代理跨域
跨域原理: 同源策略是瀏覽器的安全策略, 不是HTTP協議的一部分。服務器端調用HTTP接口只是使用HTTP協議, 不會執行js腳本, 不需要檢驗同源策略,也就不存在跨域問題。
實現思路:通過起一個代理服務器, 實現數據的轉發,也可以通過設置cookieDomainRewrite參數修改響應頭cookie中域名,實現當前域下cookie的寫入
· 在vue框架下實現跨域
利用node + webpack + webpack-dev-server代理接口跨域。在開發環境下,由于vue渲染服務和接口代理服務都是webpack-dev-server同一個,所以頁面與代理接口之間不再跨域,無須設置headers跨域信息了。后臺可以不做任何處理。
webpack.config.js部分配置
module.exports = {
entry: {},
module: {},
...
devServer: {
historyApiFallback: true,
proxy: [{
context: '/login',
target: 'http://www.daxihong.com:8080', // 代理跨域目標接口
changeOrigin: true,
secure: false, // 當代理某些https服務報錯時用
cookieDomainRewrite: 'www.daxihong.com' // 可以為false,表示不修改
}],
noInfo: true
}
}
Ⅳ.nginx反向代理中設置
和使用node中間件跨域原理相似。前端和后端都不需要寫額外的代碼來處理, 只需要配置一下Ngnix
server{
# 監聽9099端口
listen 9099;
# 域名是localhost
server_name localhost;
#凡是localhost:9099/api這個樣子的,都轉發到真正的服務端地址http://localhost:9871
location ^~ /api {
proxy_pass http://localhost:9871;
}
}
對于跨域還有挺多方式可以實現, 這里就不一一列舉了。
三、for...in 和 for...of的區別
1. for...of 是ES6新引入的特性,修復了ES5引入的for...in的不足
2. for...in 循環出的是key,for...of循環出的是value
3. for...of不能循環普通的對象,需要通過和Object.keys()搭配使用
4. 推薦在循環對象屬性的時候,使用for...in,在遍歷數組的時候的時候使用for...of
四、new一個對象,這個過程中發生了什么
var obj = new Object("name","sansan");
1. 創建一個新對象,如:var obj = {};
2. 新對象的_proto_屬性指向構造函數的原型對象。
3. 將構造函數的作用域賦值給新對象。(也所以this對象指向新對象)
4. 執行構造函數內部的代碼,將屬性添加給obj中的this對象。
5. 返回新對象obj。
五、js的防抖和節流是什么
· 防抖: 在事件被觸發n秒后再執行回調,如果在這n秒內又被觸發,則重新計時。
使用場景:
1. 給按鈕加函數防抖防止表單多次提交。
2. 對于輸入框連續輸入進行AJAX驗證時,用函數防抖能有效減少請求次數。
簡單的防抖(debounce)代碼:
function debounce(fn, wait) {
var timeout = null;
return function () {
if (timeout !== null) clearTimeout(timeout)
timeout = setTimeout(fn, wait)
}
}
// 處理函數
function handle() {
console.log(Math.random())
}
//滾動事件
window.addEventListener('scroll', debounce(handle, 2000));
· 節流: 就是指連續觸發事件但是在 n 秒中只執行一次函數。節流會稀釋函數的執行頻率。
function throttle(func, delay) {
var prev = Date.now();
return function () {
var context = this;
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 2000));
區別:
函數節流不管事件觸發有多頻繁,都會保證在規定時間內一定會執行一次真正的事件處理函數,而函數防抖只是在最后一次事件后才觸發一次函數。 比如在頁面的無限加載場景下,我們需要用戶在滾動頁面時,每隔一段時間發一次Ajax請求,而不是在用戶停下滾動頁面操作時才去請求數據。這樣的場景,就適合用節流技術來實現。
開班時間:2021-04-12(深圳)
開班盛況開班時間:2021-05-17(北京)
開班盛況開班時間:2021-03-22(杭州)
開班盛況開班時間:2021-04-26(北京)
開班盛況開班時間:2021-05-10(北京)
開班盛況開班時間:2021-02-22(北京)
開班盛況開班時間:2021-07-12(北京)
預約報名開班時間:2020-09-21(上海)
開班盛況開班時間:2021-07-12(北京)
預約報名開班時間:2019-07-22(北京)
開班盛況Copyright 2011-2023 北京千鋒互聯科技有限公司 .All Right 京ICP備12003911號-5 京公網安備 11010802035720號