前端面试题

文章目录

  • 一、闭包(完)
  • 二、原型链(完)
  • 三、防抖和节流(完)
  • 四、Vue相关
    • 1、MVC和MVVM的区别
    • 2、v-model 原理
    • 3、vue中的data为什么是一个函数?(面试常问)
    • 4、v-if 和 v-show的区别
    • 5、v-for中为什么要有key
    • 6、dist 目录打包后过大,解决办法?
    • 7、watch和computed的区别
    • 8、子组件给父组件传递数据
    • 9、全局事件总线:可以实现任意组件间的数据传递
    • 10、Vue生命周期及运行顺序
  • 五、ES6面试题(完)
    • 1、var let const 区别
    • 2、解构赋值
    • 3、ES6快速去重
    • 4、promise面试题 以下代码的执行结果是?(完)
    • 5、对象的合并、获取key、value值
  • 六、跨域(完)
    • 1、webpack 里的proxy
    • 2、Jsonp
    • 3、webpack plugin (插件)
    • 4、cors (后端解决)
  • 七、cookie、localStorage、sessionStorage的区别 (完)
  • 八、async 和 await 的区别
  • 九、箭头函数和普通函数的区别?
  • 十、项目性能优化方案
  • 十一、TypeScript
    • 1、TypeScript 的主要特点是什么?
    • 2、使用 TypeScript 有什么好处?
    • 3、TypeScript 的内置数据类型有哪些?
    • 4、类型断言
  • 十二、call()、apply()、bind()的异同
  • 十三、删除数组的固定值
  • 十四、状态码
  • 十五、vue生命周期及父子组件中的运行顺序
  • 十六、Vuex
  • 十七、JSON.parse和JSON.stringify的用法

一、闭包(完)

1、“定义在一个函数内部的函数“。
2、该函数作为返回值返回,该函数可以调用所在函数体的变量。
3、本质上,闭包是将函数内部和函数外部连接起来的桥梁。由于调用该函数一直没有被释放,所以其所调用的变量也不被释放。

另:

1、闭包存在意义:可以延长变量的生命周期,可以创建私有的环境。
2、闭包好处:
 1)、可以读取其他函数的内部变量。
 2)、将变量始终保存在内存中。
 3)、可以封装对象的私有属性和方法。
3、坏处:消耗内存、使用不当会造成内存溢出问题.

二、原型链(完)

1、JS中每个函数都存在有一个原型对象属性prototype。并且所有函数的默认原型都是Object的实例。

2、原型链,简单理解就是原型组成的链,原型也是一个对象,也有__proto__属性,原型的__proto__又是原型的原型,就这样可以一直通过__proto__想上找,这就是原型链,当向上找找到Object的原型的时候,这条原型链就算到头了。
instanceof是判断实例对象的__proto__和生成该实例的构造函数的prototype是不是引用的同一个地址。

3、原型链实现了继承。原型链存在两个问题:
(1)包含引用类型值的原型属性会被所有实例共享。
(2) 在创建子类型时,无法向超类型的构造函数中传递参数。

三、防抖和节流(完)

防抖:【场景:下拉触底加载下一页】触发事件后,在n秒内,事件只执行一次,如果在n秒内又触发了事件,则会重新计算函数的执行时间。

节流:【场景:搜索查询】连续发生的事件,n秒内,只执行一次。

四、Vue相关

1、MVC和MVVM的区别

MVC:
1、M(model数据)、V(view视图),C(controlle控制器)
2、缺点是前后端无法独立开发,必须等后端接口做好了才可以往下走。
3、前端没有自己的数据中心,太过依赖后台

MVVM:
1、M(model数据)、V(view视图)、VM(viewModel控制数据的改变和控制视图)
2、html部分相当于View层。Vue实例中的data相当于Model层,而ViewModel层的核心是Vue中的双向数据绑定,即Model变化时VIew可以实时更新,View变化也能让Model发生变化。

另:

MVVM与MVC最大的区别就是:它实现了View和Model的自动同步,也就是当Model的属性改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变属性后该属性对应View层显示会自动改变。

2、v-model 原理

通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调从而达到数据和视图同步。

3、vue中的data为什么是一个函数?(面试常问)

实际上就是一个闭包,因为vue是单页面应用,是由很多组件构成,每一个组件中都有一个data,所以通过闭包给每一个组件创建了一个私有的作用域,这样就不会相互影响。

4、v-if 和 v-show的区别

v-if是通过添加和删除元素来进行显示或者隐藏

v-show是通过操作DOM修改display样式来修改元素的显示和隐藏

