原生js部分面试题

本文介绍了JavaScript的基础知识,包括数据类型、作用域、闭包、this的指向以及类型判断。重点讲解了作用域的分类、闭包的概念及其优缺点,还探讨了this的变化场景和如何改变this的指向。此外,文章还涉及到了深拷贝与浅拷贝的区别,并列举了多种数据类型判断方法。最后,提到了事件处理、事件委托和封装通用事件绑定函数的重要性。
摘要由CSDN通过智能技术生成

一.数据类型简介:

1.JavaScript(以下简称 js)的数据类型分为两种:原始类型(即基本数据类型)和对象类型(即引用数据类型);两种类型的区别是:存储位置不同:基本数据类型存储在栈中引⽤类型的对象存储于堆中

2.js 常用的基本数据类型包括 undefined - - (未定义)、null- - (空的)、number - - (数字)、boolean- - (布尔值)、string- - (字符串)、Symbol - - (符号);

3.js 的引用数据类型也就是对象类型 Object- - (对象),比如:array - - (数组)、function - - (函数)、data - - (时间)以及 es6 新增加的 map 和 set

二、作用域

1.作用域:作用域就是一个变量可以使用的范围,主要分为全局作用域和函数作用域

全局作用域就是 Js 中最外层的作用域函数作用域是 js 通过函数创建的一个独立作用域,函数可以嵌套,所以作用域也可以嵌套Es6 中新增了块级作用域(由大括号包裹,比如:if(){},for(){}等)

2.自由变量:当前作用域外的变量都是自由变量,作用域链就是 自己没有这个变量就从上一级作用域查找,直到找到为止,直到找到顶层 window,没有的话就报错 3.变量提升:每个 var 声明的变量,function 声明的函数存在变量提升。变量和函数都有声明提升,let const 不存在变量提升会把声明语句提到代码的最顶端,赋值语句留在原地等待执行Var a=10 var a 会被提升 a=10 会留在原地

(在 js 中声明之前未定义,会在 js 的最上方会形成一个预解析池,用来存储声明了但没有先定义的变量名)

三、闭包 *

闭包:简单的理解就是函数中套了一个函数,内层函数可以访问外层函数中的变量有时候需要用到函数内的局部变量,在正常情况下是不能读取到的,这个时候就需要用到闭包。闭包可以封装对象的私有属性和方法,vue 中的 data 就是一种闭包的形式。闭包作为回调函数,可以实现函数的复用

优点:闭包因为长期驻扎在内存中。可以重复使用变量,不会造成变量污染缺点:闭包会使函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,可能会导致内存泄露。解决方法是在退出函数之前,将不使用的变量全部删除。

四、This 的指向 *

在 js 中 this 不是固定不变的,它会随着执行环境的改变而改变。要注意的是 this 取什么值,是在执行时确认的,定义时无法确认。this 的调用大概分为五种场景: 1.浏览器里,在全局范围内的 this 指向 window 对象; 2.在函数中,this 永远指向最后调用他的那个对象; 3.构造函数中,this 指向 new 出来的那个新的对象; 4.箭头函数中 this 比较特殊,箭头函数 this 为父作用域的 this,不是调用时的 this.要知道前四种方式,都是调用时确定,也就是动态的,而箭头函数的 this 指向是静态的,声明的时候就确定了下来;

有三个方法改变 this:

call:参数是单个使用的,apply:参数是一个数组call 和 apply 都会立刻调用这个函数bind:只改变 this 不会让函数立刻调用

五、类型判断

数据类型判断大概有四种 typeof、instanceof、constructor、Object.prototype.toString.call()比如说检测 num=10 的数据类型1.Type:typeof 检测数据类型会返回对应的数据类型小写字符。引用数据类型中的:Array,Object,Date,RegExp。不可以用 typeof 检测。都会返回小写的 objectconsole.log(typeof num);

