前端面试题---进阶篇
ES6,WebPack,Git面试题
ES6面试题
面试题:var、let、const区别
var
用
var
声明的变量既是全局变量,也是顶层变量注意:顶层对象,在浏览器环境指的是
window
对象,在Node
指的是global
对象var a = 10; console.log(window.a) // 10
使用
var
声明的变量存在变量提升的情况console.log(a) // undefined var a = 20
在编译阶段,编译器会将其变成以下执行
var a console.log(a) a = 20
使用
var
,我们能够对一个变量进行多次声明,后面声明的变量会覆盖前面的变量声明var a = 20 var a = 30 console.log(a) // 30
在函数中使用使用
var
声明变量时候,该变量是局部的var a = 20 function change(){ var a = 30 } change() console.log(a) // 20
而如果在函数内不使用
var
,该变量是全局的let
let
是ES6
新增的命令,用来声明变量用法类似于
var
,但是所声明的变量,只在let
命令所在的代码块内有效{ let a = 20 } console.log(a) // ReferenceError: a is not defined.
不存在变量提升
console.log(a) // 报错ReferenceError let a = 2
这表示在声明它之前,变量
a
是不存在的,这时如果用到它,就会抛出一个错误只要块级作用域内存在
let
命令,这个区域就不再受外部影响var a = 123 if (true) { a = 'abc' // ReferenceError let a; }
使用
let
声明变量前,该变量都不可用,也就是大家常说的“暂时性死区”最后,
let
不允许在相同作用域中重复声明let a = 20 let a = 30 // Uncaught SyntaxError: Identifier 'a' has already been declared
注意的是相同作用域,下面这种情况是不会报错的
let a = 20 { let a = 30 }
因此,我们不能在函数内部重新声明参数
function func(arg) { let arg; } func() // Uncaught SyntaxError: Identifier 'arg' has already been declared
const
const
声明一个只读的常量,一旦声明,常量的值就不能改变const a = 1 a = 3 // TypeError: Assignment to constant variable.
这意味着,
const
一旦声明变量,就必须立即初始化,不能留到以后赋值const a; // SyntaxError: Missing initializer in const declaration
如果之前用
var
或let
声明过变量,再用const
声明同样会报错var a = 20 let b = 20 const a = 30 const b = 30 // 都会报错
const
实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动对于简单类型的数据,值就保存在变量指向的那个内存地址,因此等同于常量
对于复杂类型的数据,变量指向的内存地址,保存的只是一个指向实际数据的指针,
const
只能保证这个指针是固定的,并不能确保改变量的结构不变const foo = {}; // 为 foo 添加一个属性,可以成功 foo.prop = 123; foo.prop // 123 // 将 foo 指向另一个对象,就会报错 foo = {}; // TypeError: "foo" is read-only
其它情况,
const
与let
一致
面试题:将下列对象进行合并
$.extend()
var obj1= {'a': 1};
var obj2= {'b': 1}
var c = $.extend(obj1, obj2);
面试题:箭头函数和普通函数有什么区别?
1、箭头函数使用箭头定义,普通函数中没有
2、箭头函数都是匿名函数
普通函数可以有匿名函数,也可以有具体名函数,但是箭头函数都是匿名函数。3、箭头函数不能用于构造函数,不能使用new
普通函数可以用于构造函数,以此创建对象实例。4、箭头函数中this的指向不同
在普通函数中,this总是指向调用它的对象,如果用作构造函数,this指向创建的对象实例。5、箭头函数本身不创建this
也可以说箭头函数本身没有this,但是它在声明时可以捕获其所在上下文的this供自己使用。
注意:this一旦被捕获,就不再发生变化6、箭头函数不绑定arguments,取而代之用rest参数解决
每一个普通函数调用后都具有一个arguments对象,用来存储实际传递的参数。但是箭头函数并没有此对象。总结:
(1).箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()
(2).普通函数的this指向调用它的那个对象
面试题:Promise有几种状态以及解决回调地狱
三种状态:pending、fulfilled、rejected(未决定,履行,拒绝),同一时间只能存在一种状态,且状态一旦改变就不能再变。
promise是一个构造函数,promise对象有resolve和reject两个参数。
resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。promise的优缺点
优点:
1.Promise 分离了异步数据获取和业务逻辑,有利于代码复用。
2.可以采用链式写法
3.可以用于解决回调地狱。
缺点:
1、无法取消Promise,一旦新建它就会立即执行,无法中途取消。
2、如果不设置回调函数,promise内部抛出的错误,不会反应到外部。
3、当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
回调地狱:
就是一层一层嵌套,会极大的影响代码的可读性和逻辑,会引起代码难以维护等问题。
用promise解决回调地狱问题:
function getTea(){ return new Promise(function(resolve,reject){ setTimeout(() => { resolve('奶茶') //通过resolve来将异步数据传出 },1000) }) } function getHotpot(){ return new Promise(function(resolve,reject){ setTimeout(() => { resolve('火锅') //通过resolve来将异步数据传出 },2000) }) } //先吃火锅,后喝奶茶 getHotpot().then(function(data){ //通过then来拿到异步数据 console.log(data); return getTea(); }).then(function(data){ //通过then来拿到异步数据 console.log(data) })
现在用解决回调地狱更好的办法,就是用async和await方法:
//async函数 async function getData(){ //直接获取resolve传出来的异步数据 let hotPot = await getHotpot(); console.log(hotPot); let Tea = await getTea(); console.log(Tea); } getData();
Promise.all
Promise.all() 方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个 Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组。此实例在
iterable
参数内所有的promise
都“完成(resolved)”或参数中不包含promise
时回调完成(resolve);如果参数中promise
有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败promise
的结果。好处是可以异步的完成调用,可以节约时间,比如一个界面调用三个接口,调用第一个接口需要一秒钟,第二个需要两秒钟,第三个需要三秒钟,但是如果使用promise.all,就不会造成时间叠加,而是只需要三秒钟就可以了。缺点是如果有一个接口调用失败了,就会导致全部接口调用失败,而且只会返回第一个失败的promise。
面试题:find和filter的区别
find和filter都是数组的查找方法,但是会有一些细节的差别:
find
- 返回值是一个对象,只返回符合条件的第一项
- 找不到会返回undefined
filter
- 返回值是一个数组,数组里面是符合条件的每一个对象以逗号隔开,可以有多个
- 找不到会返回空数组 [ ],不会返回undefined
总结:
find和filter的返回值是大家比较容易搞混的,我们可以这样记:find字面意思是寻找,但只会寻找第一个符合条件的,既然最终是返回一个,那么肯定就是找的的这一项;找不到就只能返回undefined。
filter字面意思是筛选,肯定是把所有符合条件的都找出来,这么多符合项肯定是要放在一个容器里面的,那这个容器就是一个数组,找不到自然是返回空数组呗。
面试题:some和every的区别
every()与some()方法都是JS中数组的迭代方法。
every()是对数组中每一项运行给定函数,如果该函数对每一项返回true,则返回true。
some()是对数组中每一项运行给定函数,如果该函数对任一项返回true,则返回true。
webpack面试题
面试题:webpack是什么?
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器,可以使用它管理项目中的模块依赖,并编译输出模块所需的静态文件。它可以很好地管理、打包开发中所用到的HTML,CSS,JavaScript和静态文件(图片,字体)等,让开发更高效。对于不同类型的依赖,webpack有对应的模块加载器,而且会分析模块间的依赖关系,最后合并生成优化的静态资源。
面试题:有哪些常见的Loader?他们是解决什么问题的?
- file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
- url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
- source-map-loader:加载额外的 Source Map 文件,以方便断点调试
- image-loader:加载并且压缩图片文件
- babel-loader:把 ES6 转换成 ES5
- css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
- style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
- eslint-loader:通过 ESLint 检查 JavaScript 代码
面试题:有哪些常见的Plugin?他们是解决什么问题的?
- define-plugin:定义环境变量
- commons-chunk-plugin:提取公共代码
- uglifyjs-webpack-plugin:通过
UglifyES
压缩ES6
代码
面试题:Loader和Plugin的不同?
- Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到
loader
。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。- Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
出处:关于webpack的面试题总结 - 知乎 (zhihu.com)
Git面试题
面试题:Git是什么?
GIT,全称是分布式版本控制系统,git通常在编程中会用到,并且git支持分布式部署,可以有效、高速的处理从很小到非常大的项目版本管理。分布式相比于集中式的最大区别在于开发者可以提交到本地,每个开发者通过克隆(git clone),在本地机器上拷贝一个完整的Git仓库。
说白了就是一个版本控制工具,帮助大家管理自己的代码。
版本库又名仓库(repository),可以简单理解成一个目录(存放好多版本的目录),目录里所有文件都被Git管理起来,每个文件的修改,删除,Git都会跟踪,以便任何时候都可以追踪历史或者在将来某一时刻可以还原修改。
面试题:git常用命令
git init:初始化一个git仓库
git clone:clone一个git仓库
git add file或者git add . :新增文件的命令
git commit 将缓存区内容添加到仓库中,可以在后面加-m选项,以在命令行中提供提交注释,格式如下:
git commit -m "第一次版本提交"
如果你觉得 每次 commit之前要add一下,想跳过add这一步,可以直接使用 -a选项,如:
git commit -am "第一次版本提交"
面试题:解决冲突
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
用
git log --graph
命令可以看到分支合并图。
面试题:GitFlow
Git Flow 的常用分支
- 生产分支(master)
Master分支是仓库的主分支,这个分支包含最近发布到生产环境的代码,最近发布的Release, 这个分支只能从其他分支合并,不能在这个分支直接修改
- 补丁分支(hotfix)
当我们在生产环境发现新的Bug时候,我们需要基于master分支创建一个Hotfix分支,然后在Hotfix分支上修复bug,完成Hotfix后,我们要把hotfix分支合并回Master和Develop分支
- 发布分支(release)
当你需要发布一个新功能的时候,要基于Develop分支创建一个Release分支,在Release分支测试并修复bug,完成release后,把release合并到master和develop分支
- 开发分支(develop)
这个分支是我们的主开发分支,包含所有要发布到下一个Release的代码,这个主要合并与其他分支,比如Feature分支
- 功能分支(feature)
feature分支主要是用来开发一个新的功能,一旦开发完成,我们合并回Develop分支进入下一个Release
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)