如果需要频繁的进行元素的显示和隐藏使用v-show性能更好

5、v-for中为什么要有key

1、key 可以提高虚拟DOM的更新效率。

2、在vue中,默认“就地复用”的策略,在DOM操作的时候,如果没有key 就会造成选项错乱

3、key 只能是字符串或者number,其他类型不可以。

另:

1、虚拟DOM中key的作用:

key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新的虚拟DOM】与【旧的虚拟DOM】差异比较比较规则如下:

2、 比较规则:

1)旧虚拟DOM找到了与新虚拟DOM相同的key:

若虚拟DOM中内容没变,直接使用之前的真实DOM

若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM

3、 用index作为key可能会引发的问题:

1)若对数据进行:逆序添加、逆序删除等破坏顺序的操作,会产生没有必要的真实DOM更新==>界面效果没问题,但效率低

2)如果结构中还包含输入类的DOM,会产生错误的DOM更新 ==> 界面有问题。

6、dist 目录打包后过大,解决办法?

  1. dist打包生成的文件中有 .map 文件,可以删除。在 vue.config.js文件中配置:productionSourceMap: false

  2. 组价和路由使用懒加载、按需引入等

  3. 对于文件和图片进行压缩。 安装压缩组件: compression-webpack-plugin

安装后进行导入配置:

最小化代码 minisize: true

分割代码: splitChunksl

超过限定值的文件进行压缩,threshold: 文件大小(字节为单位)

7、watch和computed的区别

1、computed能完成的功能,watch都可以完成

2、watch能完成的小功能,computed不一定能完成。例如:watch可以进行异步操作

两个重要小原则:

1、所有被vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象

2、 所有不被vue管理的函数(定时器的回调、ajax的回调、promise的回调等),最好写成箭头函数,这样this的指向才是vm或组件实例对象。

8、子组件给父组件传递数据

1、第一种方式:通过父组件给子组件传递函数类型的props实现:子组件给父组件传递数据。
2、第二种方式:通过父组件给子组件绑定一个自定义事件实现:子组件给父组件传递数据。$emit
3、第三种方式:通过父组件给子组件绑定一个自定义事件实现:使用ref实现。

9、全局事件总线:可以实现任意组件间的数据传递

1、main.js:将全局事件bus,挂载到Vue的原型上,这样所有的组件都可以使用。
前端面试题_第1张图片

10、Vue生命周期及运行顺序

五、ES6面试题(完)

1、var let const 区别

var:
1、存在变量提升,存在变量覆盖。
2、已经被定义且赋值的变量,如果再次被赋值,则以后一次值为准。
3、没有块级作用域。

const:
1、不存在变量提升和变量覆盖。
2、定义的是常量,声明之后必须赋值;定义的值不能去修改,否则报错。
3、有块级作用域。对于数组和对象的元素修改,不算做对常量的修改,不会报错。

let:
1、不存在变量提升和变量覆盖。
2、let不允许在相同的作用域中重复声明。 注意是相同作用域,不同作用域重复声明不会报错。
3、有块级作用域。

2、解构赋值

let a = 1; let b = 2;  如果在不声明第三个变量的前提下,使a=2, b=1?

答案:[a, b] = [b, a]

3、ES6快速去重

let arr = [23, 12, 13, 33, 22, 12, 21]

let item = [...new Set(arr)]

4、promise面试题 以下代码的执行结果是?(完)

const promise = new Promise((resolve, reject) => {
    console.log(1)
    resolve()
    console.log(2)
})
promise.then(() => {
    console.log(3)
})
console.log(4)

答案:1,2,4,3

解释:以上考察的是关于promise的原理,promise的构造函数是同步执行的,当new Promise的一瞬间,1,2 就立刻被执行,而 .then方法是异步执行的,当执行完1和2之后,会执行输出4,最后执行输出3

另:
1、初始态pending
2、成功态resolved
3、失败态rejected

状态可转化,但不可逆。

5、对象的合并、获取key、value值

// 扩展运算符可以用于合并两个对象
let ab = { ...a, ...b };
// 等同于
let ab = Object.assign({}, a, b);

// 获取到a对象的key值组成的数组
Object.keys(a)
// 获取到a对象的value值组成的数组
Object.values(a)

六、跨域(完)

跨域: 只要协议、域名和端口号有一个不相同就会产生跨域问题。同源策略是一个安全策略。同源,指的是协议,域名,端口相同。浏览器处于安全方面的考虑,只允许本域名下的接口交互,不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源。

1、webpack 里的proxy

