前言
上一篇 前端面试题-JavaScript(一), 感兴趣的小伙伴也可以移步这里查看 完整版JavaScript面试题,面试题会不定期更新加进去一些个人工作中遇到的或者认为比较重要的东西,后面会涉及到前端的各个方面,感兴趣的小伙伴可以关注哦!
如果文章中有出现纰漏、错误之处,还请看到的小伙伴留言指正,先行谢过
以下 ↓
1. 同步和异步的区别,怎么异步加载 JavaScript
同步模式
同步模式,又称阻塞模式。javascript
在默认情况下是会阻塞加载的。当前面的 javascript
请求没有处理和执行完时,会阻止浏览器的后续处理
异步模式
异步加载又叫非阻塞,浏览器在下载执行 js
同时,还会继续进行后续页面的处理
异步加载 JavaScript
- 动态添加
script
标签 defer
async
defer
属性和
async
都是属于
script
标签上面的属性,两者都能实现
JavaScript
的异步加载。不同之处在于:
async
在异步加载完成的时候就马上开始执行了,
defer
会等到
html
加载完毕之后再执行
2. 跨域问题的产生,怎么解决它
由于浏览器的
同源策略,在出现 域名、端口、协议有一种不一致时,就会出现跨域,属于浏览器的一种安全限制。
解决跨域问题有很多种方式,常用的就是以下几种:
-
jsonp
跨域:动态创建script
,再请求一个带参网址实现跨域通信.缺点就是只能实现get
一种请求 -
document.domain + iframe
跨域:两个页面都通过js强制设置document.domain
为基础主域,就实现了同域.但是仅限主域相同,子域不同的跨域应用场景 - 跨域资源共享(CORS):只服务端设置
Access-Control-Allow-Origin
即可,前端无须设置,若要带cookie
请求:前后端都需要设置 -
nginx
反向代理接口跨域:同源策略是浏览器的安全策略,不是HTTP
协议的一部分。服务器端调用HTTP
接口只是使用HTTP
协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题 -
WebSocket
协议跨域
3. 对 this 的理解
在 JavaScript
中,研究 this
一般都是 this
的指向问题,核心就是 this
永远指向最终调用它的那个对象,除非改变 this
指向或者箭头函数那种特殊情况
function test() {
console.log(this);
}
test() // window
var obj = {
foo: function () { console.log(this.bar) },
bar: 1
};
var foo = obj.foo;
var bar = 2;
obj.foo() // 1
foo() // 2
// 函数调用的环境不同,所得到的结果也是不一样的
4. apply()、call()和 bind() 是做什么的,它们有什么区别
相同点:三者都可以改变 this 的指向
不同点:
- apply 方法传入两个参数:一个是作为函数上下文的对象,另外一个是作为函数参数所组成的数组
var obj = {
name : 'sss'
}
function func(firstName, lastName){
console.log(firstName + ' ' + this.name + ' ' + lastName);
}
func.apply(obj, ['A', 'B']); // A sss B
-
call
方法第一个参数也是作为函数上下文的对象,但是后面传入的是一个参数列表,而不是单个数组
var obj = {
name: 'sss'
}
function func(firstName, lastName) {
console.log(firstName + ' ' + this.name + ' ' + lastName);
}
func.call(obj, 'C', 'D'); // C sss D
-
bind
接受的参数有两部分,第一个参数是是作为函数上下文的对象,第二部分参数是个列表,可以接受多个参数
var obj = {
name: 'sss'
}
function func() {
console.log(this.name);
}
var func1 = func.bind(null, 'xixi');
func1();
apply
、
call
方法都会使函数立即执行,因此它们也可以用来调用函数
bind
方法不会立即执行,而是返回一个改变了上下文this
后的函数。而原函数func
中的this
并没有被改变,依旧指向全局对象window
bind
在传递参数的时候会将自己带过去的参数排在原函数参数之前
function func(a, b, c) {
console.log(a, b, c);
}
var func1 = func.bind(this, 'xixi');
func1(1,2) // xixi 1 2
5. 什么是内存泄漏,哪些操作会造成内存泄漏
内存泄漏:是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束
可能造成内存泄漏的操作:
- 意外的全局变量
- 闭包
- 循环引用
- 被遗忘的定时器或者回调函数
你可能还需要知道 垃圾回收机制 此外,高程上面对垃圾回收机制的介绍也很全面,有兴趣的小伙伴可以看看
6. 什么是事件代理,它的原理是什么
事件代理:通俗来说就是将元素的事件委托给它的父级或者更外级元素处理
原理:利用事件冒泡机制实现的
优点:只需要将同类元素的事件委托给父级或者更外级的元素,不需要给所有元素都绑定事件,减少内存空间占用,提升性能; 动态新增的元素无需重新绑定事件
7. 对AMD和CMD的理解,它们有什么区别
AMD
和
CMD
都是为了解决浏览器端模块化问题而产生的,
AMD
规范对应的库函数有
Require.js
,
CMD
规范是在国内发展起来的,对应的库函数有
Sea.js
AMD和CMD最大的区别是对依赖模块的执行时机处理不同
1、AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
2、CMD推崇就近依赖,只有在用到某个模块的时候再去require
8. 对ES6的了解
ECMAScript 6.0 是 JavaScript 语言的下一代标准
新增的特性:
- 声明变量的方式
let
const
- 变量解构赋值
- 字符串新增方法
includes()
startsWith()
endsWith()
等 - 数组新增方法
Array.from()
Array.of()
entries()
keys()
values()
等 - 对象简洁写法以及新增方法
Object.is()
Object.assign()
entries()
keys()
values()
等 - 箭头函数、
rest
参数、函数参数默认值等 - 新的数据结构:
Set
和Map
Proxy
-
Promise
对象 -
async
函数await
命令 -
Class
类 -
Module
体系 模块的加载和输出方式
了解更多,参考 ES6入门-阮一峰
9. 箭头函数有什么特点
ES6 允许使用“箭头”(=>)定义函数
var f = v => v;
// 等同于
var f = function (v) {
return v;
}
注意点:
- 函数体内的
this
对象,就是定义时所在的对象,而不是使用时所在的对象 - 不可以当作构造函数,也就是说,不可以使用
new
命令,否则会抛出一个错误 - 不可以使用
arguments
对象,该对象在函数体内不存在。如果要用,可以用rest
参数代替
10. Promise 对象的了解
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大.所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果 –ES6入门-阮一峰
Promise
对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
特点:
- 对象的状态不受外界影响
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果
-
Promise
新建后就会立即执行
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
})
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数
promise.then(function(value) {
// success
}, function(error) {
// failure
})
then
方法返回的是一个新的Promise实例
Promise.prototype.catch
用于指定发生错误时的回调函数,具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch
语句捕获
getJSON('/post/1.json').then(function(post) {
return getJSON(post.commentURL);
}).then(function(comments) {
// some code
}).catch(function(error) {
// 处理前面三个Promise产生的错误
});
catch
方法返回的还是一个
Promise
对象,因此后面还可以接着调用
then
方法
出去上述方法,Promise还有其他用法,小伙伴们可以在这里查看大佬写的文章 ES6入门-阮一峰
11. async 函数以及 awit 命令
async
函数是什么?一句话,它就是
Generator
函数的语法糖
了解Generator函数的小伙伴,这里 传送门
async
特点:
async
函数返回一个
Promise
对象,可以使用
then
方法添加回调函数。当函数执行的时候,一旦遇到
await
就会先返回,等到异步操作完成,再接着执行函数体内后面的语句
async
函数内部return
语句返回的值,会成为then
方法回调函数的参数
async
函数返回的Promise
对象,必须等到内部所有await
命令后面的Promise
对象执行完,才会发生状态改变,除非遇到return
语句或者抛出错误
async
函数内部抛出错误,会导致返回的Promise
对象变为reject
状态。抛出的错误对象会被catch
方法回调函数接收到
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);
await
命令:
await
命令后面是一个
Promise
对象,返回该对象的结果。如果不是
Promise
对象,就直接返回对应的值
async function f() {
// 等同于
// return 123;
return await 123;
}
f().then(v => console.log(v))
// 123
await
命令后面是一个
thenable
对象(即定义then方法的对象),那么
await
会将其等同于
Promise
对象.也就是说就算一个对象不是
Promise
对象,但是只要它有
then
这个方法,
await
也会将它等同于
Promise
对象
使用注意点:
-
await
命令后面的Promise
对象,运行结果可能是rejected
,所以最好把await
命令放在try...catch
代码块中 - 多个
await
命令后面的异步操作,如果不存在继发关系,最好让它们同时触发 -
await
命令只能用在async
函数之中,如果用在普通函数,就会报错
了解更多,请点击 这里
12. export 与 export default有什么区别
export
与
export default
均可用于导出常量、函数、文件、模块等在一个文件或模块中,
export
、import
可以有多个,export default
仅有一个通过
export
方式导出,在导入时要加{ }
,export default
则不需要使用
export default
命令,为模块指定默认输出,这样就不需要知道所要加载模块的变量名;export
加载的时候需要知道加载模块的变量名
export default
命令的本质是将后面的值,赋给default
变量,所以可以直接将一个值写在export default
之后
13. 前端性能优化
参见 雅虎14条前端性能优化
14. 对JS引擎执行机制的理解
首选明确两点:
JavaScript
是单线程语言
JavaScript
的Event Loop
是JS
的执行机制, 也就是事件循环
console.log(1)
setTimeout(function(){
console.log(2)
},0)
console.log(3)
// 1 3 2
JavaScript
将任务分为同步任务和异步任务,执行机制就是先执行同步任务,将同步任务加入到主线程,遇到异步任务就先加入到
event table
,当所有的同步任务执行完毕,如果有可执行的异步任务,再将其加入到主线程中执行
视频详解,移步 这里
setTimeout(function(){console.log(1);},0);
new Promise(function(resolve){
console.log(2);
for(var i = 0; i < 10000; i++){
i == 99 && resolve();
}
}).then(function(){
console.log(3)
});
console.log(4);
// 2 4 3 1
在异步任务中,定时器也属于特殊的存在。有人将其称之为 宏任务、微任务,定时器就属于宏任务的范畴。
参考 JS引擎的执行机制
后记
总结的过程,自己确实也获益颇多,感谢前行的小伙伴。
GitHub完整版面试题,欢迎小伙伴们star
关注
预祝大家都能找到自己满意的工作
以上