JS面试题
1、javascript 的 typeof 返回哪些数据类型
number、boolean、undefined、string、object、function
2、javascript 有哪些数据类型
基本数据类型:number、boolean、undefined、string、null、
引用数据类型:object、RegExp、array、Date、Math
3、例举 3 种强制类型转换和 2 种隐式类型转换?
强制转换:parseInt,parseFloat,Number()
隐式转换:==
4、split() 和 join()的区别
前者是切割数组的形式,后者是将数组转换成字符串
5、数组方法pop() push() unshift() shift()
pop() 尾部删除 shift()头部删除
push() 尾部添加 unshift() 头部添加
6、数组方法
every() filter() forEach() isArray() map() reduce() indexOf()
7、深拷贝和浅拷贝
浅拷贝:赋值符号 =
深拷贝:
1、var arr2 = arr1.slice(0),(多层数组有问题,如[ 1 ,2,[0,1] ,3])
2、var arr2 = arr1.concat();(多层数组有问题)
3、for循环重新压进新的空数组 (多层数组需要多层循环压进去,否则有问题)
4、ES6的扩展运算符 var [...arr2] = arr1,(多层数组和多层对象有问题,如[ 1 ,2,[0,1] ,3])
let oldObj = { a: 1, b: 2 } let newObj = {...oldObj} newObj.a = 2 console.log(oldObj) // {a: 1, b: 2} let outObj = { inObj: {a: 1, b: 2} } let newObj1 = {...outObj} newObj1.inObj.a = 2 console.log(outObj) // {inObj: {a: 2, b: 2}} let outArr = [1,2,[4,5],3] let newArr = [...outArr] newArr[0] = 2; newArr[2][1] = 6; console.log(outArr)//[1,2,[4,6],3]
5、JSON.parse(JSON.stringify(arr1)) ,若为正则、函数、undefined、NaN等值有坑(实际工作中常用的方法)
8、字符串里面的字符数最多次数以及该字符是什么?
var str = "asdkfhsodjcpeksoxshieorjsa"; var obj = {};var maxNum = 0; var letter = ''; for(var i=0;i<str.length;i++){ if(!obj[str.charAt(i)]){ obj[str.charAt(i)] = 1; }else{ obj[str.charAt(i)]++; } };
for(var item in obj){ if(obj[item ]>maxNum){ maxNum=obj[item]; letter = item } } console.log('出现次数最多的是:'+letter+'出现'+maxNum+'次')
9、99乘法表制作
<script> for (var i = 1;i <=9;i++) { for(var j = 1;j <=i;j++) { document.write(i+"*"+j+"=" + i*j +" ") } document.write("<br/>") } </script>
10、js将数字转换为汉字
function convertToChinaNum ( num ) { var arr1 =newArray('零','一','二','三','四','五','六','七','八','九'); var arr2 =newArray('','十','百','千','万','十','百','千','亿','十','百','千','万','十','百','千','亿');//可继续追加更高位转换值 if(!num ||isNaN(num)){ return"零"; } var english = num.toString().split("") var result =""; for(var i =0; i < english.length; i++) { var des_i = english.length -1- i;//倒序排列设值 result = arr2[i] + result; var arr1_index = english[des_i]; result = arr1[arr1_index] + result; } //将【零千、零百】换成【零】 【十零】换成【十】 result = result.replace(/零(千|百|十)/g,'零').replace(/十零/g,'十'); //合并中间多个零为一个零 result = result.replace(/零+/g,'零'); //将【零亿】换成【亿】【零万】换成【万】 result = result.replace(/零亿/g,'亿').replace(/零万/g,'万'); //将【亿万】换成【亿】 result = result.replace(/亿万/g,'亿'); //移除末尾的零 result = result.replace(/零+$/,'') //将【零一十】换成【零十】 //result = result.replace(/零一十/g, '零十');//貌似正规读法是零一十 //将【一十】换成【十】 result = result.replace(/^一十/g,'十'); return result; }
11、事件绑定和普通事件有什么区别?
事件绑定是指把事件注册到具体的元素之上,普通事件指的是可以用来注册的事件
普通事件会覆盖掉,只执行后者方法,不支持DOM事件流
dom.onclick = function(){}
事件绑定不会覆盖掉,会依次执行,支持DOM事件流
addEventListener('click',function(){},true)
12、跨域问题?
概念:只要协议、域名、端口有任何一个不同,都被当作是不同的域
请求接口的时候有时候会出现子域名等,导致跨域问题
解决方案:JSONP、websocket、CORS、PostMessage
注意JSONP只支持GET方法
JSONP原理及实现
什么是跨域?javascript跨域的四种方式介绍-js教程-PHP中文网
13、call和apply的区别?
都是改变this的指向,两个方法属于Function.prototype原型上的方法
call传参一个一个的传,apply传参是个数组
14、继承的方法?
总共有5种
对象冒充、call、apply、原型继承、混合继承(call和原型继承混合)
JavaScript中B继承A的方法 - Me丶微笑 - 博客园
15、JavaScript指针、闭包、作用域?
this指向调用上下文
闭包:内作用域调用外作用域的变量,滥用闭包函数会造成内存泄露,因为闭包中引用到的包裹函数中定义的变量都
永远不会被释放,所以我们应该在必要的时候,及时释放这个闭包函数
作用域:定义一个函数就开辟了一个局部作用域,整个JS执行环境有一个全局作用域
16、事件委托是什么?
符合 W3C 标准的事件绑定 addEventLisntener /attachEvent
利用事件冒泡的原理,把自己的所触发的事件,让他的父元素代替执行!
17、如何阻止事件冒泡和默认事件?
阻止冒泡:e.stopPropagation()
阻止默认事件:e.preventDefault()
JS阻止冒泡和取消默认事件(默认行为)-前端开发博客
18、添加 删除 替换 插入到某个节点的方法 ?
obj.appendChild() obj.insertBefore() //原生的 js 中不提供 insertAfter(); obj.replaceChild()//替换 obj.removeChild()//删除
19、document load 和 document ready 的区别?
Document.onload 是在结构和样式加载完才执行 js
window.onload:不仅仅要在结构和样式加载完,还要执行完所有的样式、图片这些资源文
件,全部加载完才会触发 window.onload 事件
Document.ready 原生种没有这个方法,jquery 中有 $().ready(function)
20、和=的区别?
前者只是判断值是否相等,后者会判断数据类型和值是否都相等
21、javascript 的同源策略?
一段脚本只能读取来自于同一来源的窗口和文档的属性,这里的同一来源指的是主机名(域名指向的是ip地址,即主机地址)、协
议和端口号的组合
http,ftp:协议
主机名;localhost
端口名:80:http 协议的默认端口
https:默认端口是 8083
同源策略带来的麻烦:ajax 在不同域名下的请求无法实现,
如果说想要请求其他来源的 js 文件,或者 json 数据,那么可以通过 jsonp 来解决
23、JavaScript 是一门什么样的语言,它有哪些特点?
js是面向对象的弱类型语言
语言特性:面向对象(要掌握创建对象的多种方式,继承的多种方式、原型链),动态/弱类型语言
24、已知 ID 的 Input 输入框,希望获取这个输入框的输入值,怎么做?(不使用第三方框架)
document.getElementById('ID').value
25、希望获取到页面中所有的 checkbox 怎么做?(不使用第三方框架)
var domList = document.getElementsByTagName(‘input’) var checkBoxList = []; //返回的所有的 checkbox var len = domList.length; //缓存到局部变量 while (len--) { //使用 while 的效率会比 for 循环更高 if (domList[len].type == 'checkbox') { checkBoxList.push(domList[len]); } } //获取已经选中的多选项 CheckBox
26、箭头函数和普通函数的区别是什么?
答:普通函数this总是指向他的调用者,默认指向window,在严格模式下,没有直接调用者的函数中this是undefined,使用call、apply、bind绑定,this指的是绑定的对象
箭头函数的this,指向定义时所在的对象,而不是调用时所在的对象;箭头函数不能构造函数(使用new 命令),否则抛出错误;不能使用arguments对象;不能使用yield命令
27、讲一下let 、var、const的区别?
var 没有块级作用域,支持变量提升
let 有块级作用域,不支持变量提升,不允许重复声明同名变量,暂存性死区,不能通过window进行访问
const 有块级作用域,不允许变量提升,不允许重复声明同名变量,暂存性死区,不能改变变量的值
28、实现一个new的伪代码?
创建一个对象;链接原型;绑定this;返回该对象
function _new( ) { let obj = new Object(); let Con = [].shift.call(arguments); obj.__proto__ = Con.prototype; let result = Con.apply(obj,arguments); return typeof result ==='object' ? result :obj }
function create(Con, ...args) { this.obj = {}; //创建一个空的对象//将空对象指向构造函数的原型链 Object.setPrototypeOf(obj, Con.prototype); //obj绑定到构造函数上,便可以访问构造函数中的属性 let result = Con.apply(obj, args); //如果返回的result是一个对象则返回该对象,new方法失效,否则返回obj return result instanceof Object ? result : obj; }
29、原型、原型链?
每一个JS函数中都有一个prototype
(原型)属性,指向这个函数的原型对象,通过这个函数产生的实例对象都有一个__proto__
(隐式原型)属性,这个属性也是指向同一个原型对象,所有的实例对象的属性都会继承这个原型对象的属性,原型对象上也有一个__proto__
属性,指向的objec
原型对象,所有的对象属性都会继承objec
原型对象属性。而objec
t原型对象的__proto__
指向的是null
。当我们访问对象的某个属性时,就会从实例对象,原型对象,object
原型对象上层层寻找,由此形成原型链。而原型就是原型对象上的属性。
30、垃圾回收机制(闭包的延伸)?
分为以下两个阶段:
1、标记阶段:垃圾回收器,从根对象开始遍历,访问到的每一个对象都会被标示为可到达对象。
2、清除阶段:垃圾回收器在对内存当中进行线性遍历,如果发现该对象没有被标记为可到达对象,那么就会被垃圾回收机制回收。这里面牵扯到了引用计数法,每次引用都被会‘➕1’ 如果标记清零,那么就会被回收掉。
31、函数的节流和防抖动?
防抖动函数:将多次触发变成最后一次触发;
function debounce(fn,wait){ let timer = null; return function (){ let arg = arguments; if(timer){ clearTimeout(timer); timer = null; } timer = setTimeout(()=>{ fn.apply(this,arg) },wait) } } function clg(){ console.log('clg') } window.addEventListener('resize',debounce(clg,1000))
节流函数:将多次执行变成每隔一个时间节点去执行的函数
function throttle(fn,time){ let lastTime = null; return function(){ let nowTime = Date.now(); if(nowTime - lastTime > time || !lastTime){ fn(); last = nowTime } } } function sayHi(){ console.log('hi') } setInterval(throttle(sayHi,1000),500)
32、简单介绍下event loop?
js作为单线程语言。在执行过程中,会产生执行环境。这些执行环境中的代码被顺序的加入到执行栈中,如果遇到异步代码,会被挂起并加入到任务队列当中,等到主线程任务执行完毕,event loop就会从任务队列取出需要执行的代码放入到执行栈中执行。所以本质上来讲,js中的异步还是同步的行为。
任务队列有分为宏任务和微任务队列。
一次正确的event loop执行顺序如下:
1、执行所有同步代码
2、执行栈为空,查询是否有需要执行的微任务。
3、微任务(有:则执行,无:则跳出)
4、必要的话开始渲染UI
5、开始下一轮的任务队列执行宏任务中的异步代码。
33、数组去重?
//扩展运算符只对单层数据深拷贝 functin uniqueStr ( arr ) { var newArr = new Set( arr ); return [...newArr] }
functin uniqueStr ( arr ) { var newArr = [],obj = {}; for (var = i;i < arr.length;i++) { if(!obj[arr[i]]){ newArr.push(arr[i]) obj[arr[i]] = 1 } } return newArr }
function uniqueArr(arr) { const res = new Map() return arr.filter((a)=>{ return !res.has(a) && res.set(a,1) }) }
https://www.cnblogs.com/zhishaofei/p/9036943.html
34、创建对象的5中方法?
1、new 操作符+Object创建对象
var person = new Object(); person.name = "lisi"; person.age = 21; person.family = ["lida","lier","wangwu"]; person.say = function(){ alert(this.name); }
2、字面式创建对象
var person ={ name: "lisi", age: 21, family: ["lida","lier","wangwu"], say: function(){ alert(this.name); } };
3、工厂模式
funtion createPerson(name,age,family) { var o = new Object(); o.name = name; o.age = age; o.family = family; o.say = function(){ alert(this.name) } } var person = createPerson('lisi','12',['wangwu','liumazi']); console.log(person1 instanceof Object); //true console.log(person1 instanceof Person); //true console.log(person1.constructor); //constructor 属性返回对创建此对象的数组、函数的引用 //K可以重复调动,工厂式的创造对象
4、构造函数模式
function Person(name,age,family) { this.name = name; this.age = age; this.family = family; this.say = function(){ alert(this.name); } return o; } var person1 = new Person("lisi",21,["lida","lier","wangwu"]); console.log(person1 instanceof Object); //true console.log(person1 instanceof Person); //true console.log(person1.constructor); //constructor 属性返回对创建此对象的数组、函数的引用
构造函数模式每个实例包含不同的Function实例,占用内存
5、原型模式
function Person() { } Person.prototype.name = "lisi"; Person.prototype.age = 21; Person.prototype.family = ["lida","lier","wangwu"]; Person.prototype.say = function(){ alert(this.name); }; console.log(Person.prototype); //Object{name: 'lisi', age: 21, family: Array[3]} var person1 = new Person(); //创建一个实例person1 console.log(person1.name); //lisi var person2 = new Person(); //创建实例person2 person2.name = "wangwu"; person2.family = ["lida","lier","lisi"]; console.log(person2); //Person {name: "wangwu", family: Array[3]} // console.log(person2.prototype.name); //报错 console.log(person2.age); //21
6、混合模式(构造函数+原型模式)
function Person(name,age,family){ this.name = name; this.age = age; this.family = family; } Person.prototype = { constructor: Person, //每个函数都有prototype属性,指向该函数原型对象, //原型对象都有constructor属性,这是一个指向prototype属性所在函数的指针 say: function(){ alert(this.name); } } var person1 = new Person("lisi",21,["lida","lier","wangwu"]); console.log(person1); var person2 = new Person("wangwu",21,["lida","lier","lisi"]); console.log(person2);
还有动态原型模式、寄生构造函数模式、稳妥构造函数模式
35、哪些方法改变原数组,哪些方法不改变原数组
改变原数组的:
1、shift:将第一个元素删除并且返回删除元素
2、unshift:在原数组的最前端依次添加,并且返回新数组的长度
3、push:在原数组的最后依次添加项,并返回新数组的长度
4、pop:将最后一个元素移除并返回移除的项
5、reverse:反转数组的顺序
6、sort:对数组进行依次排序
7、splice:三个参数。第一个代表开始的下标,第二个代表 要删除的个数,第三个代表要替换的东西 返回被删除的数组
不改变原数组的:
1、concat:拼接,连接多个数组
2、slice:提取,返回被提取的字符
3:join:将数组中所有元素以参数作为分隔符放入一个字符
4、map,filter,some,every,foreach等不改变原数组
拓展
toString(),数组转字符串
36、js数组迭代方法与归并方法
ES5为数组定义了5个迭代的方法:
运行的函数会接受三个参数:1)数组项的值 2)该项在数组中的位置 3)数组对象本身。
.every()
对数组的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。
例: var arr = [1,2,3,4,5,4,3,2,1]; var num = arr.every(function(item,index,array){ return (item > 2); }) console.log(num); //false
.some()
对数组的每一项运行给定函数,如果该函数对任一项返回true,则返回true。
例: var arr = [1,2,3,4,5,6,7,8]; var num = arr.some(function(item,index,array){ return (item > 2); }) console.log(num); //true
.filter()
对数组的每一项运行给定函数,返回该函数会返回true的项组成的数组。
例: var arr= [1,2,3,4,5,4,3,6,1]; var num= arr.filter(function(item,index,array){ return (item > 3); }) console.log(filterResult); //[4,5,4,6]
·map()
对数组的每一项运行给定函数,返回每次函数调用的结果组成的数组。
例: var arr = [1,2,3,4,5,6,7,8]; var num = arr.map(function(item,index,array){ return item*2; }) console.log(num); //[2,4,6,8,10,12,14,16]
·forEach()
对数组的每一项运行给定函数。该方法没有返回值。
var arr = [1,2,3,4,5,6,7,8]; var num = arr.forEach(function(item,index,array){ console.log(item*2); //[2,4,6,8,10,12,14,16] }) console.log(num); //undefined
归并方法
·reduce() 是从数组的第一项开始,逐个遍历到最后。
·reduceRight() 是从数组的最后一项开始,逐个遍历到最前。
这两个方法都会迭代数组的所有项,然后构建一个最终返回的值。
传给这两个方法的函数接收4个参数:1)前一个值 2)当前值 3)项的索引 4)数组对象
例: var values = [3,6,5,2,4,2]; var sum = values.reduce(function(prev,cur,index,array){ return prev + cur; //3+6=9+5=14+2=16+4=20+2=22 }); console.log(sum); //22
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
2021-11-03 vue 中 直接操作 cookie 及 如何使用工具 js-cookie
2021-11-03 2020年人均可支配收入(同志们,你们已经很棒了)