看看这些前端面试题,带你搞定高频知识点(七)

广告:宝塔Linux面板高效运维的服务器管理软件 点击【 https://www.bt.cn/p/uNLv1L 】立即购买

看看这些前端面试题,带你搞定高频知识点(七)

每天10道题,100天后,搞定所有前端面试的高频知识点,加油!!!,在看文章的同时,希望不要直接看答案,先思考一下自己会不会,如果会,自己的答案是什么?想过之后再与答案比对,是不是会更好一点,当然如果你有比我更好的答案,欢迎评论区留言,一起探讨技术 之美。

面试官:请你谈谈JS的this指向问题

我:呃~,我们知道this中有个准则就是谁调用就指向谁,这句话潜移默化的会导致我们出现一些误区,现将可能会出错的情况总结如下,并付出代码:

1)我们要知道在全局的时候去得到这个this的话,this都会指向windows,因为我们在全局的情况下使用的东西都会被挂载到window上。

<script>    console.log(this) // 指向window    function a(){        console.log(this)    }    a() // 相当于 window.a(),指向的依旧是 window</script>
登录后复制

2)我要知道this的指向是会指向上一个调用者的,代码如下:

看完了代码,我们知道虽然本质上是由于a才调用了d函数,但是中间还是有一层是c调用了d函数,所以this指向上一级会有一个就近原则的,这点很重要!!!

<script>    var a = {        b:10,        c:{            b:12,            d:function(){                console.log(this)            }        }    }    a.c.d() // {b: 12, d: ƒ}</script>
登录后复制

3)我们要知道箭头函数是没有作用域的,也就是说是没有自己的this,它的this永远向的是上一级的this,下面给出一道某大厂的面试题,大家可以猜一下最后的打印结果是什么?

假设你已经仔细的看完了这道面试题,相信你心中已经有了答案是66了,为什么呢?,要知道箭头函数是没有自己的this的,所以需要其去上一级去寻找this,而上一级处于全局作用域,所以打印的便是全局已经挂载的id数66。

<script>    var id = 66    function a(){        setTimeout(()=>{            console.log(this.id)        },500)    }    a({id:22}) // 猜猜结果是什么?</script>
登录后复制

那我们如何改变this的指向,去控制this指向我们想要的结果呢?给出如下三种方法:

<script>    var id = 66    function a(){        setTimeout(()=>{            console.log(this.id || this)        },500)    }    // call => {} 改变之后并执行一次    a.call({id:22}) // 打印22     // apply => [] 改变之后并执行一次    a.apply([12]) // 打印 [12]    // bind() 不调用,只改变this指向    a.bind(a(id=32)) // 32</script>
登录后复制面试官:说一说call apply bind的作用和区别?

我:呃~,好的,总结如下:

call apply bind三个方法都可以用来改变函数的this指向,具体区别如下:

1)fn.call (newThis,params) call函数的第一个参数是this的新指向,后面依次传入函数fn要用到的参数。会立即执行fn函数。

2)fn.apply (newThis,paramsArr) apply函数的第一个参数是this的新指向,第二个参数是fn要用到的参数数组,会立即执行fn函数。

3)fn.bind (newThis,params) bind函数的第一个参数是this的新指向,后面的参数可以直接传递,也可以按数组的形式传入。 不会立即执行fn函数,且只能改变一次fn函数的指向,后续再用bind更改无效。返回的是已经更改this指向的新fn

面试官:请你谈谈对事件委托的理解

我:呃~,好的,事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。说白了就是将还没有出现的事件,挂载到已经出现的事件上。整出代码如下:

<body><ul id="ul">    <li>0</li>    <li>1</li>    <li>2</li>    <li>3</li>    <li>4</li>    <li>5</li></ul><button id="btn">点我添加一个li</button><script>    // 事件委托    let ul = document.getElementById("ul")    ul.addEventListener('click',(event)=>{        console.log(event)        event = event || window.event        let target = event.target        if(target.nodeName == 'LI'){            alert(target.innerHTML)        }    })    let btn = document.getElementById('btn')    btn.addEventListener('click',()=>{        let li = document.createElement('li')        li.textContent = ul.children.length        ul.appendChild(li)    })</script></body>
登录后复制

面试官:说一说promise是什么与使用方法?

我:呃~,好的,Promise是ES6提供的一个构造函数,可以使用Promise构造函数new一个实例,Promise构造函数接收一个函数作为参数,这个函数有两个参数,分别是两个函数 resolverejectresolve将Promise的状态由等待变为成功,将异步操作的结果作为参数传递过去;reject则将状态由等待转变为失败,在异步操作失败时调用,将异步操作报出的错误作为参数传递过去。实例创建完成后,可以使用then方法分别指定成功或失败的回调函数,也可以使用catch捕获失败,thencatch最终返回的也是一个Promise,所以可以链式调用。

Promise的作用

Promise是异步微任务,解决了异步多层嵌套回调的问题,让代码的可读性更高,更容易维护 Promise使用

Promise的特点

1)对象的状态不受外界影响

2)一旦状态改变,就不会再变,任何时候都可以得到这个结果

