js用递归遍历多维数组_js面试题更新之40

js用递归遍历多维数组_js面试题更新之40
文章图片

【js用递归遍历多维数组_js面试题更新之40】1、数组方法pop() push() unshift() shift()
push后面添加元素,个数不限,返回新数组的长度
pop从后面删除一个元素,返回那个元素
unshift从前面添加元素,个数不限,返回新数组的长度
shift从前面删除一个元素,返回那个元素
2、javascript的typeof返回哪些数据类型
ObjectnumberfunctionBooleanunderfind
(注意这里没有null,null是一个空对象,是Object的类型。undefined隐形转换数字为NaN,不是任何值,不等于NaN本身。null隐形转换数字文0。强制转化都为NaN。)
3、split() join() 的区别
split() 字符串的方法,把字符串分割成数组split(“,”)
join()数组的方法,把数组连接成字符串join(“--”)
4、输出的值是什么:

var arr = [1, 2, 3, 4, 5, 5]for (var i = 0; isetTimeout(function(){console.log(i)})//输出6次6。setTimeout()是异步操作。var定义变量是存在变量提升,//当i=6时循环停止,才开始执行6次console.log(i) }

for (let i = 0; isetTimeout(function(){console.log(i)})}//输出0 1 2 3 4 5 。let不存在变量提升,可以形成块级作用域

for (var i = 0; isetTimeout(function(){console.log(arr[i])})}//输出6次undefined

for (let i = 0; isetTimeout(function(){console.log(arr[i])})}//输出 1 2 3 4 5 5

5、前端有哪几种本地存储方式,简述各自的特点(请描述一下cookies,sessionStorage和localStorage的区别?)
前端有三种本地存储的方式:cookie、localStorage 、 sessionStorage
  • cookie---最大数据量为4kb左右,存储量小,可以设置有效期,默认为会话级别。是基于http的。
  • localStorage---有效期永久,存多了,不主动删除,会造成浏览器很卡。同源可以修 改localStorage的数据。
  • sessionStorage:有效期顶层窗口关闭钱,数据在页面会话结束的时候会被清除,属于临时保存同一窗口的数据。最大容量有5M左右。
6、简述常见的http状态码
200 请求成功
304 服务器已经执行了请求,当文件没有变化 ,简单讲有缓存了。
404 Not Found
500 服务端错误
7、从输入URL到页面加载发生了什么?
1、DNS解析 (把域名解析为相应的ip地址)
2、TCP连接 (三次握手的过程)
3、发送HTTP请求
4、服务器处理请求并返回HTTP报文
5、浏览器解析渲染页面
6、连接结束 (断开连接过程是四次挥手的过程)
8、Promise构造函数是同步执行还是异步执行,那么 then 方法呢?
Promise构造函数是同步执行的,then方法是异步执行的
9、setTimeout、Promise、async/await 的区别?
事件循环(Event Loop)中分为宏任务队列和微任务队列
setTimeout的回调函数放到宏任务队列里,等到执行栈清空以后执行
promise.then里的回调函数会放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行
async函数表示函数里面可能会有异步方法,await后面跟一个表达式。async方法执行时,遇到await会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行
补充:promise 是es6新增一种异步编程的方案
async/await是es7中新增的异步编程的方案。
经典案例:今日头条的面试题,执行的顺序
async function async1 () {console.log('async1 start') // 2await 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')//4resolve(); }).then (function () {console.log('promise2')//6})console.log('script end')//5运行结果:1、 script start2、 async1 start3、 async24、 promise15、 script end6、 promise27、 async1 end8、 setTimeout

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 }
例:let arr=[‘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)} // a b对象中的键
11、手写一个 Promise(中高级必考)什么是promise?promise是用来干啥的?解决了什么问题?
Promise是异步编程的一个解决方案,主要用来解决两个问题:1、解决异步的问题,2、解决回调地狱的,就是第一个函数的输出是第二个函数的输入的这种现象。
letpromise=new Promise((resolve,reject)=>{If(异步操作成功){resolve(value); }else{reject(error); //操作失败}})promise.then(function(value){ //success },function(error){ //failure })//promise.then()两个参数,第二个参数可选

Promise 对象的三种状态:pending(正在进行)、fulfilled(成功)、rejected(失败)。
状态只能pending到fulfilled或者pending到rejected,状态一旦改变不能再变。
12、对象、数组的深拷贝浅拷贝
浅拷贝:就是流于表面的拷贝方式,浅拷贝只拷贝的对象的地址,也就是说两个对象指向的是同一地址,修改其中的一个对象的属性,另一个对象的属性也会修改。
深拷贝:完全拷贝,拷贝之后新旧数据完全分离,不再共用对象类型的属性值,不会相互影响。
13、手写一个js深拷贝(先理解什么是深拷贝)
乞丐版:
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)

面试够用版(判断是数组还是对象,新建一个数组或者对象,通过for in循环数组对象,完成深拷贝) 递归拷贝
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; }

14、数组去重手写
利用es6中Set去重
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的数据结构。类似于数组,但是成员的属性都是唯一的,没有重复的值。

双重for循环+splice()方法
function single(arr){for(var i=0; ifor(var j=i+1; jif(arr[i]==arr[j]){arr.splice(j,1); j--; //arr的长度变了}}} returnarr; }var arr = [1,2,2,23,23,undefined,undefined]; console.log(single(arr)) //[1, 2, 23, undefined]

利用indexOf去重
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]

新建一个空数组,for循环判断新数组中是否存在原数组中元素,如果有相同的值则跳过,不相同push到新数组。
15、冒泡排序和选择排序
冒泡排序:相邻两个元素比较
相邻两个元素进行比较,将一个数组中数字使用循环进行升序或排序的
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; }}}

选择排序:先找值
这种排序方式先找最大的,排在最左侧,然后找第二个往左靠。。。。
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; }}}

