前端面试题(包含答案)
浏览器
说一下用户从输入url到显示页面这个过程发生了什么
- DNS 解析,就是根据 IP 地址获取域名
- 检查浏览器缓存
- 客户端向服务器发送 TCP 响应,建立三次握手
- 握手完成后服务端回馈响应,浏览器向服务器发送 HTTP 请求,服务器处理收到的请求,将数据返回至浏览器
- 读取页面内容,浏览器渲染,解析 HTML、CSS,加载 JS 资源,建立文档树
- 连接结束
状态码
200:响应成功
301:本网页被转移到另一个URL
302:重定向
400:传的参数有问题,服务器不能解析
403:禁止访问
404:请求资源不存在
500:服务器遇到错误或关闭
502:nginx没配置好,网关错误
503:超载或停机服务器目前无法使用,一段时间后可能恢复正常
Javascript
介绍一下 JavaScript 原型,原型链
原型:
每个析构函数都拥有自己的prototype(原型)属性,这个属性指向一个对象,这就是原型。
原型链:
JavaScript所有对象都是由原型对象继承而来,而原型对象本身也是一个对象,它也有自己的对象,这样层层上溯,形成了一个类似链表结构,这就是原型链
解释一下什么是 promise?
里面是同步函数,then
后面才是异步回调
promise 可以有三种状态:
- pending:初始状态,既不是成功也不是失败
- fulfilled:意味着操作完全成功
- rejected:意味着操作失败
如果 promise 不能使用,那么用什么方法来替代它呢?
使用回调函数(callback)
const、var、let 的区别
- var 声明的变量会提升到当前作用域顶部,可以重复声明,可以多次赋值
- let 声明的变量不会提升,提前使用会报错,会形成块级作用域,不可以重复声明,允许多次赋值
- const 声明的变量不可重复声明,不可多次赋值,会形成块级作用域。
bind、apply 和 call 是啥
它们都是用来修改 this
指向的,使用某个上下文调用该函数,请使用 .bind()
,这在事件中很有用。 如果要立即调用函数,使用.call()
或 .apply()
,并修改上下文。
const mbs = {
name: '麻不烧',
say(prefix, age) {
console.log(`${prefix},my name is ${this.name},i am ${age} year old`)
}
}
const A = {
name:'小丁'
}
mbs.say.call(A,'hello',3) // 'hello,my name is 小丁,i am 3 year old'
浅拷贝和深拷贝
浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝
浅拷贝
- Object.assign()
- Array.prototype.slice(0)
- 扩展运算符 …
深拷贝
- JSON.parse(JSON.stringify())
- 循环对象,把对象的 KEY 和 VALUE 存放到一个新的变量里面
它们俩的区别就是:浅拷贝地址还是指向原来那个内存地址,深拷贝是重新开辟一个内存地址
深拷贝JSON.parse(JSON.stringify())有什么缺点,如何解决呢
js关键字有丢失,比如 function、null、正则表达式
如何解决呢?
循环对象,把对象的 KEY 和 VALUE 存放到一个新的变量里面
function deepClone(source) {
const targetObj = source.constructor === Array ? [] : {};
for (keys in source) {
if(source.hasOwnProperty(keys)) {
// 数组和对象
if(source[keys] && typeof source[keys] === 'object') {
// targetObj[keys] = targetObj[keys] === Array ? [] : {}; // 只是为了可读性,可要可不要
targetObj[keys] = deepClone(source[keys]);
} else {
// 基本类型
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}
js的基本类型和引用类型有哪些
基本数据类型指的是简单的数据段,有5种,包括null
、undefined
、string
、boolean
、number
;
引用数据类型指的是有多个值构成的对象,包括object
、array
、date
、regexp
、function
等。
闭包的概念?优缺点?
闭包的概念:闭包就是能读取其他函数内部变量的函数。
优点:
- 避免全局变量的污染
- 一个变量长期存储在内存中(缓存变量)
- 环境私有化,方法都是孤立的
缺点:
- 内存泄露(消耗)
- 常驻内存,增加内存使用量
示例代码
// 闭包
function a() {
let name = 'John'
function getName() {
return name + '12312312'
}
return getName()
}
function add() {
let num = 0;
function go() {
num++;
console.log(`num===>`, num)
}
return go
}
// 因为 num 的值存在内存里面,所以每次递增
let as = add()
as() // 1
as() // 2
as() // 3
function foo(a) {
const c = "closures";
if (typeof a === "number" || a instanceof Number) {
const b = a + 1;
console.log(b);
}
return () => c;
}
const func = foo();
func(); // 'closures'
谈谈对 this 对象的理解?
- this 总是指向函数的直接调用者(而非间接调用者);
- 如果有 new 关键字,this 指向 new 出来的那个对象;
- 在事件中,this 指向触发这个事件的对象,特殊的是,IE 中的 attachEvent 中的 this 总是指向全局对象 Window。
- 箭头函数的 this 是指向外部上下文的 this
HTML
简述一下 src 与 href 的区别?
href 是指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,用于超链接。
src 是指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;在请求 src 资源时会将其指向的资源下载并应用到文档内,例如 js 脚本,img 图片和 frame 等元素。当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,图片和框架等元素也如此,类似于将所指向资源嵌入当前标签内。这也是为什么将 js 脚本放在底部而不是头部。
CSS
transform、translate、transition 分别是什么属性?CSS 中常用的实现动画方式
transform
是指变换、变形,是 css3 的一个属性,和 width,height 属性一样;
translate
是 transform 的属性值,是指元素进行 2D(3D)维度上位移或范围变换;
transition
是指过渡效果,往往理解成简单的动画,需要有触发条件。
Vue
Vue 双向绑定原理
vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)。
怎么理解 Vue 的单向数据流?
一句话解释:父组件传给子组件的 props 值,子组件没权利修改;
那如果希望修改父组件传给子组件的值呢:
- 在子组件 data 中创建一个变量获取 props 中的值,再改变这个 data 中的值。
- 子组件使用 $emit 发出一个事件,让父组件接收去修改这个值。
为什么 Vue 中 data 必须的返回函数
因为组件是可以复用的,为了不让多处的组件共享同一 data 对象,防止数据污染。
为什么Vue2中无法检测Object和Array的变化
https://yukinoyukino.com/archives/wei-shen-me-vue2-zhong-wu-fa-jian-ce-object-he-array-de-bian-hua
property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的
Vue 中 key 值的作用?
key 的作用主要是为了高效的更新虚拟DOM。
vue里面的导航守卫
https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
- 全局前置守卫(beforeEach)、全局解析守卫(beforeResolve)、全局后置守卫(beforeAfter)
- 路由独享的守卫: beforeEnter
- 组件内的守卫: beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
Vue 子组件和父组件执行顺序
加载渲染过程:
父组件 beforeCreate
父组件 created
父组件 beforeMount
子组件 beforeCreate
子组件 created
子组件 beforeMount
子组件 mounted
父组件 mounted
更新过程:
父组件 beforeUpdate
子组件 beforeUpdate
子组件 updated
父组件 updated
销毁过程:
父组件 beforeDestroy
子组件 beforeDestroy
子组件 destroyed
父组件 destoryed
路由里面的 hash 与 history 区别
hash 原理:
- hash 通过监听浏览器
onhashchange
事件变化,查找对应路由应用。通过改变location.hash
改变页面路由。 - hash 可以兼容到 IE8
- 只会读取哈希符号后的内容,并不会发起任何网络请求
- hash 不需要服务器任何配置
- hash 模式中的 # 也称作锚点,所以页面定位会失效
history 原理:
- 利用 html5 的history Interface 中新增的
pushState()
和replaceState()
方法,改变页面路径。可通过 back、forward、go 等,可以读取历览器历史记录栈的信息,pushState、repalceState 还可以对浏览器历史记录栈进行修改。 - history 只能兼容到 IE10
- 每访问一个页面都要发起网络请求
- 刷新页面时,无法找到url对应的页面,会出现 404 问题,需要 nginx 配置一下