1. 讲一下 var、let、const 的区别?
var 声明的变量有变量提升的特性,而 let、const 没有
var 声明的变量会挂载到 windows 对象上,所以使用 var 声明的是全局变量,而 let 和 const 声明的变量是局部变量, 块级作用域外不能访问
同一作用域下 let 和 const 不能重复声明同名变量,而var可以
const声明的是常量,必须赋初值,一旦声明不能再次赋值修改,如果声明的是复合类型数据,可以修改其属性
2. js中的基础数据类型有哪几种? 了解包装对象吗?
答:六种,string, number, boolean, undefiend, null, symbol 基础数据类型临时创建的临时对象,称为包装对象。其中 number、boolean 和 string 有包装对象,代码运行的过程中会找到对应的包装对象,然后包装对象把属性和方法给了基本类型,然后包装对象被系统进行销毁。
3. 如何判断this指向?箭头函数的this指向什么?
可以分为6种情况来描述this指向
普通函数直接调用中的this
普通函数中的 this 指向 window 对象, 严格模式下为 undefiend
在对象里调用的this
指向调用函数的那个对象,this: 谁调用就指向谁
在构造函数以及类中的this
构造函数和类需要配合 new 使用, 而 new 关键字会将构造函数中的 this 指向实例对象,所以 this 指向 实例对象。
绑定事件函数的this
谁调用就指向谁。
定时器中的this
定时器中的 this 指向 window,因为定时器中采用回调函数作为处理函数,而回调函数的 this 指向 window。
箭头函数中的this
箭头函数没有自己的 this,会继承其父作用域的 this。
4. call apply bind 的作用与区别?
作用
改变函数内部 this 的指向
区别
call 和 apply 会调用函数,而 bind 不会调用
call 和 bind 的参数是 参数列表逐个传入,而 apply 的参数必须为数组形式
闭包的定义
闭包是指能够访问另一个函数作用域中的变量的一个函数。 在js中,只有函数内部的子函数才能访问局部变量, 所以闭包可以理解成 “定义在一个函数内部的函数”。
闭包的作用
利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部,让外部函数可以访问到内部函数的变量和方法
闭包的优点
正常的函数,在执行完之后,函数里面声明的变量会被垃圾回收机制处理掉。但是形成闭包的函数在执行之后,不会被回收,依旧存在内存中。
闭包的缺点
因为变量不会被回收,所以内存中一直存在,耗费内存。
异步任务分为 宏任务 和 微任务
9.浏览器为什么要阻止跨域请求?如何解决跨域?每次跨域请求会达到服务端吗?
浏览器阻止跨域请求的原因是因为"同源政策" , "同源政策"主要解决浏览器的安全问题,"同源"是 协议、域名 和 端口都相同,非同源是 协议 域名 和 端口 只要有一个不同都是非同源,就会有跨域问题
解决跨域的方法有很多种
使用jsonp跨域 postMessage跨域 跨域资源共享(CORS) nodejs中间件代理跨域( (用的最多)通过中间件进行转发到非同源地址,请求的还是同源地址) WebSocket协议跨域 每次的跨域请求都会正常发出,服务端也会正常返回,但是被浏览器拦截了,所以跨域请求会到达服务端
1. 理解
- 定义:程序中已在堆中分配的内存,因为某种原因未释放或者无法释放的问题
- 简单理解: 无用的内存还在占用,得不到释放和归还,比较严重的时候,无用的内存还会增加,从而导致整个系统卡顿,甚至崩溃。
2. 生命周期
1. 分配期
分配所需要的内存,在js中,是自动分配的
2. 使用期
使用分配的内存,就是读写变量或者对象的属性值
3. 释放期
不需要时将该内存释放,js会自动释放(除了闭包和一些bug以外)
内存泄漏就是出现在这个时期,内存没有被释放导致的
3. 可能出现内存泄漏的原因
1. 意外的全局变量
2. DOM元素清空时,还存在引用
3. 闭包
4. 遗忘的定时器
11.Token一般存放在哪里? Token放在 cookie, sessionStorage 和 localStorage 中有什么区别?
W3C 中定义事件的发生经历三个阶段
捕获阶段 目标阶段 冒泡阶段
阻止冒泡:在 W3c 中,使用 stopPropagation()方法
创建一个空对象,并且把 this 指向这个对象,同时还继承了该对象的原型 属性和方法被加入到 this 引用的对象中
不会进行函数提升 没有自己的 this,this指向的是所在作用域指向的对象 不能使用 new 关键字 不可以使用 arguments 对象
15.JavaScript 原型,原型链 ? 有什么特点?
原型
原型分为隐式原型(__ proto__ ) 和 显式原型(prototype),每个对象都有它的隐式原型(__ proto__ ),指向它对应构造函数的显式原型(prototype) 无论何时,只要创建一个函数,就会为这个函数添加一个 prototype 属性,这个属性就指向原型对象__JavaScript高级程序设计(第四版)p225 构造函数的 prototype 指向原型对象,原型对象有一个 constructor 属性指回构造函数,每个构造函数生成的实例对象都有一个 __ proto__ 属性,这个属性也指向原型对象。
原型链
每个对象都有 __ proto__ 属性,这个属性指向原型对象,当想访问对象的一个属性时,如果这个对象本身没有这个属性就会通过 __ proto__ 属性 查找,原型对象也是对象,每个对象又有自己的 __ proto__ 属性,所以就会一直这样查找上去,直到找到这个属性,这就是原型链的概念。 原型链就是对象沿着 __ proto__ 这条链逐步向上搜索,最顶层是 Object,Object 的 __ proto__ 是 null。
是 js 中常用绑定事件的常技巧。“事件代理”是把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是 DOM 元素的事件冒泡。使用事件委托的好处是可以提高性能。 可以大量节省内存占用,减少事件注册,当新增子对象时无需再次对其绑定。
JSON 字符串转换为 JSON 对象
let obj = JSON . parse ( str) ;
JSON 对象转换为 JSON 字符串
let obj = JSON . stringify ( str) ;
作用域
函数在定义时会创建一个 AO对象,就是作用域 规定变量和函数的可使用范围称为 作用域
作用域链
作用域链会被保存到一个隐式属性 [[ scope ]] 中去,这个属性是我们用户访问不到的,但的的确确是存在的 是让js引擎来访问的 里面存储的就是作用域链 作用域就是代码执行之前产生的 AO 和 GO, 作用域链就是 AO 和 GO 的集合 每个函数都有一个作用域链,查找变量或方法时,会先从函数作用域逐层查找最后到全局作用域查找,这些作用域的集合称为作用域链。
浅拷贝: 如果拷贝的是基本数据类型相当于直接拷贝它的值,修改值互不影响 如果拷贝的是引用数据类型,拷贝的就是指向堆内存里面这个对象的内存地址 ,如果修改了其中一个对象的数据,那么另一个对象也会受到影响,因为内存地址 指向堆里面同一块内存 常用 es6 0bject.assign()
实现 深拷贝: 深拷贝是将一个对象完整的独立拷贝一份出来,然后在堆内存中开辟一块新的内存块存储,所以不会互相影响 常用 es6扩展运算符
递归
Array.concat()
实现
防抖:高频的触发事件,规定时间内触发会被清除,只有当超过规定时间触发,然后执行最后一次事件 节流:高频的触发事件,限制触发次数,规定时间内只能触发一次
2开头的表示请求成功
3开头的表示重定向
4开头表示客户端错误
400表示请求报文中存在语法错误 403常见的跨域 404请求资源不存在 5开头表示服务器端错误
let、const: 声明变量和常量 模板字符串:增强版的字符串,用反引号标识,嵌入变量只需要放在${}
中 箭头函数:ES6中函数定义不再使用关键字function(),而是利用了()=>来进行定义 解构赋值:按照类型的不同有不同的方式提取值,赋值 Symbol:新增的基本数据类型,特点就是里面的值唯一 Set 和 Map 数据结构 展开运算符(…): 可以将数组或对象里面的值展开, 还可以将 Set 数据结构转换为数组 for...of
循环: 可以遍历数组对象以及 Set 和 Map 数据结构class 类:通过 extends
实现继承 promise、(async/await): 都是用来解决异步编程的方案 10.proxy:代理对象,直接监听对象的变化,然后触发相应的逻辑
Promise 是 es6
引入解决异步编程问题的解决方案 Promise 有三种状态:pending(进行中)、resolve(已完成)、reject(已失败) 当 Promise 的状态由 pending 转变为 resolved 或 reject 时,会执行相应的回调, 一旦从 pending 状态变成为其他状态就不能再更改状态了 可以链式调用,解决回调地狱的问题
28. Promise.all() 和 Promise.race()
Promise.all()
Promise.all()
的作用是接收一组异步任务,然后并行执行任务,等所有任务执行完之后再执行回调Promise.all()
传入一组 Promise 数组,只有当所有的 Promise 状态都成功才返回成功,只要有一个失败就返回失败的 Promise 状态
Promise.race()
Promise.race()
的作用是接收一组异步任务,然后并行执行任务,只留取第一个完成的任务,其他任务任然会执行,只不过执行结果会被抛弃Promise.race()
传入一个 Promise 数组,返回的结果由第一个执行完成的 Promise对象 的结果来决定
29. 怎么让一个函数无论promise对象成功和失败都能被调用?
Promise.finally()
finally 方法用于不管 Promise 的状态变为什么,都会执行它内部的函数
30. ajax 的作用 和 优缺点 (ajax整理的不多就一起放这里面了)
优点
实现页面局部刷新,在不刷新整个页面的情况下与服务器通信 分担一部分后端的工作,减少服务器压力
缺点
对 seo 的支持比较弱 ajax 不支持浏览器的返回按钮
1. 创建 ajax 对象
const ajax = new XMLHttpRequest ( ) ;
2. 创建 ajax 请求 ( 设置请求的方法和请求地址) open
ajax. open ( 'get' , 'http://localhost:8080/server?a=100&b=200' ) ;
3. 发送请求 send
ajax. send ( ) ;
4. 处理服务器端返回的结果 onreadystatechange事件
readystate:五个值 0 1 2 3 4 ,为4 的时候代表数据已经接收完成
status:状态码 200 为成功
if ( ajax. readystate === 4 && ajax. status >= 200 && ajax. status < 300 ) {
表示成功,可以写相应的逻辑了
}
原生 ajax 可以通过 XMLHttpRequest 对象上的 abort 方法中断 ajax 请求; 应用场景:文件上传
两者都可以用于遍历数组,只不过for-in
遍历的是数组元素的索引 (index), 而for-of
遍历的是数组元素的值 for-in
可以遍历普通对象,获取的是对象的键名。 for-of
不可以遍历普通对象for-in
不可以遍历Set/Map for-of
可以遍历Set/Map
typeof
常用于判断基本数据类型,因为对象、数组和Null都返回的Object
console. log ( typeof '温情' ) ;
console. log ( typeof 111 ) ;
console. log ( typeof true ) ;
console. log ( typeof undefined ) ;
console. log ( typeof function ( ) { } ) ;
console. log ( typeof { } ) ;
console. log ( typeof [ 1 , 2 , 3 ] ) ;
console. log ( typeof null ) ;
instanceof
用于判断引用数据类型,检测构造函数的prototype属性是否出现在某个实例对象的原型链上,有则返回true,否则返回false,就是判断对象属于什么类型;
let arr = [ ] ;
console. log ( arr instanceof Array ) ;
console. log ( arr instanceof Object ) ;
let obj = { } ;
console. log ( obj instanceof Array ) ;
console. log ( obj instanceof Object ) ;
let date = new Date ( ) ;
console. log ( date instanceof Date ) ;
console. log ( date instanceof Object ) ;
console. log ( date instanceof Array ) ;
Object.prototype.toString.call()
返回一个“[object XXX]”格式的字符串,XXX就是具体的数据类型
function getType ( value ) {
if ( typeof value !== 'object' ) {
return typeof value;
} else {
return Object . prototype. toString . call ( value) . split ( ' ' ) [ 1 ] . slice ( 0 , - 1 ) ;
}
} ;
console. log ( getType ( ) ) ;
console. log ( getType ( null ) ) ;
console. log ( getType ( 123 ) ) ;
console. log ( getType ( '温情' ) ) ;
console. log ( getType ( { } ) ) ;
console. log ( getType ( [ ] ) ) ;
console. log ( getType ( new Date ) ) ;
console. log ( getType ( new RegExp ) ) ;
console. log ( getType ( new Function ) ) ;
push
向数组后面添加元素concat
数组连接、合并length
数组元素的长度join()
将数组元素连接起来构成一个字符串,括号里面代表用什么分割pop
移除数组的最后一个元素,返回值是被移除的元素shift
移除数组的第一个元素,返回值是被移除的元素unshift
向数组的开头添加一个或多个元素,返回值是加了之后新的长度sort
对数组的元素进行排序,并返回数组reverse
将数组中元素的位置颠倒,并返回该数组。slice(begib, end)
返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的(包括 begin,不包括end)。原始数组不会被改变。splice(start, deleteItem, items)
通过删除或替换现有元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。indexOf
返回在数组中可以找到一个给定元素的第一个索引(下标),如果不存在,则返回-1lastIndexOf(searchEle, fromIndex)
返回指定元素在数组中的最后一个的索引(下标),如果不存在则返回 -1。从数组的后面向前查找,第二个参数可选,如果有第二个参数从 fromIndex 处开始往前找。
DOM:文档对象模型,就是把 文档 当做一个对象,顶级对象是document
, dom主要是操作页面元素。 BOM: 浏览器对象模型,把 浏览器 当做一个对象,顶级对象是window
, bom主要是控制浏览器窗口交互的一些对象,除了window
还有history
,navigator
,location
37. typeof null的结果是什么,为什么?
结果是object,因为对象在底层是用二进制表示的,在js中二进制前三位都为0的话会被判定为object类型,null为空,二进制表示全为0,所以就被判定为object了
commonJs主要使用require()
和module.exports
来引入和导出各种值
es6模块主要是import
和export
来引入和导出各种值
commonJS模块输出的是一个值的拷贝,而ES6模块输出的是值的引用;
关于模块顶层的this指向问题,在commonJS顶层,this指向当前模块; 而在ES6模块中,this指向undefined
;
Object.prototype.toString.call(); 对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
function getType ( value ) {
if ( typeof value !== 'object' ) {
return typeof value;
} else {
return Object . prototype. toString . call ( value) . split ( ' ' ) [ 1 ] . slice ( 0 , - 1 ) ;
}
} ;
console. log ( getType ( ) ) ;
console. log ( getType ( null ) ) ;
console. log ( getType ( 123 ) ) ;
console. log ( getType ( '温情' ) ) ;
console. log ( getType ( { } ) ) ;
console. log ( getType ( [ ] ) ) ;
console. log ( getType ( new Date ) ) ;
console. log ( getType ( new RegExp ) ) ;
console. log ( getType ( new Function ) ) ;