devServer: {
    proxy: {  //配置跨域
      '/api': {
        target: 'http://121.121.67.254:8185/',  //这里后台的地址模拟的;应该填写你们真实的后台接口
        changOrigin: true,  //用于控制请求头中的post值,默认开启
        pathRewrite: {
          /* 重写路径,当我们在浏览器中看到请求的地址为:http://localhost:8080/api/core/getData/userInfo 时
            实际上访问的地址是:http://121.121.67.254:8185/core/getData/userInfo,因为重写了 /api
           */
          '^/api': '' 
        }
      },
    }
  }

2、Jsonp

面试官:说说JSONP请求吧。
我:JSONP请求首先是为了解决跨域问题而存在的一种民间解决方案balabala...
    浏览器存在同源安全机制balabala...
    通过标签的形式发请求balabala...
    需要和后端同学进行约束balabala...
    只能使用get请求balabala...
复制代码

3、webpack plugin (插件)

npm i -S webpack-dev-middleware 安装中间键,把前端和后端的服务绑在一起

中间件
let webpack = require('webpack')
let middle = require('webpack-dev-middleware')
let compiler = webpack(require('./webpack.config.js'))
app.use(middle(compiler))

4、cors (后端解决)

var allowCrossDomain = function(req,res,next) {
    // 请求源
    res.header("Access-Control-Allow-Origin", "*")
    // 请求头 token
    res.header("Access-Control-Allow-Headers", "*")
    // 请求方法 get post put del
    res.header("Access-Control-Allow-Methods", "*")
    next();
}
app.use(allowCrossDomain )

七、cookie、localStorage、sessionStorage的区别 (完)

共同点: 都是保存在浏览器端、且同源的

不同点:
cookie
1、可在在浏览器和服务器间来回传递。
2、存储大小限制:4k
3、只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭
4、作用域:同源窗口中都是共享的,只要浏览器不关闭,数据仍然存在。

sessionStorage
1、不会自动把数据发送给服务器,仅在本地保存。
2、存储大小限制:5M(字节)
3、仅在当前浏览器窗口关闭之前有效。
4、作用域:不在不同的浏览器窗口中共享,即使是同一个页面。

localStorage
1、不会自动把数据发送给服务器,仅在本地保存。
2、存储大小限制:5M(字节)。
3、始终有效,窗口或浏览器关闭也一直保存,本地存储,因此用作持久数据;
4、作用域:同源窗口中都是共享的;只要浏览器不关闭,数据仍然存在。

八、async 和 await 的区别

async:
1、定义异步函数。generate的语法糖,是异步的意思。打印函数名是promise对象,可以通过这个函数名称.then 这个方法。

await:
1、await只能写在async函数中,不能写在别处。等待的意思,等待某个动作的完成。

优点:async和await 属于es7语法。编写方便,提高程序效率,避免了回调地狱。

补充:promise和async和await的区别
promise es6语法,promise中包含catch,async需要自己定义catch
promise 提供的方法会多一些,all、race等方法,aync中是没有的。

九、箭头函数和普通函数的区别?

函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
不可以当作构造函数,也就是说不可以使用new命令,否则会报错
不可以使用arguments对象,该对象在函数体内不存在,如果要用可以使用Rest参数代替
不可以使用yield命令,因此箭头函数不能用作Generator函数

十、项目性能优化方案

减少http请求
减少DNS查询
使用CDN
避免重定向
图片懒加载
路由懒加载
减少DOM元素操作
使用外部js和css
压缩js、css、字体、图片等
使用iconfont字体图标、雪碧图等
避免图片的src为空
把样式表放在link中
把js放在页面的底部

十一、TypeScript

TypeScript 是 Microsoft 开发的JavaScript 的开源超集,用于在不破坏现有程序的情况下添加附加功能。
由于其独特的优势,例如,静态类型和许多速记符号,TypeScript 现在被前端和全栈开发人员广泛用于大型项目。

1、TypeScript 的主要特点是什么?

1、跨平台:TypeScript 编译器可以安装在任何操作系统上,包括 Windows、macOS 和 Linux。
2、ES6 特性:TypeScript 包含计划中的 ECMAScript 2015 (ES6) 的大部分特性,例如箭头函数。
3、面向对象的语言:TypeScript 提供所有标准的 OOP 功能,如类、接口和模块。
4、静态类型检查:TypeScript 使用静态类型并帮助在编译时进行类型检查。因此,你可以在编写代码时发现编译时错误,而无需运行脚本。
5、可选的静态类型:如果你习惯了 JavaScript 的动态类型,TypeScript 还允许可选的静态类型。

2、使用 TypeScript 有什么好处?

