前端面试题四
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状态码