斗智斗勇一

斗智斗勇题

说说JavaScript中的数据类型?存储上的差别?

1.问常见的数据类型有哪些 ​ number、string、undefined、null、boolean、object、array、function、symbol、bigint

symbol(ES6) 辛波 表示独一无二、bigint(ES10) 笔搁应t 表示最大的数

2.这些数据可以分为哪些类

- 基本数据类型:number、string、undefined、null、boolean、symbol、bigint

- 引用数据类型:object、array、function

3.基本和引用数据类型之间的区别是什么?

- 基本数据类型存储的时候是在计算机的栈内存中

- 引用数据类型储存的时候也是在计算的栈内存中(地址)储存的是地址 地址指向的才是堆内存(数据)

数组的常用方法有哪些?

1.数组方法基本的使用

- 添加到数组的末尾 数组.push(添加的值)

- 添加到数组的首位 数组.unshift(添加的值) en谢负特

- 删除数组中的最后一个元素 数组.pop()

- 删除数组中的第一个元素 数组.shift() 谢负特

2.splice 丝普莱丝

- 删除数组中的值 数组.splice(开始的下标,删除的个数)

- 可以添加新的值 数组.splice(开始的下标,0,添加的值)

splice : 数组任意地方删除或者添加元素

3.indexOf方法

查找某个元素在数组中第一次出现的位置

4.forEach方法

用于遍历数组 使用说明:这个方法没有返回值,返回值为undefined,不会改变原来数组的值。

5.map方法

遍历数组,并将每个元素传入回掉函数中处理后,组成新的数组并返回 使用说明:这个方法主要用于以同样的 规则处理数组中的每个值,并组成新的数组返回

6.filter方法 fu呃特

遍历数组,根据过滤条件,筛选出数组中满足条件的元素,组成新数组并返回 使用说明:使用方法和功能跟 map方法很像,只是运行规则不一样。map方法中的函数,用于返回新的元素,而filter方法中的函数,根 据返回truefalse来筛选元素

7.reduce方法 瑞丢丝

归并,其中调用回掉函数,回掉函数中有两个参数,第一个参数是上一次操作的返回值,第二个参数是从第二 个元素开始到最后一个元素

8.reverse()

反转数组中的值: 数组.reverse() 瑞沃丝

9.concat()

拼接数组 数组.concat(拼接的值) 康凯t

- 拼接返回一个新的数组 需要定义一个变量去接收新的数组

- 拼接多个值的时候,只需要在小括号内再写多个值就行了(值需要使用逗号隔开)

10.slice()

截取数组 数组.slice(开始下标,结束的下标) 丝莱丝

截取也会返回一个新的数组 需要使用一个变量接收新的数组

开始和结束的下标表示:包含开始,不包含结束 => [)

第二个参数是可以省略的 表示从开始下标到结束全部选中截取

开始和结束的下标如果是正值的情况下:结束一定要大于开始 不然会输出空的数组

开始和结束的下标如果是负值的情况下:第一个参数一定要比第二个参数小 (负值是倒着数的-了解)

11.join()

拼接字符串 数组.join('连接符号') 囧in

12..sort()

数组排序 数组.sort() 10以下的数 索t

谈谈 JavaScript 中的类型转换机制

常见的类型转换有:

  • 强制转换(显示转换)

  • 自动转换(隐式转换)

Number()

将任意类型的值转化为数值

先给出类型转换规则:

斗智斗勇一_第1张图片

parseInt()

parseInt相比Number,就没那么严格了,parseInt函数逐个解析字符,遇到不能转换的字符就停下来

parseInt('32a3') //32

String()

可以将任意类型的值转化成字符串

给出转换规则图:

斗智斗勇一_第2张图片

Boolean()

可以将任意类型的值转为布尔值,转换规则如下:

斗智斗勇一_第3张图片

自动转换为布尔值

  • undefined

  • null

  • false

  • +0

  • -0

  • NaN

  • ""

除了上面几种会被转化成false,其他都换被转化成true

自动转换成数值

字符串+做拼接处理,其他运算符都会把运算子自动转成数值进行运算

== 和 ===区别,分别在什么情况使用

  • 两个都为简单类型,字符串和布尔值都会转换成数值,再比较

  • 简单类型与引用类型比较,对象转化成其原始类型的值,再比较

  • 两个都为引用类型,则比较它们是否指向同一个对象

  • null 和 undefined 相等

  • 存在 NaN 则返回 false