1、TypeScript 更具表现力,语法混乱更少。
2、TS会在编译时之前捕获逻辑错误,因此调试很容易。
3、静态类型使 TypeScript 比 JavaScript 的动态类型更易于阅读和结构化。
4、由于通用的转译,它可以跨平台使用,在客户端和服务器端项目中。

3、TypeScript 的内置数据类型有哪些?

// 基本数据类型

// 布尔类型 (boolean)
let flag: boolean = true

//数字类型 (number)
let num: number = 123

// 字符串类型 (string)
let str: string = "hello ts"  //字符串类型

// 数组类型 (Array)
// 1
let arr: number[] = [1, 2, 3, 4, 5]

// 2
let arr1: Array<string> = ["6", "7", "8", "9", "10"]


// 元祖类型 (tuple) 
// 可指定数组包含多种类型数据
let tup: [string, number, boolean] = ["123", 456, true]  //对应顺序要一致

// 枚举类型 (enum)
enum mode { success = 1, error = 0 } //if 不赋值打印索引值
let suc: mode = mode.success  // suc=1

// 任意类型 (any)
let all: any = "所有类型"

// null和undefined
let unde: string | undefined //定义未赋值,输出undefined

let nu: null | undefined // nu只能赋值 null

// void类型
// 一般定义方法没有返回值 return
function func(): void { }

function func1(): string {
    return "ts"
}

4、类型断言

有些时候,我们需要做一些“自己比编译器更清楚的知道自己在做什么”,这个时候就用到断言,告诉编译器:没错,就是这样的,就是要这么干。编译器也就假设:嗯,这个程序员已经进行了相关检查,不会有事的。

类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误。
“尖括号” 语法:<类型>值

let someValue: any = 'this is a string'
let strLength: number = (someValue).length

as 语法:值 as 类型

let someValue: any = 'this is a string'
let strLength: number = (someValue as string).length

十二、call()、apply()、bind()的异同

call()、apply()、bind()都是用于改变this指向的方法,不同点传参方式不太相同以及返回不同。

1、call( ) 是接收一个及其以上的参数,第一个参数表示this要指向的对象,其余参数表示调用函数需要传入的参数,返回调用函数的返回结果,属于立即执行函数;
2、apply( ) 是接收两个参数,第一个参数表示this要指向的对象,第二参数表示调用函数需要传入的参数所组成的数组,返回调用函数的返回结果,属于立即执行函数;
3、bind( ) 是接收一个及其以上的参数,和call()一致,但是其返回是一个函数,而不是调用函数的返回结果;

十三、删除数组的固定值

let a = [1, 2, 3. 4]
a.splice(a.indexOf('1'), 1)
a.filter(i => i !== '1')

十四、状态码

200 – 服务器成功返回网页
404 – 请求的网页不存在
500(服务器内部错误) 服务器遇到错误,无法完成请求。
503 – 服务器超时

1xx(临时响应)
表示临时响应并需要请求者继续执行操作的状态码。

