前言上一篇 前端面试题-JavaScript(一), 感兴趣的小伙伴也可以移步这里查看 完整版JavaScript面试题,面试题会不定期更新加进去一些个人工作中遇到的或者认为比较重要的东西,后面会涉及到前端的各个方面,感兴趣的小伙伴可以关注哦!如果文章中有出现纰漏、错误之处,还请看到的小伙伴留言指正,先行谢过以下 ↓1. 同步和异步的区别,怎么异步加载 JavaScript同步模式同步模式,又称阻塞模式。javascript 在默认情况下是会阻塞加载的。当前面的 javascript 请求没有处理和执行完时,会阻止浏览器的后续处理异步模式异步加载又叫非阻塞,浏览器在下载执行 js 同时,还会继续进行后续页面的处理异步加载 JavaScript动态添加 script 标签deferasyncdefer属性和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() // windowvar obj = { foo: function () { console.log(this.bar) }, bar: 1};var foo = obj.foo;var bar = 2;obj.foo() // 1foo() // 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 Bcall 方法第一个参数也是作为函数上下文的对象,但是后面传入的是一个参数列表,而不是单个数组var obj = { name: ‘sss’}function func(firstName, lastName) { console.log(firstName + ’ ’ + this.name + ’ ’ + lastName);}func.call(obj, ‘C’, ‘D’); // C sss Dbind 接受的参数有两部分,第一个参数是是作为函数上下文的对象,第二部分参数是个列表,可以接受多个参数var obj = { name: ‘sss’}function func() { console.log(this.name);}var func1 = func.bind(null, ‘xixi’);func1();apply、call 方法都会使函数立即执行,因此它们也可以用来调用函数bind 方法不会立即执行,而是返回一个改变了上下文 this 后的函数。而原函数 func 中的 this 并没有被改变,依旧指向全局对象 windowbind 在传递参数的时候会将自己带过去的参数排在原函数参数之前function func(a, b, c) { console.log(a, b, c);}var func1 = func.bind(this, ‘xixi’);func1(1,2) // xixi 1 25. 什么是内存泄漏,哪些操作会造成内存泄漏内存泄漏:是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束可能造成内存泄漏的操作:意外的全局变量闭包循环引用被遗忘的定时器或者回调函数你可能还需要知道 垃圾回收机制 此外,高程上面对垃圾回收机制的介绍也很全面,有兴趣的小伙伴可以看看6. 什么是事件代理,它的原理是什么事件代理:通俗来说就是将元素的事件委托给它的父级或者更外级元素处理原理:利用事件冒泡机制实现的优点:只需要将同类元素的事件委托给父级或者更外级的元素,不需要给所有元素都绑定事件,减少内存空间占用,提升性能; 动态新增的元素无需重新绑定事件7. 对AMD和CMD的理解,它们有什么区别AMD和CMD都是为了解决浏览器端模块化问题而产生的,AMD规范对应的库函数有 Require.js,CMD规范是在国内发展起来的,对应的库函数有Sea.jsAMD和CMD最大的区别是对依赖模块的执行时机处理不同1、AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块 2、CMD推崇就近依赖,只有在用到某个模块的时候再去require参考:AMD-中文版 CMD-规范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 和 MapProxyPromise对象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))// 123await 命令后面是一个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 2JavaScript 将任务分为同步任务和异步任务,执行机制就是先执行同步任务,将同步任务加入到主线程,遇到异步任务就先加入到 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引擎的执行机制后记总结的过程,自己确实也获益颇多,感谢前行的小伙伴。预祝大家都能找到自己满意的工作以上