本篇内容介绍了“JavaScript的面试问答题有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
JavaScript的数据类型都有什么?
基本数据类型:String,Boolean,Number,Undefined,Null
引用数据类型:Object(Array,Date,RegExp,Function)
javascript中==
和===
的区别是什么?
==
会自动进行类型转换,===
不会
例举3种强制类型转换和2种隐式类型转换?
强制(parseInt,parseFloat,Number())
隐式(==
) 1==”1”//true
null==undefined//true
原生 JS 中 call()、apply()、bind() 方法有什么区别?
三个方法都可以改变函数运行时的 this 指向。
三个方法第一个参数都是函数调用执行时this 指向的对象。
call() 方法第二个参数是个可变参数,是函数调用执行时本身所需要的参数。
apply() 方法第二个参数是数组或arguments。call()与apply()都是立即调用函数执行,在运行时修改this指向。
bind()是返回一个新的函数,新函数的函数主体与原函数的函数主体一致,当新函数被调用时,函数体中 this 指向的是 bind() 方法第一个参数传递的对象,而bind() 方法不会影响原函数本身的 this 指向。
什么是闭包?特点是?
闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
闭包的特点:
(1)作为一个函数变量的一个引用,当函数返回时,其处于激活状态。
(2) 一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
简单的说,JavaScript 允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。
事件委托是什么?
符合W3C标准的事件绑定 addEventLisntener /attachEvent
让利用事件冒泡的原理,让自己的所触发的事件,让他的父元素代替执行!
如何阻止事件冒泡和默认事件
e. stopPropagation();//标准浏览器
event.canceBubble=true;//ie9之前
阻止默认事件:
为了不让a点击之后跳转,我们就要给他的点击事件进行阻止
return false
e.preventDefault();
document load 和document ready的区别?
Document.onload 是在结构和样式加载完才执行js
window.onload:不仅仅要在结构和样式加载完,还要执行完所有的样式、图片这些资源文件,全部加载完才会触发window.onload事件
Document.ready原生种没有这个方法,jquery中有 $().ready(function)
为了保证页面输出安全,我们经常需要对一些特殊的字符进行转义,请写一个函数escapeHtml,将, &, “进行转义
return str.replace(/[”&]/g, function(match) { switch (match) { case “”: return “>”; case “&”: return “&”; case “\””: return “"”; } });}
简述创建函数的几种方式
第一种(函数声明):function sum1(num1,num2){ return num1+num2; }
第二种(函数表达式):var sum2 = function(num1,num2){ return num1+num2; }
第三种(函数对象方式):var sum3 = new Function("num1","num2","return num1+num2");
把 Script 标签 放在页面的最底部的body封闭之前 和封闭之后有什么区别?浏览器会如何解析它们?
如果说放在body的封闭之前,将会阻塞其他资源的加载
如果放在body封闭之后,不会影响body内元素的加载
iframe的优缺点?
优点:
解决加载缓慢的第三方内容如图标和广告等的加载问题
Security sandbox
并行加载脚本
缺点:
iframe会阻塞主页面的Onload事件
即时内容为空,加载也需要时间
没有语意
Javascript如何实现继承?
原型链继承,借用构造函数继承,组合继承,寄生式继承,寄生组合继承
请你谈谈Cookie的弊端?
缺点:
Cookie 数量和长度的限制。部分浏览器每个 domain 最多只能有50条 cookie,基本所有浏览器中每个 cookie 长度不能超过4KB,否则会被截掉。
安全性问题。如果 cookie 被人拦截了,那人就可以取得所有的 session 信息。即使加密也与事无补,因为拦截者并不需要知道 cookie 的意义,他只要原样转发 cookie 就可以达到目的了。
有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务器端保存一个计数器。如果我们把这个计数器保存在客户端,那么它起不到任何作用。
占用网络上传带宽。每次请求服务器资源时,都会携带 cookie 信息向服务器传递。
DOM操作——怎样添加、移除、移动、复制、创建和查找节点?
创建新节点
createDocumentFragment() // 创建一个DOM片段
createElement() // 创建一个具体的元素
createTextNode() // 创建一个文本节点
添加、移除、替换、插入
appendChild()
removeChild()
replaceChild()
insertBefore() // 在已有的子节点前插入一个新的子节点
查找
getElementsByTagName() // 通过标签名称
getElementsByName() // 通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
getElementById() // 通过元素Id,唯一性
js延迟加载的方式有哪些?
defer和async
动态创建DOM方式(创建script,插入到DOM中,加载完毕后callBack)
按需异步载入js
documen.write和 innerHTML 的区别?
document.write 只能重绘整个页面
innerHTML 可以重绘页面的一部分
哪些操作会造成内存泄漏?
内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。
setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
闭包
控制台日志
循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
判断一个字符串中出现次数最多的字符,统计这个次数?
var str = 'asdfssaaasasasasaa';var json = {};for (var i = 0; i < str.length; i++) { if(!json[str.charAt(i)]){ json[str.charAt(i)] = 1; }else{ json[str.charAt(i)]++; }};var iMax = 0;var iIndex = '';for(var i in json){ if(json[i]>iMax){ iMax = json[i]; iIndex = i; }}alert('出现次数最多的是:'+iIndex+'出现'+iMax+'次');
数组扁平化
数组扁平化是指将一个多维数组变为一个一维数组
const arr = [1, [2, [3, [4, 5]]], 6];// => [1, 2, 3, 4, 5, 6]
方法一:使用flat()
const res1 = arr.flat(Infinity);
方法二:利用正则
const res2 = JSON.stringify(arr).replace(/\[|\]/g, '').split(',');
但数据类型都会变为字符串
方法三:正则改良版本
const res3 = JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']');
方法四:使用reduce
const flatten = arr => { return arr.reduce((pre, cur) => { return pre.concat(Array.isArray(cur) ? flatten(cur) : cur); }, [])}const res4 = flatten(arr);
方法五:函数递归
const res5 = [];const fn = arr => { for (let i = 0; i < arr.length; i++) { if (Array.isArray(arr[i])) { fn(arr[i]); } else { res5.push(arr[i]); } }}fn(arr);
数组去重
const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}];// => [1, '1', 17, true, false, 'true', 'a', {}, {}]
方法一:利用Set
const res1 = Array.from(new Set(arr));
方法二:两层for循环+splice
const unique1 = arr => { let len = arr.length; for (let i = 0; i < len; i++) { for (let j = i + 1; j < len; j++) { if (arr[i] === arr[j]) { arr.splice(j, 1); // 每删除一个树,j--保证j的值经过自加后不变。同时,len--,减少循环次数提升性能 len--; j--; } } } return arr;}
方法三:利用indexOf
const unique2 = arr => { const res = []; for (let i = 0; i < arr.length; i++) { if (res.indexOf(arr[i]) === -1) res.push(arr[i]); } return res;}
方法四:利用include
const unique3 = arr => { const res = []; for (let i = 0; i < arr.length; i++) { if (!res.includes(arr[i])) res.push(arr[i]); } return res;}
方法五:利用filter
const unique4 = arr => { return arr.filter((item, index) => { return arr.indexOf(item) === index; });}
方法六:利用Map
const unique5 = arr => { const map = new Map(); const res = []; for (let i = 0; i < arr.length; i++) { if (!map.has(arr[i])) { map.set(arr[i], true) res.push(arr[i]); } } return res;}
类数组转化为数组
类数组是具有length属性,但不具有数组原型上的方法。常见的类数组有arguments、DOM操作方法返回的结果。
方法一:Array.from
Array.from(document.querySelectorAll('div'))
方法二:Array.prototype.slice.call()
Array.prototype.slice.call(document.querySelectorAll('div'))
方法三:扩展运算符
[...document.querySelectorAll('div')]
方法四:利用concat
Array.prototype.concat.apply([], document.querySelectorAll('div'));
debounce(防抖)
触发高频时间后n秒内函数只会执行一次,如果n秒内高频时间再次触发,则重新计算时间。
const debounce = (fn, time) => { let timeout = null; return function() { clearTimeout(timeout) timeout = setTimeout(() => { fn.apply(this, arguments); }, time); }};
防抖常应用于用户进行搜索输入节约请求资源,window触发resize事件时进行防抖只触发一次。
throttle(节流)
高频时间触发,但n秒内只会执行一次,所以节流会稀释函数的执行频率。
const throttle = (fn, time) => { let flag = true; return function() { if (!flag) return; flag = false; setTimeout(() => { fn.apply(this, arguments); flag = true; }, time); }}
节流常应用于鼠标不断点击触发、监听滚动事件。
函数珂里化
指的是将一个接受多个参数的函数 变为 接受一个参数返回一个函数的固定形式,这样便于再次调用,例如f(1)(2)
经典面试题:实现add(1)(2)(3)(4)=10; 、 add(1)(1,2,3)(2)=9;
function add() { const _args = [...arguments]; function fn() { _args.push(...arguments); return fn; } fn.toString = function() { return _args.reduce((sum, cur) => sum + cur); } return fn;}
深拷贝
递归的完整版本(考虑到了Symbol属性):
const cloneDeep1 = (target, hash = new WeakMap()) => { // 对于传入参数处理 if (typeof target !== 'object' || target === null) { return target; } // 哈希表中存在直接返回 if (hash.has(target)) return hash.get(target); const cloneTarget = Array.isArray(target) ? [] : {}; hash.set(target, cloneTarget); // 针对Symbol属性 const symKeys = Object.getOwnPropertySymbols(target); if (symKeys.length) { symKeys.forEach(symKey => { if (typeof target[symKey] === 'object' && target[symKey] !== null) { cloneTarget[symKey] = cloneDeep1(target[symKey]); } else { cloneTarget[symKey] = target[symKey]; } }) } for (const i in target) { if (Object.prototype.hasOwnProperty.call(target, i)) { cloneTarget[i] = typeof target[i] === 'object' && target[i] !== null ? cloneDeep1(target[i], hash) : target[i]; } } return cloneTarget;}
“JavaScript的面试问答题有哪些”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!