100(继续) 请求者应当继续提出请求。服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
101(切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。

2xx (成功)
表示成功处理了请求的状态码。

200(成功) 服务器已成功处理了请求。通常,这表示服务器提供了请求的网页。如果是对您的 robots.txt 文件显示此状态码,则表示 Googlebot 已成功检索到该文件。
201(已创建) 请求成功并且服务器创建了新的资源。
202(已接受) 服务器已接受请求,但尚未处理。
203(非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
204(无内容) 服务器成功处理了请求,但没有返回任何内容。
205(重置内容) 服务器成功处理了请求,但没有返回任何内容。与 204 响应不同,此响应要求请求者重置文档视图(例如,清除表单内容以输入新内容)。
206(部分内容) 服务器成功处理了部分 GET 请求。

3xx (重定向)
要完成请求,需要进一步操作。通常,这些状态码用来重定向。Google 建议您在每次请求中使用重定向不要超过 5 次。您可以使用网站管理员工具查看一下 Googlebot 在抓取重定向网页时是否遇到问题。诊断下的网络抓取页列出了由于重定向错误导致 Googlebot 无法抓取的网址。

300(多种选择) 针对请求,服务器可执行多种操作。服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301(永久移动) 请求的网页已永久移动到新位置。服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。您应使用此代码告诉 Googlebot 某个网页或网站已永久移动到新位置。
302(临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来响应以后的请求。此代码与响应 GET 和 HEAD 请求的 301 代码类似,会自动将请求者转到不同的位置,但您不应使用此代码来告诉 Googlebot 某个网页或网站已经移动,因为 Googlebot 会继续抓取原有位置并编制索引。
303(查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。对于除 HEAD 之外的所有请求,服务器会自动转到其他位置。
304(未修改)
自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。
如果网页自请求者上次请求后再也没有更改过,您应将服务器配置为返回此响应(称为 If-Modified-Since HTTP 标头)。服务器可以告诉 Googlebot 自从上次抓取后网页没有变更,进而节省带宽和开销。
305(使用代理) 请求者只能使用代理访问请求的网页。如果服务器返回此响应,还表示请求者应使用代理。
307(临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来响应以后的请求。此代码与响应 GET 和 HEAD 请求的 301 代码类似,会自动将请求者转到不同的位置,但您不应使用此代码来告诉 Googlebot 某个页面或网站已经移动,因为 Googlebot 会继续抓取原有位置并编制索引。

4xx(请求错误)
这些状态码表示请求可能出错,妨碍了服务器的处理。

400(错误请求) 服务器不理解请求的语法。
401(未授权) 请求要求身份验证。对于登录后请求的网页,服务器可能返回此响应。
403(禁止) 服务器拒绝请求。如果您在 Googlebot 尝试抓取您网站上的有效网页时看到此状态码(您可以在 Google 网站管理员工具诊断下的网络抓取页面上看到此信息),可能是您的服务器或主机拒绝了 Googlebot 访问。
404(未找到)
服务器找不到请求的网页。例如,对于服务器上不存在的网页经常会返回此代码。

如果您的网站上没有 robots.txt 文件,而您在 Google 网站管理员工具“诊断”标签的 robots.txt 页上看到此状态码,则这是正确的状态码。但是,如果您有 robots.txt 文件而又看到此状态码,则说明您的 robots.txt 文件可能命名错误或位于错误的位置(该文件应当位于顶级域,名为 robots.txt)。

如果对于 Googlebot 抓取的网址看到此状态码(在”诊断”标签的 HTTP 错误页面上),则表示 Googlebot 跟随的可能是另一个页面的无效链接(是旧链接或输入有误的链接)。

405(方法禁用) 禁用请求中指定的方法。
406(不接受) 无法使用请求的内容特性响应请求的网页。
407(需要代理授权) 此状态码与
401(未授权)类似,但指定请求者应当授权使用代理。如果服务器返回此响应,还表示请求者应当使用代理。
408(请求超时) 服务器等候请求时发生超时。
409(冲突) 服务器在完成请求时发生冲突。服务器必须在响应中包含有关冲突的信息。服务器在响应与前一个请求相冲突的 PUT 请求时可能会返回此代码,以及两个请求的差异列表。
410(已删除) 如果请求的资源已永久删除,服务器就会返回此响应。该代码与 404(未找到)代码类似,但在资源以前存在而现在不存在的情况下,有时会用来替代 404 代码。如果资源已永久移动,您应使用 301 指定资源的新位置。
411(需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
412(未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
413(请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414(请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
415(不支持的媒体类型) 请求的格式不受请求页面的支持。
416(请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态码。
417(未满足期望值) 服务器未满足”期望”请求标头字段的要求。

5xx(服务器错误)
这些状态码表示服务器在处理请求时发生内部错误。这些错误可能是服务器本身的错误,而不是请求出错。

500(服务器内部错误) 服务器遇到错误,无法完成请求。
501(尚未实施) 服务器不具备完成请求的功能。例如,服务器无法识别请求方法时可能会返回此代码。
502(错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503(服务不可用) 服务器目前无法使用(由于超载或停机维护)。通常,这只是暂时状态。
504(网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505(HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。

十五、vue生命周期及父子组件中的运行顺序

前端面试题_第2张图片

十六、Vuex

1、state: 统一定义公共数据(类似于data(){return {a:1, b:2,xxxxxx}})
2、mutations : 使用它来修改数据(类似于methods)
3、getters: 类似于computed(计算属性,对现有的状态进行计算得到新的数据-------派生 )
4、actions: 发起异步请求
5、modules: 模块拆分

同步赋值:this.$store.commit(‘setUrl’, { url, host} )

异步赋值:

new Vuex.store({
  // 省略其他...
  actions: {
    // context对象会自动传入,它与store实例具有相同的方法和属性
    action的名字: function(context, 载荷) {
      // 1. 发异步请求, 请求数据
      
      // 2. commit调用mutation来修改数据
      
      // context.commit('mutation名', 载荷)
    }
  }
})

十七、JSON.parse和JSON.stringify的用法

JSON.parse()方法将JSON格式字符串转换为js对象
JSON.stringify方法将js对象转换为JSON格式字符串

你可能感兴趣的:(javascript,javascript,前端,vue.js)