全等操作符由 3 个等于号( === )表示,只有两个操作数在不转换的前提下相等才返回 true。即类型相同,值也需相同

使用相等操作符(==)的写法明显更加简洁了

所以,除了在比较对象属性为null或者undefined的情况下,我们可以使用相等操作符(==),其他情况建议一律使用全等操作符(===)

深拷贝浅拷贝的区别?如何实现一个深拷贝?

浅拷贝

浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝

如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址

即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址

深拷贝

深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另 一个对象的属性

小结

前提为拷贝类型为引用类型的情况下:

  • 浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址

  • 深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址

说说你对闭包的理解?闭包使用场景

闭包是什么

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围), 这样的组合就是闭包(closure)

形成条件

内部函数引用外部函数的变量的时候闭包就产生了

优点

可以让外部作用访问到内部作用的变量 延长局部变量的生命周期

作用

闭包当中的变量会一直存在于内存当中,可以一直给我们来进行使用 不会被垃圾回收机制处理

外部作用域可以访问函数内部的变量

缺点

因为局部变量会一直存在于内存当中,所以会一直占用这内存空间,对于IE低版本的浏览器来说,容易造成内存泄露,消耗内存

为什么要使用闭包

对于普通函数来讲,函数执行完毕之后,会释放掉其内存空间 闭包,不会主动的释放内存空间

说说你对作用域链的理解

作用域决定了代码区块中变量和其他资源的可见性

我们一般将作用域分成:

  • 全局作用域

  • 函数作用域

  • 块级作用域

全局作用域

任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意 位置访问

函数作用域

函数作用域也叫局部作用域,如果一个变量是在函数内部声明的它就在一个函数作用域下面。这些变量只能在 函数内部访问,不能在函数以外去访问

块级作用域

ES6引入了letconst关键字,和var关键字不同,在大括号中使用letconst声明的变量存在于块级作用 域中。在大括号之外不能访问这些变量

词法作用域

词法作用域,又叫静态作用域,变量被创建时就确定好了,而非执行阶段确定的。也就是说我们写好代码时它 的作用域就确定了,JavaScript 遵循的就是词法作用域

作用域链

当在Javascript中使用一个变量的时候,首先Javascript引擎会尝试在当前作用域下去寻找该变量,如果没 找到,再到它的上层作用域寻找,以此类推直到找到该变量或是已经到了全局作用域

JavaScript原型,原型链 ? 有什么特点?

原型

**每一个函数自诞生以来都有一个对象 `prototype` => 显示原型对象**
**每一个对象自诞生以来都一个属性 `__proto__` => 隐式原型对象**

原型链

原型对象也是一个对象,一层一层的串下去,形成了一个链条,叫做原型链

Javascript如何实现继承?

下面给出JavaScripy常见的继承方式:

  • 原型链继承

原型链继承是比较常见的继承方式之一,其中涉及的构造函数、原型和实例,三者之间存在着一定的关系, 即 每一个构造函数都有一个原型对象,原型对象又包含一个指向构造函数的指针,而实例则包含一个原型 对象的 指针

  • 构造函数继承(借助 call)

借助 call调用Parent函数

  • 组合继承

前面我们讲到两种继承方式,各有优缺点。组合继承则将前两种方式继承起来

  • 原型式继承

这里主要借助Object.create方法实现普通对象的继承

  • 寄生式继承

寄生式继承在上面继承基础上进行优化,利用这个浅拷贝的能力再进行增强,添加一些方法

  • 寄生组合式继承

    寄生组合式继承,借助解决普通对象的继承问题的Object.create 方法,在前面几种继承方式的优缺点基础上进行改造,这也是所有继承方式里面相对最优的继承方式

谈谈this对象的理解

在绝大多数情况下,函数的调用方式决定了 this 的值(运行时绑定)

this 关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象

- 在普通函数中指向 window

- 在事件函数中指向 事件源

- 在定时器中指向是 window

- 在自执行函数执行 window

JavaScript中执行上下文和执行栈是什么?

执行上下文的类型分为三种:

  • 全局执行上下文:只有一个,浏览器中的全局对象就是 window对象,this 指向这个全局对象

  • 函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文

  • Eval 函数执行上下文: 指的是运行在 eval 函数中的代码,很少用而且不建议使用

执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 回收阶段

说说JavaScript中的事件模型

javascript中的事件,可以理解就是在HTML文档或者浏览器中发生的一种交互操作,使得网页具备互动性, 常见的有加载事件、鼠标事件、自定义事件等