2 . instanceof除了使用 typeof 来判断,还可以使用 instanceof。instanceof 运算符需要指定一个构造函数,或者说指定一个特定的类型,它用来判断这个构造函数的原型是否在给定对象的原型链上。console.log(arr instanceof Array);

3.constructorconstructor 是 prototype 对象上的属性,指向构造函数。我们可以用实例的隐式原型去找到构造函数的值。console.log(num.proto.constructor);

4 . 使用 Object.prototype.toString.call()检测对象类型可以通过 toString() 来获取每个对象的类型。每个对象都能通过 Object.prototype.toString() 来检测console.log(Object.prototype.toString.call(num));

六:深拷贝 浅拷贝

深拷贝拷贝的是值 浅拷贝拷贝的是地址深拷贝和浅拷贝的区别

  1. 浅拷贝: 将原对象的引用直接赋给新对象,新对象只是原对象的一个引用,而不复制对象本身,新旧对象还是共享同一块内存

  2. 深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”,新对象跟原对象不共享内存,修改新对象不会改到原对象

基本数据类型存储在栈中引⽤类型的对象存储于堆中

数组 深拷贝的方法

  1. 可以用 JSON.parse(JSON.stringify())

  2. concat

  3. 展开运算符

对象的深拷贝

  1. 可以用 JSON.parse(JSON.stringify())

  2. 用递归实现

七、字符串的方法 **

字符串的方法charAt( ) 方法从一个字符串中返回某个下标上的字符concat( ) 方法将一个或多个字符串与原字符串连接合并,形成一个新的字符串并返回。

search( ) 获取某个字符或者字符串片段首次出现的位置match( ) 检索字符串或者正则表达式replace( ) 替换 replace(参数 1,参数 2); 参数 1:替换谁 参数 2:替换值split( 参数 1,参数 2 ) 字符串切割,切割后返回数组

slice( ) 和 substring( ) ( 开始位置,结束位置 ) 获取两个索引值之间的字符串片段 从下标 2 开始截取,到下标 4 结束,但不包含 4substr ( 开始位置,截取的长度 ) 获取两个索引值之间的字符串片段

indexOf( ) 获取某个字符或者字符串首次出现的位置,找到则返回索引值,找不到则返回-1lastIndexOf( ) 获取某个字符或者字符串最后出现的位置,找到则返回索引值,找不到则返回-1

八、this, call, apply, bind *

跟 this 指向的答案背一样就行

1.浏览器里,在全局范围内的 this 指向 window 对象; 2.在函数中,this 永远指向最后调用他的那个对象; 3.构造函数中,this 指向 new 出来的那个新的对象;4.Call、apply、bind 中的 this 被强绑定在指定的那个对象上; 5.箭头函数中 this 比较特殊,箭头函数 this 为父作用域的 this,不是调用时的 this.要知道前四种方式,都是调用时确定,也就是动态的,而箭头函数的 this 指向是静态的,声明的时候就确定了下来;6.apply、call、bind 都是 js 给函数内置的一些 API,调用他们可以为函数指定 this 的执行,同时也可以传参。

九、数组排序 ****

  1. 冒泡排序法将数组中的相邻两个元素进行比较,将比较大(较小)的数通过两两比较移动到数组末尾(开始),执行一遍内层循环,确定一个最大(最小)的数,外层循环从数组末尾(开始)遍历到开始(末尾)

  2. 插入排序法(插队排序)将要排序的数组分成两部分,每次从后面的部分取出索引最小的元素插入到前一部分的适当位置·从第一个元素开始,该元素可以认为已经被排序;·取出下一个元素,在已经排序的元素序列中从后向前扫描;·如果该元素(已排序)大于新元素,将该元素移到下一位置;·重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置;·将新元素插入到该位置后;·重复步骤 2~5。

  3. 快速排序法实现思路是,将一个数组的排序问题看成是两个小数组的排序问题,以一个数为基准(中间的数),比基准小的放到左边,比基准大的放到右边,而每个小的数组又可以继续看成更小的两个数组,一直递归下去,直到数组长度大小最大为 2。