冒泡排序和顺序排序(划重点)。
(1)冒泡排序是比较相邻位置的两个数,而选择排序是按顺序比较,找最大值或者最小值;
(2)冒泡排序每一轮比较后,位置不对都需要换位置,选择排序每一轮比较都只需要换一次位置;
(3)冒泡排序是通过数去找位置,选择排序是给定位置去找数;
总结:一般选择排序优于冒泡排序。因为每次排序只需要交换一位置。冒泡排序比较耗性能。
16、 浅谈async/await
1、async声明一个异步async function fun(){….}
自动将常规的函数转换成Promise ,返回值也是一个Promise对象。
只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
异步函数内部可以使用await
2、await 等待异步功能执行 var result=await new Promise()
放置在Promise调用之前,await强制其他代码等待,直到Promise完成并返回结果
只能与Promise一起使用,不适于回调。
只能在async函数内部使用。
17、事件循环
function printing() {console.log(1); setTimeout(function() { console.log(2); }, 1000); setTimeout(function() { console.log(3); }, 0); console.log(4); }// 1 4 3 2

理解: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()
function hello(){
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) 作为函数的参数,表示该函数的参数不是对象。
(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写法只是让对象原型的写法更加清晰、更像面向对象编程的语法
class Person{constructor(name){this.name=name//this关键字代表实例对象}say(){console.log(123)}}var person =new Person(‘张三’);person.say()

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向外暴露成员只允许一次
38、http和https 区别;
HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。
HTTPS和HTTP的区别主要如下:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、
身份认证的网络协议,比http协议安全。
39、简述readyonly与disabled的区别:
1、readonly 只针对input(type为text和password)和textarea有效。而disabled对于所有的表单元素都有效。
2、当表单元素使用了disabled后,当我们将表单以PSOT和get方式提交的话,这个元素的值不会被传递出去,而readonly将会把值传递出去。
40、同步和异步的区别:同步异步主要是事情做完以后,如何进行处理、或者说关注的是一种消息通信机制。
同步:同步相当于当客户端发送请求给服务端。在等待服务端的响应请求时,客户端不做其他事情。
当服务端做完了才返回给客户端,这样的话客户端一直等待,用户使用起来不友好。
异步:当客户端发送给服务器请求时,在等待服务器响应的时候吗,客户端可以做其他的事情,不用等待服务端的响应,

    推荐阅读