前端面试题四
1. js原型链
2. 服务器端怎么设置cookie?
expires
该属性用来设置Cookie的有效期。Cookie中的maxAge用来表示该属性,单位为秒。Cookie中通过getMaxAge()和setMaxAge(int maxAge)来读写该属性。
cookie.setMaxAge(0);//不记录cookie
cookie.setMaxAge(-1);//会话级cookie,关闭浏览器失效
cookie.setMaxAge(60*60);//过期时间为1小时
3. Javascript数据类型,Symbol类型一般怎样使用,引用类型和基本类型
基本数据类型:String、Number、null、undefined、Boolean、Symbol、BigInt
应用场景一:我们可以将Symbol用来作为对象属性名(key)
Symbol类型的key是不能通过object.keys()或者for...in来枚举的,它未被包含在对象自身的属性名集合(property names)之中。多以利用该特性,我们可以把一些不需要对外操作或者访问的属性使用Symbol来定义。
也正因为这样的一个特性,我们在使用JSON.stringify()将对象,JSON字符串的时候,Symbol属性你也会排除在输出内容之外。
我们可以利用这一特点来更好的设计我们的数据对象,让“对内操作”和“对外选择性输出”变得更加优雅。
有一些专门的API还是可以取得到Symbol定义的属性的:
然而,这样的话,我们就没办法获取以Symbol方式定义的对象属性了么?非也。还是会有一些专门针对Symbol的API,比如: // 使用Object的API Object.getOwnPropertySymbols(obj) // [Symbol(name)] // 使用新增的反射API Reflect.ownKeys(obj) // [Symbol(name), 'age', 'title']
应用场景二:使用Symbol来代替常量
const TYPE_AUDIO = 'AUDIO' const TYPE_VIDEO = 'VIDEO' const TYPE_IMAGE = 'IMAGE'
使用Symbol之后
const TYPE_AUDIO = Symbol() const TYPE_VIDEO = Symbol() const TYPE_IMAGE = Symbol()
应用场景三:使用Symbol来定义类的私有属性/方法
JS中没有Java的private
而有了Symbol以及模块化机制,类的私有属性和方法菜变得可能。
在文件a.js中
const PASSWORD = Symbol()
class Login {
constructor(username, password) {
this.username = username
this[PASSWORD] = password
}
checkPassword(pwd) {
return this[PASSWORD] === pwd
}
}
export default Login
在文件b.js中
import Login from './a'
const login = new Login('admin', '123456')
login.checkPassword('123456') // true
login.PASSWORD // oh!no!
login[PASSWORD] // oh!no!
login["PASSWORD"] // oh!no!
由于Symbol常量PASSWORD被定义在a.js所在的模块中,外面的模块获取不到这个Symbol,也不可能再创建一个一模一样的Symbol出来(因为Symbol是唯一的),因此这个PASSWORD的Symbol只能被限制在a.js内部使用,所以使用它来定义的类属性是没有办法被模块外访问到的,达到了一个私有化的效果。
基本类型:string,number,boolean,null,undefined,symbol、bigint
引用类型:Function,Array,Object
4. 手写数组去重
利用indexOf去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array .indexOf(arr[i]) === -1) {
array .push(arr[i])
}
}
return array;
}
利用hasOwnProperty
function unique(arr) {
var obj = {};
return arr.filter(function(item, index, arr){
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
5. 讲一下事件流?
(1)事件流描述的是从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序。(2)事件就是用户或浏览器自身执行的某种动作。诸如click(点击)、load(加载)、mouseover(鼠标悬停)。(3)事件处理程序响应某个事件的函数就叫事件处理程序(或事件侦听器)。
dom2级事件规定的事件包括三个阶段:事件捕获阶段==>处于目标阶段==>事件冒泡阶段
洋葱模型
6. preventDefault()和stopPropagation()的区别
stopPropagation()阻止事件冒泡
preventDefault()阻止事件默认行为
该方法将通知 Web 浏览器不要执行与事件关联的默认动作(如果存在这样的动作)。例如,如果 type 属性是 "submit",在事件传播的任意阶段可以调用任意的事件句柄,通过调用该方法,可以阻止提交表单。注意,如果 Event 对象的 cancelable 属性是 fasle,那么就没有默认动作,或者不能阻止默认动作。无论哪种情况,调用该方法都没有作用。
7. 解决异步的几种方式?
(1)回调函数
function f1(f2){
setTimeout(function(){
console.log('先执行 f1')
},1000)
f2()
}
function f2() {
console.log('再执行 f2')
}
总结:回调函数易于实现,便于理解,但多次回调会使得代码高度耦合,回调地狱。
(2)事件监听
脚本的执行不取决代码的顺序,而取决于某一个事件是否发生。
$(document).ready(function(){
console.log('DOM 已经 ready')
});
(3)发布订阅模式
发布/订阅模式是利用一个消息中心,发布者发布一个消息给消息中心,订阅者从消息中心订阅该消息,。类似于 vue 的父子组件之间的传值。
//订阅done事件
$('#app').on('done',function(data){
console.log(data)
})
//发布事件
$('#app').trigger('done,'haha')
(4)promise
Promise 实际就是一个对象, 从它可以获得异步操作的消息,Promise 对象有三种状态,pending(进行中)、fulfilled(已成功)和rejected(已失败)。Promise 的状态一旦改变之后,就不会在发生任何变化,将回调函数变成了链式调用。
export default function getMethods (url){
return new Promise(function(resolve, reject){
axios.get(url).then(res => {
resolve(res)
}).catch(err =>{
reject(err)
})
})
}
getMethods('/api/xxx').then(res => {
console.log(res)
}, err => {
console.log(err)
})
(5)generator
Generator 函数是一个状态机,封装了多个内部状态。执行 Generator 函数会返回一个遍历器对象,使用该对象的 next() 方法,可以遍历 Generator 函数内部的每一个状态,直到 return 语句。
形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式, yield是暂停执行的标记。
next() 方法遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
function *generatorDemo() {
yield 'hello';
yield 1 + 2;
return 'ok';
}
var demo = generatorDemo()
demo.next() // { value: 'hello', done: false }
demo.next() // { value: 3, done: false }
demo.next() // { value: 'ok', done: ture }
demo.next() // { value: undefined, done: ture }
(6)async/await
async函数返回的是一个 Promise 对象,可以使用 then 方法添加回调函数,async 函数内部 return 语句返回的值,会成为 then 方法回调函数的参数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
await命令后面返回的是 Promise 对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。
async function demo() {
try {
await new Promise(function (resolve, reject) {
// something
});
} catch (err) {
console.log(err);
}
}
demo().then(data => {
console.log(data) //
})
8. defer和async的区别
(1)<script src="script.js"></script>
没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素读到就加载并执行。
(2)<script async src="script.js"></script>
有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。
(3)<script defer src="myscript.js"></script>
有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。

9. 写一下双飞翼布局,两边固定中间自适应
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>双飞翼布局</title>
</head>
<style>
body{
margin: 0;
padding: 0;
}
#wrapper{
min-width: 600px;
}
#header,#footer{
width:100%;
height: 50px;
line-height: 50px;
background: yellow;
}
#content{
/* width: 100%; */
overflow: hidden;
}
#left,#right,#middle{
float:left;
height: 500px;
}
#left{
margin-left: -100%;
width: 160px;
background: orange;
}
#middle{
width: 100%;
background: pink;
}
#right{
margin-left: -200px;
width: 200px;
background: blue;
}
#middle-content{
margin: 0 200px 0 160px;
}
</style>
<body>
<div id="wrapper">
<div id="header">header</div>
<div id="content">
<div id="middle">
<div id="middle-content">middle</div>
</div>
<div id="left">left</div>
<div id="right">right</div>
</div>
<div id="footer">footer</div>
</div>
</body>
</html>
10. 移动端适配方式
(1)百分比方案
使用百分比%宽度,高度用px固定,根据可视化区域实时尺寸进行调整,尽可能适应各种分辨率,通常使用max-width/min-width控制尺寸范围过大或者过小。下表是子元素不同属性设置百分比的依据。
优势:原理简单,不存在兼容问题
不足:
- 如果屏幕尺度跨度太大,相对设计稿过大或者过小的屏幕不能正常显示,在大屏手机或横竖屏切换场景下可能会导致页面元素被拉伸变形,字体大小无法随屏幕大小发生变化。
... - 设置盒模型的不同属性时,其百分比设置的参考元素不唯一,容易使布局问题变得复杂
(2)rem方案
rem是相对长度单位,rem方案中的样式设计相对于根元素font-size计算值得倍数。
根据屏幕宽度设置html标签的font-size,在布局时使用rem单位布局,达到自适应的目的,是弹性布局的一种实现方式。
- 兼容性好
不足:不是纯css移动适配方案,需要引入js脚本 在头部内嵌一段 js脚本 监听分辨率的变化来动态改变根元素的字体大小,css样式和 js 代码有一定 耦合性,并且必须将改变font-size的代码放在 css 样式之前。
(3)vh/vw方案
视口是浏览器中用于呈现网页的区域,移动端的视口通常指的是 布局视口
- vw : 1vw 等于 视口宽度 的 1%
- vh : 1vh 等于 视口高度 的 **1% **
- vmin : 选取 vw 和 vh 中 最小 的那个
- vmax : 选取 vw 和 vh 中 最大 的那个
优势:纯 css 移动端适配方案,不存在脚本依赖问题
不足:存在一些兼容性问题,Android4.4以下不支持
(4)rem+vw/vh方案
vw/vh 方案能够实现宽度和高度的自适应,并且逻辑清晰,由于其被支持得较晚,所以存在一定的兼容性问题。将 vw/vh 方案与 rem 方案相结合,给根元素设置随视口变化的vw单位,可以通过postcss-plugin-vwtorem将其转换。具体的计算过程为:
对于1080px宽的设计稿,设置默认根字号的大小为100px,那么设计稿中1px对应的是 100vw/1080 = 0.0925926vw,并且 1rem = 100px,也就可以得到1rem = 9.256926vw
同时可以使用媒体查询限制根元素的最大最小值,实现对页面的最大最小宽度限制,对用户的视觉体验更好。
(5)基于媒体查询的响应式设计
+ 弹性布局 方案。比如给小屏幕手机设置@2x图,为大屏手机设置@3x图。通过媒体查询技术需要设置一定量的断点,到达某个断点前后的页面发生显著变化,用户体验不太友好
11. HTTP和HTTPS有什么区别?
HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。
HTTPS和HTTP的区别主要如下:
(1)https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
(2)http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
(3)http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
(4)http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
12. HTTP状态码


浙公网安备 33010602011771号