3)resolve 方法的参数是then中回调函数的参数,reject 方法中的参数是catch中的参数

4)then 方法和 catch方法 只要不报错,返回的都是一个fullfilled状态的promise

应用场景

解决地狱回调问题

具体使用方法,参考我之前的文章:一文搞懂JS中的Promise

面试官:说一说跨域是什么?如何解决跨域问题?

我:呃,好的,总结内容如下:

什么是跨域

当前页面中的某个接口请求的地址和当前页面的地址如果协议、域名、端口其中有一项不同,就说该接口跨域了。 跨域限制的原因:

浏览器为了保证网页的安全,出的同源协议策略。

跨域解决方案

cors

目前最常用的一种解决办法,通过设置后端允许跨域实现。 res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader("Access-Control-Allow-Methods", "GET, PUT, OPTIONS, POST");

node中间件、nginx反向代理

跨域限制的时候浏览器不能跨域访问服务器,node中间件和nginx反向代理,都是让请求发给代理服务器,静态页面面和代理服务器是同源的,然后代理服务器再向后端服务器发请求,服务器和服务器之间不存在同源限制。JSONP

利用的原理是script标签可以跨域请求资源,将回调函数作为参数拼接在url中。后端收到请求,调用该回调函数,并将数据作为参数返回去,注意设置响应头返回文档类型,应该设置成javascript。

面试官:说一说JavaScript有几种方法判断变量的类型?

我:呃,好的,JavaScript有4种方法判断变量的类型,总结如下:

typeof

常用于判断基本数据类型,对于引用数据类型除了function返回’function‘,其余全部返回’object'。

instanceof

主要用于区分引用数据类型,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true

Object.prototype.toString.call()(对象原型链判断方法):

适用于所有类型的判断检测,检测方法是Object.prototype.toString.call(数据) 返回的是该数据类型的字符串。

constructor(用于引用数据类型):

用于检测引用数据类型,检测方法是获取实例的构造函数判断和某个类是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰。

面试官:说一说JS实现异步的方法?

我:呃~,好的,所有异步任务都是在同步任务执行结束之后,从任务队列中依次取出执行。常见的实现异步的方式如下:

回调函数、事件监听、setTimeout(定时器)、Promise、async/await,generator生成器

面试官:说一说数组去重都有哪些方法?

我:呃~,数组去重的方法有很多,举几个例子并简单的加以说明,如下:

利用对象属性key排除重复项

遍历数组,每次判断对象中是否存在该属性,不存在就存储在新数组中,并且把数组元素作为key,设置一个值,存储在对象中,最后返回新数组。

利用Set类型数据无重复项

new 一个 Set,参数为需要去重的数组,Set 会自动删除重复的元素,再将 Set 转为数组返回。

filter+indexof 去重

利用 Array 自带的 filter 方法,返回 arr.indexOf(num) 等于 index 的num。

reduce +includes去重

利用reduce遍历和传入一个空数组作为去重后的新数组,然后内部判断新数组中是否存在当前遍历的元素,不存在就插入到新数组中。

面试官:说一说es6中箭头函数?

我:呃~,好的,箭头函数相当于匿名函数,简化了函数定义。箭头函数有两种写法,当函数体是单条语句的时候可以省略{}和return。另一种是包含多条语句,不可以省略{}和return。 箭头函数最大的特点就是没有this,所以this是从外部获取,就是继承外部的执行上下文中的this,由于没有this关键字所以箭头函数也不能作为构造函数。

箭头函数比普通函数的定义写法更加简洁明了和快捷。但是两者又有区别:箭头函数没有原型prototype和super,所以无法创建this,其this是通过继承外部函数环境中的变量获取的,所以call、bind、apply都无法改变其this的指向;在找不到最外层的普通函数时,其this一般指向window;箭头函数不能使用new;箭头函数没有arguments;也不能作为generator函数,不能使用yield命令;箭头函数不能用于对象域和回调函数动态this中,一般用在内部没有this引用。

面试官:说一说JS变量提升?

我:呃~,好的,变量提升是指JS的变量和函数声明会在代码编译期提升到代码的最前面。 变量提升成立的前提是使用Var关键字进行声明的变量,并且变量提升的时候只有声明被提升,赋值并不会被提升,同时函数的声明提升会比变量的提升优先。 变量提升的结果,可以在变量初始化之前访问该变量,返回的是undefined。在函数声明前可以调用该函数。

使用let和const声明的变量是创建提升,形成暂时性死区,在初始化之前访问let和const创建的变量会报错。

【推荐学习:javascript高级教程】

以上就是看看这些前端面试题,带你搞定高频知识点(七)的详细内容,更多请关注9543建站博客其它相关文章!

广告:SSL证书一年128.66元起,点击购买~~~

9543建站博客
一个专注于网站开发、微信开发的技术类纯净博客。

作者头像
admin创始人

肥猫,知名SEO博客站长,14年SEO经验。

上一篇:前端ui框架有哪些
下一篇:聊聊uniapp下多组合条件查询的实现方法

发表评论

关闭广告
关闭广告