十、数组扁平化***

数组扁平化就是将一个多维数组转换为一个一维数组,比如[[1,2,3],3,[2,3]] =>[1,2,3,3,2,3]实现基本方式1、对数组的每一项进行遍历。2、判断该项是否是数组。3、如果该项不是数组则将其直接放进新数组。4、是数组则回到 1,继续迭代。5、当数组遍历完成,返回这个新数组。

十一、垃圾回收和内存机制

垃圾回收:浏览器的 js 具有自动垃圾回收机制,垃圾收集器会定期的找出那些不在继续使用的变量,然后释放内存。垃圾回收器会按照固定的时间间隔周期性的执行。js 中最常用的垃圾回收方式就是标记清除。例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。而当变量离开环境时,则将其标记为“离开环境”。引用计数的含义是跟踪记录每个值被引用的次数。当这个值的引用次数变成 0 时,则说明没有办法再访问这个值了,就把它回收掉。

内存泄漏:

  1. 循环引用一个很简单的例子:一个 DOM 对象被同一个多个 Javascript 对象引用,这个 DOM 对象可能会引发内存泄露。要想破坏循环引用,需要赋值为 null。

  2. 闭包在闭包中引入闭包外部的变量时,当闭包结束时此对象无法被垃圾回收(GC)。

  3. DOM 泄露当原有的 DOM 被移除时,子节点引用没有被移除则无法回收

  4. Times 计时器泄露

十二 原生 Ajax 的创建过程 ***

1.创建 xhr 核心对象var xhr=new XMLHttpRequest();

2.调用 open 准备发送(参数一:请求方式参数二: 请求地址参数三:true 异步,false 同步xhr.open('post','http://www.baidu.com/api/search',true))

3.如果是 post 请求,必须设置请求头。

4.调用 send 发送请求 (有参数就写在括号里,)xhr.send()

  1. 可以用 onload 事件 触发请求成功的操作或者也可以用(监听异步回调 onreadystatechange判断 readyState 为 4 表示请求完成判断 status 状态码 为 200 表示接口请求成功responeseText 为相应数据。字符串类型。)

备注:如果是 post 请求,想要传 json 格式参数。

设置请求头的时候设置为 json 格式

1.xhr.setRequestHeader('Content-Type', 'application/json')

open 发送数据2.xhr.open({_id:xxx,user:xxxx,age:xxxx})

十三:Jsonp 的原理 ****

JSONP 原理:

ajax 请求受同源策略影响,不允许进行请求,我们利用 script 标签的 src 属性不受同源策略的约束,利用这个特性 jsonp 需要以下步骤:

  1. 动态创建<script></script>(document.createElement('script'))

  2. 设置 src 属性,(src 中要包含参数 callback=fn)进行跨域请求

  3. 将 <script></script>添加到页面中执行 (body.appendChild('script'))

  4. 页面要提前定义好 callback。

  5. 后端会返回回调函数执行并包裹参数 callback(data)备注:服务端不再返回 JSON 格式的数据,而是返回回调函数包裹数据(fn({name:'tom',age:18}),在 src 中进行了调用,这样实现了跨域。

十四:存储 *

本地存储分为 cookie、localStorage、sessionStorage,CookieCookie 设计初衷是用来和服务器通讯,而不是本地存储,他只是被‘借用’到本地存储。Cookie 有一些缺点:存储空间小,最大 4k、用的时候比较麻烦

localStorage、sessionStorage在 HTML5 中,新加入了一个 localStorage/sessionStorage 特性,这个特性主要是用来作为本地存储来使用的,解决了 cookie 存储空间不足的问题(cookie 中每条 cookie 的存储空间为 4k),localStorage 中一般浏览器支持的是 5M 大小。优点:HTML5 专门为存储而设计,最大可存 5M、API 简单易用 setItem getItem、不会随着 http 请求被发送出去

localStorage、sessionStorage.cookie 不同点:

Cookie 可以设置过期时间 存储容量比较小 用起来没有方便的方法localStorage 数据会永久存储,除非代码或手动删除sessionStroage 数据只存在于当前会话,浏览器关闭则清空一般用 localStorage 会更多一些

注意:localStorage 只支持 string 类型的存储。

十五。宏任务和微任务 ( 也是同步异步的答案)

js 中的一个机制,就是遇到宏任务,先执行宏任务,将宏任务放入 eventqueue,然后在执行微任务。

宏任务和微任务都包含一些事件宏任务:setTimeout,setInterval,Ajax,DOM 事件微任务:Promise async/await

js 是单线程的,只能做一件事情,如果碰到异步任务就会把异步任务放在任务队列里等待执行,等到同步任务执行完成了,而且异步任务准备好了就会被放进主线程等待依次执行。异步的特点不会阻塞后面代码的执行。也就是请求处理过程中,你不能闲着,会产生异步的请求。回头再处理,然后继续执行下面的请求。异步和单线程是相辅相成的,js 是一门单线程脚本语言,所以需要异步来辅助

十六:dom 操作 (不必要全背 挑几个背)

DOM 是网页中用来表示文档中对象的标准模型,他是由节点和对象组成的结构集合。在浏览器解析 HTML 标签时,会构建一个 DOM 树结构。由此呢 js 也提供了一些 dom 的操作一、dom 元素获取1.document.getElementById(id 的值)  通过 id 来获取元素的对象,返回值是一个对象2.document.getElementsByName(name)  通过 name 属性来获取对象的,返回值是一个数组,与 getElementById()方法类似,但他是查询的 name 元素,而不是 id 属性3.document.getElementsByTagName()  通过标签来获取元素的对象, 返回值是一个数组4.document.getElementsByClassName()  通过 class 类名来获取的对象,返回值是一个数组5.document.querySelector() css 选择器,返回与该模式匹配的第一个元素,结果为一个元素;如果没找到匹配的元素,则返回 null6.document.querySelectorAll() css 选择器,返回与该模式匹配的所有元素,结果为一个类数组二、dom 创建二、dom 操作

  1. 创建:新的标签(元素节点) = document.createElement("标签名")

  2. 删除:父节点.removeChild(子节点);

  3. 插入:insertBefore(新插入的节点,参照物节点) 往某个节点的前面插入一个新的节点

  4. 追加:appendChild(新的节点的名) 当前对象追加一个子节点

十七.事件

  1. 事件绑定的方法一是直接在标签内直接添加执行语句,二是绑定函数。第三种 是事件监听(addEventListener)

  2. DOM 事件两种类型 (事件传播也背这个答案) 事件类型分两种:事件捕获、事件冒泡。 事件捕获就是由外往内,从事件发生的顶点开始,逐级往下查找,一直到目标元素。 事件冒泡就是由内往外,从具体的目标节点元素触发,逐级向上传递,直到根节点。

怎么阻止事件冒泡:vue 里是 stop 原生 js 可以 return false 还有 stopPropagation

十八。事件委托

事件委托,又名事件代理。事件委托就是利用事件冒泡,就是把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡,那么委托也就没法实现了

好处:提高性能,减少了事件绑定,从而减少内存占用比如:瀑布流:无限上拉列表中,如果给每一个图片绑定点击事件,非常繁琐且消耗内存。所以我们可以把每张图片上的点击事件委托给共同的父元素。

十九。封装一个通用的事件绑定函数

我们在封装这个函数的时候可以用事件监听来实现 ,封装的函数有三个参数,第一个是要绑定事件的元素,第二个是要绑定的事件类型,第三个是事件的执行函数。调用这个函数 就可以实现给某个元素绑定一个事件了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值