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) );