1. JS 数据类型 ?存储上的差别?
数据类型主要包括两部分:
基本数据+类型: Undefined、Null、Boolean、Number 和 String,Symbol(创建后独一无二且不可变的数据类型 )
引用数据类型: Object (包括 Object 、Array 、Function)
存储区别:
基本数据类型存储在栈中
引用类型的对象存储于堆中
2.数组常用方法?
增:
push() 向数组的末尾添加一个或更多元素,并返回新的长度
unshift() 在数组开头添加任意多个值,然后返回新的数组长度
splice() 传入三个参数,分别是开始位置、0(要删除的元素数量)、插入的元素,返回空数组
concat() 首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组,不会影响原始数组
删:
pop() 方法用于删除数组的最后一项,同时减少数组的length 值,返回被删除的项
shift() 方法用于删除数组的第一项,同时减少数组的length 值,返回被删除的项
splice() 传入两个参数,分别是开始位置,删除元素的数量,返回包含删除元素的数组
slice() 传入两个参数,分别是开始位置和结束位置,不包括结束值,返回一个新数组,不影响原数组
改:
splice() 传入三个参数,分别是开始位置,要删除元素的数量,要插入的任意多个元素,返回删除元素的数组,对原数组产生影响
查:
indexOf() 返回要查找的元素在数组中的位置,如果没找到则返回 -1
includes() 返回要查找的元素在数组中的位置,找到返回true,否则false
find() 返回第一个匹配的元素
3.JavaScript字符串的常用操作方法有哪些?
增:
字符串可以通过‘+’以及${}进行字符串拼接
concat 用于将一个或多个字符串拼接成一个新字符串
删:三个函数都接收一个或两个参数,跟数组中slice相似
slice()
substr() 接受两个参数:起始索引和要提取的字符数
substring() 接受两个参数:起始索引和结束索引 不包括结束位置的字符
改:
trim()、trimLeft()、trimRight() 删除前、后或前后所有空格符,再返回新的字符串
repeat() 接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果
padStart()、padEnd() 复制字符串,接收两个参数,第一个参数是长度,第二个参数是想要填充的字符,如果小于指定长度,则在相应一边(end/start)填充字符,直至满足长度条件
toLowerCase()、 toUpperCase() 大小写转化
查:
chatAt() 返回给定索引位置的字符,由传给方法的整数参数指定
indexOf() 从字符串开头去搜索传入的字符串,并返回位置(如果没找到,则返回 -1 )
startWith() 从字符串中搜索传入的字符串,判断开头字符串是否与期待值相同,并返回一个表示是否包含的布尔值
includes() 从字符串中搜索传入的字符串,判断字符串是否包含期待值,并返回一个表示是否包含的布尔值
4.JavaScript字符串的常用转换方法和模板匹配方法?
转换方法:
split() 把字符串按照指定的分割符,拆分成数组中的每一项
模板匹配方法:
match() 接收一个参数,可以是一个正则表达式字符串,也可以是一个RegExp对象,返回数组
search() 接收一个参数,可以是一个正则表达式字符串,也可以是一个RegExp对象,找到则返回匹配索引,否则返回 -1
replace() 接收两个参数,第一个参数为匹配的内容,第二个参数为替换的元素(可用函数)
5.JavaScript 中的类型转换机制
显示转换:
Number()
字符串:如果可以被解析为数值,则转换为相应的数值
字符串:如果不可以被解析为数值,返回 NaN
空字符串转换为0
布尔值:true 转成 1,false 转成 0
undefined:转成 NaN
null:转成0
对象:通常转换成NaN(除了只包含单个数值的数组)
parseInt() parseInt相比Number,就没那么严格了,parseInt函数逐个解析字符,遇到不能转换的字符就停下来
String() 可以将任意类型的值转化成字符串
特殊:如果接受的是对象则返回[object,object] 如果是数组【1,2,3】返回1,2,3
Boolean() 可以将任意类型的值转为布尔值
隐式转换:
在+运算中,一旦存在字符串,则会进行字符串拼接操作
除了+有可能把运算子转为字符串,其他运算符都会把运算子自动转成数值 。常用就是将字符串转为数值 字符串-0 = 数值
6.null 和 undefined 的区别?
null和undefined不能通过==来判断。
undefined
这个变量从根本上就没有定义
隐藏式 空值
null
这个值虽然定义了,但它并未指向任何内存中的对象
声明式 空值
7. “ ===”、“ ==”的区别?
==: 如果操作数相等,则会返回 true
两个都为简单类型,字符串和布尔值都会转换成数值,再比较
简单类型与引用类型比较,对象转化成其原始类型的值,再比较
两个都为引用类型,则比较它们是否指向同一个对象
null 和 undefined 相等
存在 NaN 则返回 false
===:只有在无需类型转换运算数就相等的情况下,才返回 true,需要检查数据类型
区别:
相等操作符(==)会做类型转换,再进行值的比较,全等运算符不会做类型转换
8. “eval是做什么的?
它的功能是把对应的字符串解析成 JS 代码并运行;
应该避免使用 eval,不安全,非常耗性能(2次,一次解析成 js 语句,一次执行)。
9. 箭头函数有哪些特点?
不需要function关键字来创建函数
省略return关键字
改变this指向
10. var、let、const 区别?
var 存在变量提升。
let 只能在块级作用域内访问。
const 用来定义常量,必须初始化,不能修改(对象特殊)
11. new操作符具体干了什么呢?
1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
2、属性和方法被加入到 this 引用的对象中。
3、新创建的对象由 this 所引用,并且最后隐式的返回 this 。
12.深拷贝浅拷贝的区别?如何实现一个深拷贝?
浅拷贝: 指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝 , 两个对象指向同一个地址
深拷贝: 深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
如何实现深拷贝:
JSON.stringify()
手写循环递归
_.cloneDeep()
MessageChannel 新增
jquery的extend
13.对作用域链的理解
作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的
简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期
14.JavaScript原型,原型链 ? 有什么特点?
原型:
JavaScript的所有对象中都包含了一个 [__proto__] 内部属性,这个属性所对应的就是该对象的原型
JavaScript的函数对象,除了原型 [__proto__] 之外,还预置了 prototype 属性
当函数对象作为构造函数创建实例时,该 prototype 属性值将被作为实例对象的原型 [__proto__]
原型链:
当一个对象调用的属性/方法自身不存在时,就会去自己 [__proto__] 关联的前辈 prototype 对象上去找
如果没找到,就会去该 prototype 原型 [__proto__] 关联的前辈 prototype 去找。依次类推,直到找到属性/方法或 undefined 为止。从而形成了所谓的“原型链”
原型特点:
JavaScript对象是通过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变
15.请解释什么是事件代理
事件代理(Event Delegation),又称之为事件委托。是 JavaScript 中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。使用事件代理的好处是可以提高性能
可以大量节省内存占用,减少事件注册,比如在table上代理所有td的click事件就非常棒
可以实现当新增子对象时无需再次对其绑定
16.Javascript如何实现继承?
构造函数绑定:使用 call 或 apply 方法,将父对象的构造函数绑定在子对象上
实例继承:将子对象的 prototype 指向父对象的一个实例 Cat.prototype = new Animal();
拷贝继承:如果把父对象的所有属性和方法,拷贝进子对象
原型继承:将子对象的 prototype 指向父对象的 prototype F.prototype = Parent.prototype;
ES6 语法糖 extends:class ColorPoint extends Point {}
17.谈谈This对象的理解
this总是指向函数的直接调用者(而非间接调用者)
如果有new关键字,this指向new出来的那个对象
在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window
18.事件模型
W3C中定义事件的发生经历三个阶段:捕获阶段(capturing)、目标阶段(targetin)、冒泡阶段(bubbling)
冒泡型事件:当你使用事件冒泡时,子级元素先触发,父级元素后触发
捕获型事件:当你使用事件捕获时,父级元素先触发,子级元素后触发
DOM事件流:同时支持两种事件模型:捕获型事件和冒泡型事件
阻止冒泡:在W3c中,使用stopPropagation()方法;在IE下设置cancelBubble = true
阻止捕获:阻止事件的默认行为,例如click - 后的跳转。在W3c中,使用preventDefault()方法,在IE下设置window.event.returnValue = false
19.new操作符具体干了什么呢?
创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型
属性和方法被加入到 this 引用的对象中
新创建的对象由 this 所引用,并且最后隐式的返回 this
20.JavaScript中执行上下文和执行栈是什么?
执行上下文: 是一种对Javascript代码执行环境的抽象概念,也就是说只要有Javascript代码运行,那么它就一定是运行在执行上下文中
全局执行上下文:只有一个,浏览器中的全局对象就是 window对象,this 指向这个全局对象
函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文
Eval 函数执行上下文: 指的是运行在 eval 函数中的代码,很少用而且不建议使用
执行栈:也叫调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文
当Javascript引擎开始执行你第一行脚本代码的时候,它就会创建一个全局执行上下文然后将它压到执行栈中
每当引擎碰到一个函数的时候,它就会创建一个函数执行上下文,然后将这个执行上下文压到执行栈中
引擎会执行位于执行栈栈顶的执行上下文(一般是函数执行上下文),当该函数执行结束后,对应的执行上下文就会被弹出,然后控制流程到达执行栈的下一个执行上下文
21.typeof 与 instanceof 区别?
typeof 操作符返回一个字符串,表示未经计算的操作数的类型
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
区别:
typeof会返回一个变量的基本类型,instanceof返回的是一个布尔值
instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型
而typeof 也存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了function 类型以外,其他的也无法判断
22.判断是否为数组的5种方法?
instanceof data instanceof Array
constructor data.constructor == Array
Array.isArray() Array.isArray(data) 最推荐
typeof typeof(data)
Object.prototype.toSrtring.call()
23. 判断一个值是什么类型有哪些方法?
typeof 运算符
instanceof 运算符
Object.prototype.toString.call 方法
constructor
24. ajax过程?
(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象.
(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
(3)设置响应HTTP请求状态变化的函数.
(4)发送HTTP请求.
(5)获取异步调用返回的数据.
(6)使用JavaScript和DOM实现局部刷新.
25.Ajax原理,ajax优缺点?
Ajax的原理简单来说是在用户和服务器之间加了—个中间层(AJAX引擎),通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。使用户操作与服务器响应异步化。这其中最关键的一步就是从服务器获得请求数据
Ajax的过程只涉及JavaScript、XMLHttpRequest和DOM。XMLHttpRequest是ajax的核心机制
优点:
通过异步模式,提升了用户体验.
优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用.
Ajax在客户端运行,承担了一部分本来由服务器承担的工作,减少了大用户量下的服务器负载。
Ajax可以实现动态不刷新(局部刷新)
缺点:
安全问题 AJAX暴露了与服务器交互的细节。
对搜索引擎的支持比较弱。
不容易调试。
26.bind、call、apply 区别?
bind、call、apply用来改变this指向
apply:接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入
改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次 fn.apply(null,[1,2,3]);
call: 第一个参数也是this的指向,后面传入的是一个参数列表 fn.call(obj,1,2,3)
bind: bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入) 返回的是新的函数
27.如何实现一个bind?
实现bind三步:
修改this指向
动态传递参数
兼容new关键字
28.说说你对正则表达式的理解?应用场景?
正则表达式是一种用来匹配字符串的强有力的武器
应用场景:
验证QQ合法性(5~15位、全是数字、不以0开头):
验证手机号格式
29.对事件循环的理解(详细)?
前提: JavaScript是一门单线程的语言,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环
在JavaScript中,所有的任务都可以分为
同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等
同步任务进入主线程,即主执行栈,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。上述过程的不断重复就事件循环
异步任务分为微任务和宏任务:
微任务: 一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前
Promise
MutaionObserver 监听dom发生改变的
Object.observe(已废弃;Proxy 对象替代)
process.nextTick(Node.js)
宏任务: 宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合
script (可以理解为外层同步代码)
setTimeout/setInterval
postMessage、MessageChannel
setImmediate、I/O(Node.js)
执行顺序:
先执行同步代码,
遇到异步宏任务则将异步宏任务放入宏任务队列中,
遇到异步微任务则将异步微任务放入微任务队列中,
当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,
微任务执行完毕后再将异步宏任务从队列中调入主线程执行,
一直循环直至所有任务执行完毕。