事件流都会经历三个阶段:

  • 事件捕获阶段(capture phase)

  • 处于目标阶段(target phase)

  • 事件冒泡阶段(bubbling phase)

事件模型可以分为三种:

  • 原始事件模型(DOM0级)

  • 标准事件模型(DOM2级)

  • IE事件模型(基本不用

typeof 与 instanceof 区别

typeof 操作符返回一个字符串,表示未经计算的操作数的类型

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

typeofinstanceof都是判断数据类型的方法,区别如下:

  • typeof会返回一个变量的基本类型,instanceof返回的是一个布尔值

  • instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型

  • typeof 也存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了function 类型以外,其他的也无法判断

如果需要通用检测数据类型,可以采用Object.prototype.toString,调用该方法,统一返回格式“[object Xxx]”的字符串

解释下什么是事件代理?应用场景?

事件委托,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,而不是目标元素

当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数

从上面应用场景中,我们就可以看到使用事件委托存在两大优点:

  • 减少整个页面所需的内存,提升整体性能

  • 动态绑定,减少重复工作

如果把所有事件都用事件代理,可能会出现事件误判,即本不该被触发的事件被绑定上了事件 有些没有事件冒泡机制,所以无法进行委托绑定事件

说说new操作符具体干了什么?

JavaScript中,new操作符用于创建一个给定构造函数的实例对象

从上面介绍中,我们可以看到new关键字主要做了以下的工作:

  • 创建一个新的对象obj

  • 将对象与构建函数通过原型链连接起来

  • 将构建函数中的this绑定到新建的对象obj

  • 根据构建函数返回类型作判断,如果是原始值则被忽略,如果是返回对象,需要正常处理

ajax原理是什么?如何实现?

AJAX全称(Async Javascript and XML)

即异步的JavaScriptXML,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页

Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面

优点:

异步:效率高

局部刷新:用户体验好

承载部分的服务器的压力

有没有From表单都可以发送请求

bind、call、apply 区别?如何实现一个bind?

callapplybind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向

apply 以数组的形式传入 改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次

call 跟apply一样,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次

bind 改变this指向后不会立即执行,而是返回一个永久改变this指向的函数

说说你对正则表达式的理解?应用场景?

正则表达式是一种用来匹配字符串的强有力的武器

它的设计思想是用一种描述性的语言定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的

说说你对事件循环的理解

首先,JavaScript是一门单线程的语言,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环

JavaScript中,所有的任务都可以分为

  • 同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行

  • 异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等

异步任务还可以细分为微任务与宏任务

async 是异步的意思,await则可以理解为 async wait。所以可以理解async就是用来声明一个异步方法,而 await是用来等待异步方法执行

DOM常见的操作有哪些?

文档对象模型 (DOM) 是 HTMLXML 文档的编程接口

通过document获取节点

document.getElementById("标签id名"); // 通过标签的id名获取标签
document.getElementsByTagName("标签名"); // 通过标签名获取标签
document.getElementsByClassName("标签类名"); // 通类名获取标签
document.getElementsByName("标签的name属性的值"); // 通过标签的name属性获取标签
// 上述4种获取标签的方法,除了通过id可以准确获取到元素,别的方法都是只能获取到元素的集合(类数组)

使用css选择器获取元素:

documen.querySelector(css选择器); // 获取到匹配css的第一个元素
documen.querySelectorAll(css选择器); // 获取到匹配css的所有元素

创建节点 createElement

更新节点 innerHTML

appendChild 把一个子节点添加到父节点的最后一个子节点

insertBefore 把子节点插入到指定位置

removeChild 删除节点

说说你对BOM的理解,常见的BOM对象你了解哪些?

BOM (Browser Object Model),浏览器对象模型,提供了独立于内容与浏览器窗口进行交互的对象

其作用就是跟浏览器做一些交互效果,比如如何进行页面的后退,前进,刷新,浏览器的窗口发生变化,滚动条的滚动,以及获取客户的一些信息如:浏览器品牌版本,屏幕分辨率

Bom的核心对象是window,它表示浏览器的一个实例

location 网页地址相关操作 navigator 对象主要用来获取浏览器的属性,区分浏览器类型 history 操作浏览器URL的历史记录,可以通过参数向前,向后,或者向指定

说说 JavaScript 中内存泄漏的几种情况?

内存泄漏(Memory leak)是在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存

常见的内存泄露情况 意外的全局变量 定时器也常会造成内存泄露 闭包维持函数内局部变量 使其得不到释放

没有清理对DOM元素的引用同样造成内存泄露 包括使用事件监听addEventListener监听的时候,在不监听的情

况下使用removeEventListener取消对事件监听

Javascript本地存储的方式有哪些?区别及应用场景?

javaScript本地缓存的方法我们主要讲述以下四种:

  • cookie

cookie 是服务器端保存在浏览器的一小段文本信息,浏览器每次向服务器端发出请求,都会附带上这段信息

会话状态管理(登录状态 购物车 游戏分数)个性化设置(自定义主题)浏览器行为跟踪(跟踪分析用户行为)

  • sessionStorage

一旦页面(会话)关闭,sessionStorage 将会删除数据 设置setItem 获取getItem 删除removeItem

  • localStorage

持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的

  • indexedDB

indexedDB是一种低级API,用于客户端存储大量结构化数据(包括, 文件/ blobs)。该API使用索引来实现对该数据的高性能搜索

说说你对函数式编程的理解?优缺点?

主要的编程范式有三种:命令式编程,声明式编程和函数式编程

优点 更好的管理状态 更简单的复用 更强的复用性 强大的组合性 减少代码量,提高维护性

缺点 性能开销 资源占用 递归陷阱 在函数式编程中,为了实现迭代,通常会采用递归操作

Javascript中如何实现函数缓存?函数缓存有哪些应用场景?

函数缓存,就是将函数运算过的结果进行缓存

本质上就是用空间(缓存存储)换时间(计算过程)

常用于缓存数据计算结果和缓存对象

实现函数缓存主要依靠闭包、柯里化、高阶函数

说说 Javascript 数字精度丢失的问题,如何解决?

理论上用有限的空间来存储无限的小数是不可能保证精确的,但我们可以处理一下得到我们期望的结果

当你拿到 1.4000000000000001 这样的数据要展示时,建议使用 to Precision 凑整并 parseFloat 转成数字后再显示

什么是防抖和节流?有什么区别?如何实现?

节流 在大量触发的事件当中,我们让他在短时间当中触发少次

防抖 在连续触发事件当中,我们让他在短时间触发一次

应用场景

防抖在连续的事件,只需触发一次回调的场景有:

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求

  • 手机号、邮箱验证输入检测

  • 窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。

节流在间隔一段时间执行一次回调的场景有:

  • 滚动加载,加载更多或滚到底部监听

  • 搜索框,搜索联想功能

如何判断一个元素是否在可视区域中?

判断一个元素是否在可视区域,我们常用的有三种办法:

  • offsetTop、scrollTop

offsetTop,元素的上外边框至包含元素的上内边框之间的像素距离

  • getBoundingClientRect

返回值是一个 DOMRect对象,拥有left, top, right, bottom, x, y, width, 和 height属性

如果一个元素在视窗之内的话,那么它一定满足下面四个条件:

top 大于等于 0 left 大于等于 0 bottom 小于等于视窗高度 right 小于等于视窗宽度

  • Intersection Observer

Intersection Observer 即重叠观察者,从这个命名就可以看出它用于判断两个元素是否重叠,因为不用进行事件的监听,性能方面相比getBoundingClientRect会好很多

大文件上传如何做断点续传?

整体思路比较简单,拿到文件,保存文件唯一性标识,切割文件,分段上传,每次上传一段,根据唯一性标识判断文件上传进度,直到文件的全部片段上传完毕

使用场景

  • 大文件加速上传:当文件大小超过预期大小时,使用分片上传可实现并行上传多个 Part, 以加快上传速度

  • 网络环境较差:建议使用分片上传。当出现上传失败的时候,仅需重传失败的Part

  • 流式上传:可以在需要上传的文件大小还不确定的情况下开始上传。这种场景在视频监控等行业应用中比较常见

如何实现上拉加载,下拉刷新?

上拉加载及下拉刷新都依赖于用户交互 什么时机下触发交互动作 上拉加载的本质是页面触底,或者快要触底时的动作 下拉刷新的本质是页面本身置于顶部时,用户下拉时需要触发的动作

什么是单点登录?如何实现?

利用cookie

web常见的攻击方式有哪些?如何防御?

XSS,跨站脚本攻击,允许攻击者将恶意代码植入到提供给其它用户使用的页面中

  • XSS (Cross Site Scripting) 跨站脚本攻击

  • CSRF(Cross-site request forgery)跨站请求伪造

  • SQL注入攻击

你可能感兴趣的:(前端,javascript)