渲染页面6、连接结束(断开连接过程是四次挥手的过程)
4、服务器处理请求并返回HTTP报文
5、浏览器解析渲染页面
6、连接结束(断开连接过程是四次挥手的过程)
8、Promise构造函数是同步执行还是异步执行,那么 then 方法呢?
Promise构造函数是同步执行的,then方法是异步执行的
9、setTimeout、Promise、async/await 的区别?
事件循环(EventLoop)中分为宏任务队列和微任务队列
setTimeout的回调函数放到宏任务队列里,等到执行栈清空以后执行
promise.then里的回调函数会放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行
async函数表示函数里面可能会有异步方法,await后面跟一个表达式。async方法执行时,遇到await会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行
补充:promise是es6新增一种异步编程的方案
async/await是es7中新增的异步编程的方案。
经典案例:今日头条的面试题,执行的顺序
<pre class="has">async function async1 () { console.log('async1 start') // 2 await async2(); console.log('async1 end') //7}async function async2 () { console.log('async2') //3}console.log('script start') // 1setTimeout(function () { console.log('setTimeout') //8}, 0)async1();new Promise (function (resolve) { console.log('promise1') //4 resolve();}).then (function () { console.log('promise2') //6})console.log('script end') //5运行结果:1、 script start2、 async1 start3、 async24、 promise15、 script end6、 promise27、 async1 end8、 setTimeout
</pre>
10、forEach、for in、for of三者区别
forEach:用来遍历数组,对数组中的每个元素执行一次提供的函数,不改变原数组,无返回值,undefined。
for in 一般常用来遍历对象或json。
for of数组对象都可以遍历。其中遍历对象使用Object.keys()
例:arr.forEach(function(value,index,arr){代码段})
例:let obj={a:1,b:2} for(let o in obj){console.log(o) //a b }
例:letarr=[‘China’,’korea’] let obj={a:1,b:2}
for(let o of arr){console.log(o) // China Korea}
for(let o of Object.keys(obj)){//直接写for(let o of obj)报错
console.log(o) }// ab 对象中的键
11、手写一个Promise(中高级必考)什么是promise?promise是用来干啥的?解决了什么问题?
Promise是异步编程的一个解决方案,主要用来解决两个问题:1、解决异步的问题,2、解决回调地狱的,就是第一个函数的输出是第二个函数的输入的这种现象。
<pre class="has">let promise=new Promise((resolve,reject)=>{If(异步操作成功){resolve(value);}else{reject(error); //操作失败}})promise.then(function(value){ //success },function(error){ //failure }) //promise.then()两个参数,第二个参数可选
</pre>
Promise对象的三种状态:pending(正在进行)、fulfilled(成功)、rejected(失败)。
状态只能pending到fulfilled或者pending到rejected,状态一旦改变不能再变。
12、对象、数组的深拷贝浅拷贝
浅拷贝:就是流于表面的拷贝方式,浅拷贝只拷贝的对象的地址,也就是说两个对象指向的是同一地址,修改其中的一个对象的属性,另一个对象的属性也会修改。
深拷贝:完全拷贝,拷贝之后新旧数据完全分离,不再共用对象类型的属性值,不会相互影响。
13、手写一个js深拷贝(先理解什么是深拷贝)
乞丐版:
<pre class="has">01、var newObj=JSON.parse(JSON.stringify(obj))无法复制函数,丢失原型链,对于多维数组也有效02、var newArr=arr.slice() 或者arr.concat() 只能实现一维数组的深拷贝03、var […newArr]=arres6扩展运算法实现数组的深拷贝(当然数组中没有属性值没有对象的时候)04、var {…obj2}=obj05、对象只有一层的话可以使用Object.assign()函数var newobj=Object.assign({},obj)
</pre>
面试够用版(判断是数组还是对象,新建一个数组或者对象,通过forin循环数组对象,完成深拷贝)递归拷贝
<pre class="has">function deepCopy(obj){ //判断是否是简单数据类型if(typeof obj == "object"){ //复杂数据类型 var result = obj.constructor == Array ? [] : {}; for(let i in obj){ result[i] = typeof obj[i] == "object" ?deepCopy(obj[i]) : obj[i]; } //递归判断 }else { //简单数据类型 直接 == 赋值 var result = obj; } return result;}
</pre>
14、数组去重手写
利用es6中Set去重
<pre class="has">var arr = [1,2,2,23,23,undefined,undefined]; var newarr = Array.from(new Set(arr)) console.log(newarr) // [1, 2, 23, undefined]补充:ES6提供了一个新的数据结构Set,本身是一个构造函数,用来生成Set的数据结构。类似于数组,但是成员的属性都是唯一的,没有重复的值。
</pre>
双重for循环+splice()方法
<pre class="has">function single(arr){ for(var i=0;i for(var j=i+1;j if(arr[i]==arr[j]){ arr.splice(j,1); j--; //arr的长度变了 } }} return arr;}var arr = [1,2,2,23,23,undefined,undefined]; console.log(single(arr)) // [1, 2, 23, undefined]
</pre>
利用indexOf去重
<pre class="has">var arr = [1,2,2,23,23,undefined,undefined]; var newapp=[];for(var i=0;iif(newapp.indexOf(arr[i])===-1){newapp.push(arr[i])}} console.log(newapp) // [1, 2, 23, undefined]
</pre>
新建一个空数组,for循环判断新数组中是否存在原数组中元素,如果有相同的值则跳过,不相同push到新数组。
15、冒泡排序和选择排序
冒泡排序:相邻两个元素比较
相邻两个元素进行比较,将一个数组中数字使用循环进行升序或排序的
<pre class="has"> arr = [1, 2, 3, 4] for (var j = 0; j < arr.length; j++) { for (var i = 0; i < arr.length; i++) { if (arr[i] < arr[i + 1]) { var a = arr[i] arr[i] = arr[i + 1] arr[i + 1] = a; } } }
</pre>
选择排序:先找值
这种排序方式先找最大的,排在最左侧,然后找第二个往左靠。。。。
<pre class="has">arr = [1, 2, 3, 4] for (var i = 0; i < arr.length - 1; i++) { for (var j = i + 1; j < arr.length; j++) { if (arr[i] < arr[j]) { tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } } }
</pre>
冒泡排序和顺序排序(划重点)。
(1)冒泡排序是比较相邻位置的两个数,而选择排序是按顺序比较,找最大值或者最小值;
(2)冒泡排序每一轮比较后,位置不对都需要换位置,选择排序每一轮比较都只需要换一次位置;
(3)冒泡排序是通过数去找位置,选择排序是给定位置去找数;
总结:一般选择排序优于冒泡排序。因为每次排序只需要交换一位置。冒泡排序比较耗性能。
16、浅谈async/await
1、async声明一个异步asyncfunction fun(){….}
自动将常规的函数转换成Promise ,返回值也是一个Promise对象。
只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
异步函数内部可以使用await
2、await等待异步功能执行 varresult=awaitnewPromise()
放置在Promise调用之前js 递归遍历多维数组,await强制其他代码等待,直到Promise完成并返回结果
只能与Promise一起使用,不适于回调。
只能在async函数内部使用。
17、事件循环
<pre class="has">function printing() { console.log(1); setTimeout(function() { console.log(2); }, 1000); setTimeout(function() { console.log(3); }, 0); console.log(4); } // 1 4 3 2
</pre>
理解:javascritpt是一门单线程的语言。
js分为同步任务和异步任务。事件循环分为宏任务和微任务。
同步任务在主线程上执行,形成一个执行栈,主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就在任务队列中放置一个事件。
一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,将可执行的异步任务添加到执行栈中,开始执行。
执行顺序:执行栈中的任务----事件循环中宏任务------事件循环中的微任务
同步任务交给主线程,主线程之外事件触发线程管理一个任务队列,为异步任务。
18、ajax请求的时候get 和post方式的区别
1、get请求会将参数跟在url后面进行参数传递,而post请求则是作为http消息的实体内容发送给web服务器。
2、get提交的数据大小有限制,这个限制是url的整体长度而不是参数的长度。post提交没有这个限制。
3、get请求的数据会被浏览器缓存起来,带来严重的安全问题,而post相对来说可以避免这些问题。
4、一般情况下。Get请求用来请求数据,post请求用来提交数据。
19、Javascript垃圾(GC)回收机制
Javascript垃圾回收机制原理:为了防止内存泄漏,垃圾回收机制会定期的清理哪些不再用到内存变量,然后释放其内存。
现在各大浏览器的通常采用的垃圾回收机制的两种方法:标记清除、引用计数
Js最常用的垃圾回收方式是标记清除,当变量进入环境时,将这个变量标记为“进入环境”,当这个变量离开环境时标记“离开环境”。标记为‘离开环境’的就回收内存。
20、闭包是什么,有什么特性,对页面有什么影响
闭包是指有权访问另—个函数作用域中变量的函数。创建闭包的最常见的方式就是在—个函数内创建另—个函数,通过另—个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。
闭包的特性:
1.函数内再嵌套函数
2.内部函数可以引用外层的参数和变量
3.参数和变量不会被垃圾回收机制回收,使变量私有化,容易造成内存的泄漏。
21、”==”和“===”的不同
前者会自动转换类型,再判断是否相等,后者不会自动类型转换,直接去比较
22、函数声明与函数表达式的区别?
定义函数的三种方式1、函数声明2、函数表达式3、new Function构造函数。
在Javscript中,解析器在向执行环境中加载数据时,对函数声明和函数表达式并非是一视同仁的,解析器会率先读取函数声明(函数提升),并使其在执行任何代码之前可用(可以访问),至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解析执行。
hello()
functionhello(){
console.log(“函数的声明”)
}
fun() //这里会报错!
var fun=function(){
console.log(“函数表达式”)
}
23、null和undefined的区别?
null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。当声明的变量还未被初始化时,变量的默认值为undefined。null用来表示尚未存在的对象
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2)调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
null表示"没有对象",即该处不应该有值。典型用法是:
(1) 作为函数的参数js 递归遍历多维数组,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
24、new操作符具体干了什么呢?(面对对象)
1、创建一个空对象
2、将构造函数中的this指向这个对象
3、将属性和方法绑定到这个对象上
4、隐式返回这个对象
25、如何获取javascript三个数中的最大值和最小值?
Math.max(a,b,c);//最大值
Math.min(a,b,c)//最小值
Math.max(…arr) //arr是一个数组[2,5,66,7] 返回66 扩展符
26、闭包的优点:(32特点)
(1)希望一个变量长期驻扎在内存当中(不被垃圾回收机制回收)
(2)避免全局变量的污染
(3)私有成员的存在
27、如何优化网页加载速度?
1、压缩 css和 Js 代码 ,减少css和js的文件大小
2、合并js、css文件,减少http请求
3、将css样式放在顶部,将js脚本放在底部
4、减少DOM操作,尽可能的用变量代替不必要的dom操作。
5、使用外部的js和css。
28、你如何优化自己的代码?
1、代码重用:
2、避免全局变量(命名空间,封闭空间,模块化mvc..)
3、拆分函数避免函数过于臃肿
4、适当的注释
5、变量命名规范
6、内存管理,尤其是闭包中的变量的释放。
29、重绘和回流(重排)
回流(重排):
1、当render tree 中的一部分(或全部)因为元素的规模尺寸,布局、隐藏等改变而需要重新构建,这就称为回流
2、当页面布局和几何属性改变时就需要回流
什么是重绘?
1、当render tree 中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就称为重绘。
回流必将引起重绘,而重绘不一定会引起回流
30、栈和堆的区别?
栈(stack):由编译器自动分配释放,存放函数的参数值,局部变量等;
堆(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统释放
31、Javascript作用链域
作用域链的原理和原型链很类似,如果这个变量在自己的作用域中没有,那么它会寻找父级的,直到最顶层。
注意:JS没有块级作用域,若要形成块级作用域,可通过(function(){})();立即执行的形式实现
32、谈谈this的理解-------(this永远指向最后调用它的对象,也就是执行的时候谁调用的)
01、普通函数中的this代表window。
02、事件中的this代表的事件源(特殊IE浏览器attchEvent中的this总指向去全局对象window)
03、定时器中函数代表的window
04、自调用的函数中额this指向window
05、对象中的方法中this的代表的是当前对象
06、箭头函数中this指向定义时的上一层作用域中this
(补充:箭头函数本身没有this和arguments的,在箭头函数中引用this实际上是调用定义时的上一层作用域的this。这里强调是上一层的作用域,是因为对象是不能形成独立作用域的。)
33、es5和es6的区别,说一下你所知道的es6
ES6新增的一些特性:
01、声明变量的关键字:let、const-------两个都有块级作用域且var有变量提升。
02、箭头函数
03、模板字符串------模板字符串是增强版的字符串,用反引号(`)标识,可以当作普通字符串使用,也可以用来定义多行字符串
04、 解构赋值--------ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值
05、for of循环--------for...of循环可以遍历数组、Set和Map结构、某些类似数组的对象、对象,以及字符串
06、import、export导入导出----在es6中文件可以默认为一个模块,模块通过export向外暴露接口。通过import导入一个模块,注意import和export只能出现在模块的最外层结构中能够,否则报错。
07、Set数据结构----Set数据结构类似数组,所有的数据都是唯一的,没有一个重复值,它本身是一个构造函数。
08、展开运算符----…
09、class类的继承---ES6中不再像ES5一样使用原型链实现继承,而是引入class这个概念
10、Promise------es6提供的一个异步编程的方案。
11、Proxy代理------使用代理监听对象的操作
12、修饰器------decorator是一个函数,用于修改类似与方法的行为
13、Symbol-----新的原始数据类型。Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的
34、var、let、const之间的区别
var声明变量可以重复声明,而let不可以重复声明
var是不受限于块级的,而let是受限于块级
var会与window相映射(会挂一个属性),而let不与window相映射
var可以在声明的上面访问变量,而let有暂存死区,在声明的上面访问变量会报错
const声明之后必须赋值,否则会报错
const定义不可变的量,改变了就会报错
const和let一样不会与window相映射、支持块级作用域、在声明的上面访问变量会报错
35、使用箭头函数应注意什么?
(1)箭头函数中的this,不是指向window,而是父级。
(2)不能使用arguments对象(箭头函数中没有this和arguments对象)
(3)不能用作构造函数,就是不能使用new命令,否则会跑出错误。
(4)不可以使用yeild命令。因此箭头函数不能用作Generator函数
(补充:Generator函数作为一个用来操作异步的状态机,遇到yeild停止,通过调用next()来继续操作,一:function关键字与函数名之间有一个星号,函数体使用yeild(类似return)产出不同的状态。)
36、ECMAScript 6 怎么写 class ,为何会出现 class?
ES6的class可以看作是一个语法糖,它的绝大部分功能ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法
<pre class="has">class Person{constructor(name){ this.name=name //this关键字代表实例对象 } say(){ console.log(123) }}var person =new Person(‘张三’);person.say()
</pre>
37、说一下es6的导入导出模块
导入通过import关键字
import {sum} from "./example.js" 导入一个模块中一个成员
import {sum,multiply,time} from "./exportExample.js" //导入多个
import * as example from "./exportExample.js" //导入一整个模块
导出通过export关键字
export var name= 'Michael';
export {firstName, lastName, year};
使用export default时,对应的import语句不需要使用大括号
let bosh = function crs(){ }
export default bosh; //导出
import crc from 'crc'; //导入
不使用export default时,对应的import语句需要使用大括号
let bosh = function crs(){ }
export bosh; //导出
import {crc} from 'crc'; //导入
在es6中文件可以默认为一个模块,模块通过export向外暴露接口。通过import导入一个模块,注意import和export只能出现在模块的最外层结构中能够,否则报错。
Export default向外暴露成员只允许一次
发表评论
热门文章
Spimes主题专为博客、自媒体、资讯类的网站设计....
一款个人简历主题,可以简单搭建一下,具体也比较简单....
仿制主题,Typecho博客主题,昼夜双版设计,可....
用于作品展示、资源下载,行业垂直性网站、个人博客,....
54447454
10月31日
[已回复]
能重复在发一下吗,无法下载了