总结js面试题(未完成)
Posted Lumbago~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了总结js面试题(未完成)相关的知识,希望对你有一定的参考价值。
文章目录
1. this关键字(指向)
this是javascript语言的一个关键字,它是函数运行时,在函数体内部自动生成一个对象,只能在函数体内部使用。函数的不同使用场合,this有不同的值。总的来说this就是函数运行时所在的环境对象。
情况一:
纯粹的函数调用:这是函数的最通常的用法,属于全局调用,因此this就代表全局对象
var x = 1;
function test(){
console.log(this.x);
}
test(); // 1 情况二:作为对象方法
情况二:
作为对象方法的调用:函数还可以作为某个对象的方法调用,这时this就指这个上级对象。
function test(){
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;
obj.m();
情况三:
作为构造函数调用:所谓构造函数,就是通过这个函数,可以生成一个新对象。这时this就指这个新对象。
function test(){
this.x = 1;
}
var obj = new test();
console.log(obj.x); // 1
情况四:
apply的调用:
apply( )是函数的一个方法,作用是改变函数的调用对象。它的第一个参数就表示改变后的调用这个函数的对象。因此这时this指的就是这第一个参数。
apply( )的参数为空时,默认调用全局对象。这时运行结果为0,证明this指的是全局对象。
```javascript
var x = 0;
function test(){
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;
obj.m.apply(); // 0 this指的是全局对象
obj.m.apply(obj); // 1 this指的是obj
情况六:
箭头函数:
箭头函数没有自己的this,继承外层上下文绑定的this;
let obj = {
age: 20,
info: function() {
return () => {
console.log(this.age); //this继承的是外层上下文绑定的this
}
}
}
let person = {age: 28};
let info = obj.info();
info(); //20
let info2 = obj.info.call(person);
info2(); //28
二. 事件模型:事件委托、代理?如何让事件先冒泡后捕获?
事件委托:
又叫事件代理,利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
原理:
事件冒泡机制,从最深的节点开始,然后逐步向上传播事件。
作用:
①支持为同一个DOM元素注册多个同类型事件;
②可将事件分为事件捕获和事件冒泡。
代码:
addEventListener(event,function,useCapture布尔值)
默认为false冒泡,true为捕获
attachEvent()
//IE8及IE更早版本
detachEvent()
//移除事件监听
//不使用事件捕获
window.onload = function(){
let oBox = document.getElementById("box");
oBox.onclick = function(){
alert(1); //不触发
}
oBox.onclick = function(){
alert(2); //触发
}
}
//使用事件捕获
window.onload = function(){
oBox.addEventListener("click",function(){
alert(1); //触发
})
oBox.addEventListener("click",function(){
alert(2); //触发
})
}
事件捕获:
(从上到下查找)
当一个事件触发后,从Window对象触发,不断经过下级节点,直到目标节点。在事件到达目标节点之前的过程就是捕获阶段。所有经过的节点,都会触发对应的事件。
当为事件捕获(useCapture:true)时,先执行body的事件,再执行div的事件
事件冒泡:
(从上往上查找)
当事件到达目标节点后,会沿着捕获阶段的路线原路返回。同样,所有经过的节点,都会触发对应的事件。
当为事件冒泡(useCapture:false)时,先执行div的事件,再执行body的事件
先冒泡后捕获:
根据w3c标准,应先捕获再冒泡。若要实现先冒泡后捕获,给一个元素绑定两个addEventListener,其中一个第三个参数设置为false(即冒泡),另一个第三个参数设置为true(即捕获),调整它们的代码顺序,将设置为false的监听事件放在设置为true的监听事件前面即可。
三. 对象和面向对象
对象:
属性和方法的集合就是对象(万物皆对象)。
面向对象:
首先就是找对象,如果该对象不具备所需要的方法或属性,那就给它添加。面向对象是一种编程思维的改变。通过原型的方式来实现面向对象编程。
封装,继承,多态这些都是编程思想
还有封装一些API()返回一个promise的时候用的也是面向对象
.面向过程编程
“面向过程”(Procedure Oriented)是一种以过程为中心的编程思想。这些都是以什么正在发生为目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是封装、继承、类。
特性:模块化 流程化
优点:性能比面向对象高, 因为类调用时需要实例化,开销比较大,比较消耗资源;
单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、易扩展
创建对象的方式(4种):
new Object、字面量、构造函数、原型。
四. for···in和for···of的区别:(for···in取key,for··of取value)
for···in取key(下标),可以遍历数组,对象,字符串
for··of取value(值),for··of只能遍历数组
使用for…of遍历普通对象,需要配合Object.keys()一起使用。
var obj = {name:"Bob",age:25};
for(var i in obj){
console.log(i) // name age
}
for(var i of obj){
console.log(i) //报错
}
五.查找数组重复项
filter+indexOf
var arr = [1, true, true, 15, false, undefined, null, "NaN ", 0, " a "]
function arr_unique5(arr) {
return arr.filter((val, index, item) => {
console.log(val)
console.log(index)
console.log(item)
console.log(item.indexOf(val))
return item.indexOf(val) === index;
});
}
console.log(arr_unique5(arr))
forEach + includes
var arr = [1, true, true, 15, false, undefined, null, "NaN ", 0, " a "]
function arr_unique6(arr) {
var res = [];
var err = [];
arr.forEach((val) => {
if (!res.includes(val)) {
res.push(val);
} else {
err.push(val)
}
});
return err;
}
console.log(arr_unique6(arr))
六、数组扁平化
数组扁平化就是将一个多维数组转换为一个一维数组
实现基本方式
1、对数组的每一项进行遍历。
2、判断该项是否是数组。
3、如果该项不是数组则将其直接放进新数组。
4、是数组则回到1,继续迭代。
5、当数组遍历完成,返回这个新数组。
1.常规方式 递归处理
Array.prototype.flatten = function () {
var resultArr = [];
var len = this.length;
for (var i = 0; i < len; i ++) {
if (Array.isArray(this[i])) {
resultArr = resultArr.concat(this[i].flatten());
} else {
resultArr.push(this[i]);
}
}
return resultArr;
}
var arr=[1,2,3,[4,5,'hello',['world',9,666]]]
console.log(arr.flatten())//[1, 2, 3, 4, 5, "hello", "world", 9, 666]
2.es6中的flat函数也可以实现数组的扁平化
let arr1 = [1,2,['a','b',['中','文',[1,2,3,[11,21,31]]]],3];
console.log( arr1.flat( Infinity ) );
七、垃圾回收机制
简单来讲:就是浏览器或定期的查看内存中存储的变量,如果长时间没有使用,机会清除掉也就是回收
闭包的使用是长期在内存中,不会被回收,永久保存。
八、iframe的优缺点有哪些
它是一个标签
优点:
①iframe能够原封不动的把嵌入的网页展现出来;
②如果有多个网页引用iframe,那么你只需要修改iframe的内容,就可以实现调用的每一个页面内容的更改,方便快捷。
③网页如果为了统一风格,头部和版本都是一样的,就可以写成一个页面,用iframe来嵌套,可以增加代码的可重用。
④如果遇到加载缓慢的第三方内容如图标和广告,这些问题可以由iframe来解决。
缺点:
①会产生很多页面不易管理;
②iframe框架结构有时会让人感到迷惑,如果框架个数多的话,可能会出现上下、左右滚动条,会分散访问者的注意力,用户体验度差。
③代码复杂,无法被一些搜索引擎索引到,这一点很关键,现在的搜索引擎爬虫还不能很好的处理iframe中的内容,所以使用iframe会不利于搜索引擎优化。
④很多的移动设备(PDA 手机)无法完全显示框架,设备兼容性差。
⑤iframe框架页面会增加服务器的http请求,对于大型网站是不可取的。
九、函数柯里化(卡瑞化、加载化)
就是比如你写一个项目有很多小功能,可以将这些功能分成一个一个的函数封装起来
可以叫他颗粒化,便于修改这些功能改变和的数据改变等情况 提高效率,便于查找。
把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
容易理解的概念:
Currying概念其实很简单,只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数(主要是利用闭包实现的)。
特点:
①接收单一参数,将更多的参数通过回调函数来搞定;
②返回一个新函数,用于处理所有的想要传入的参数;
③需要利用call/apply与arguments对象收集参数;
④返回的这个函数正是用来处理收集起来的参数。
作用:
能进行部分传值,而传统函数调用则需要预先确定所有实参。如果你在代码某一处只获取了部分实参,然后在另一处确定另一部分实参,这个时候柯里化和偏应用就能派上用场。
用途:
我认为函数柯里化是对闭包的一种应用形式,延迟计算、参数复用、动态生成函数(都是闭包的用途)。
function add(x,y){ //普通函数
console.log(x+y);
}
function curryingAdd(x){ //柯里化函数(闭包)
return function(y){
console.log(x+y);
}
}
add(1,2) //3
curryingAdd(1)(2) //3
十、window的onload事件和domcontentloaded
window.onload:
当一个资源及其依赖资源已完成加载时,将触发onload事件。
document.onDOMContentLoaded:
当初始的html文档被完全加载和解析完成之后,DOMContentLoaded事件被触发,而无需等待样式表、图像和子框架的完成加载。
区别:
①onload事件是DOM事件,onDOMContentLoaded是HTML5事件。
②onload事件会被样式表、图像和子框架阻塞,而onDOMContentLoaded不会。
③当加载的脚本内容并不包含立即执行DOM操作时,使用onDOMContentLoaded事件是个更好的选择,会比onload事件执行时间更早。
以上是关于总结js面试题(未完成)的主要内容,如果未能解决你的问题,请参考以下文章