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号