讲一下 var、let、const 的区别?
- var 声明的变量有变量提升的特性,而 let、const 没有
- var 声明的变量会挂载到 windows 对象上,所以使用 var 声明的是全局变量,而 let 和 const 声明的变量是局部变量, 块级作用域外不能访问
- 同一作用域下 let 和 const 不能重复声明同名变量,而var可以
- const 声明的是常量,必须赋初值,一旦声明不能再次赋值修改,如果声明的是复合类型数据,可以修改其属性
js
中的基础数据类型有哪几种
- 基本数据类型(值类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined),
- 引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function)。
- 特殊的对象:正则(RegExp)和日期(Date)
- 特殊类型:underfined 未定义、Null 空对象、Infinate 无穷、NAN 非数字
基本数据类型的值直接在栈内存中存储,值与值之间独立存在,修改一个变量不会影响到其他变量。
对象是保存在堆内存中的,每创建一个新对象,就会在堆内存中开辟出一个新空间,而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用,当其中一个通过变量修改属性时,另一个也会受到影响
js
数据类型的检测方式有哪些?
typeof
常用于判断基本数据类型,因为对象、数组和Null都返回的Objectinstanceof
用于判断引用数据类型,检测构造函数的prototype属性是否出现在某个实例对象的原型链上,有则返回true,否则返回false,就是判断对象属于什么类型Object.prototype.toString.call()
返回一个“[object XXX]”格式的字符串,XXX就是具体的数据类型
this指向的6种指向
- 普通函数直接调用中的this: 普通函数中的 this 指向 window 对象, 严格模式下为 undefiend
- 在对象里调用的this: 指向调用函数的那个对象,this: 谁调用就指向谁
- 在构造函数以及类中的this: 构造函数和类需要配合 new 使用, 而 new 关键字会将构造函数中的 this 指向实例对 象,所以 this 指向 实例对象
- 绑定事件函数的this: 谁调用就指向谁
- 定时器中的this: 定时器中的 this 指向 window,因为定时器中采用回调函数作为处理函数,而回调函数的 this 指向 window
- 箭头函数中的this: 箭头函数没有自己的 this,会继承其父作用域的 this。
call apply bind 的作用与区别?
- 相同点:call 和 apply 和 bind 都可以改变this指向,都可以传参
- 不同点call apply自动调用,bind需要再调一次,bind的返回的是对应函数
- call apply 如果第一个参数指定了 null 或者 undefined 则内部 this 指向 window
闭包?
- 闭包是指能够访问另一个函数作用域中的变量的一个函数。 在
js
中,只有函数内部的子函数才能访问局部变量, 所以闭包可以理解成 “定义在一个函数内部的函数” - 闭包的作用: 利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部,让外部函数可以访问到内部函数的变量和方法
- 闭包的优点: 正常的函数,在执行完之后,函数里面声明的变量会被垃圾回收机制处理掉。但是形成闭包的函数在执行之后,不会被回收,依旧存在内存中
- 闭包的缺点: 因为变量不会被回收,所以内存中一直存在,耗费内存。
- 防抖和节流、封装私有变量、for循环中的保留i的操作、函数柯里化
js
执行机制
js
是单线程:
JavaScript语言单线程,也就是说,同一个时间只能做一件事情。,由于JavaScript需要用户与页面交互,操作dom,所以只能是单线程的,而单线程就意味着所有任务需要排队,前一个任务结束才会执行后一个任务,这样所导致的问题是如果js
执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉
同步和异步:
程序里面所有的任务,可以分成两类:同步任务(synchronous)和异步任务(asynchronous)。
为了利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制,且不得操作 DOM。本质是js
还是单线程的
同步:前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。
异步:异步任务是那些被引擎放在一边,不进入主线程、而进入任务队列的任务。只有引擎认为某个异步任务可以执行了(比如 Ajax 操作从服务器得到了结果),该任务(采用回调函数的形式)才会进入主线程执行。排在异步任务后面的代码,不用等待异步任务结束会马上运行,也就是说,异步任务不具有“堵塞”效应.
它们的本质区别是:这条流水线上各个流程的执行顺序不同。
js
执行机制:
1、先执行执行栈中的同步任务。
2、异步任务(回调函数)放入任务队列中。
3、一旦执行栈中的所有同步任务执行完毕,系统会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
事件循环(Event Loop)
当js
解析执行时,会被引擎分为两类任务,同步任务(synchronous) 和 异步任务(asynchronous)。
- 对于同步任务来说,会被推到执行栈按顺序去执行这些任务。
- 对于异步任务来说,当其可以被执行时,会被放到一个任务队列(task queue)里等待
js
引擎去执行。
当执行栈中的所有同步任务完成后,js
引擎才会去任务队列里查看是否有任务存在,并将任务放到执行栈中去执行,执行完了又会去任务队列里查看是否有已经可以执行的任务。这种循环检查的机制,就叫做事件循环(Event Loop)
宏任务和微任务
对于任务队列,其实是有更细的分类。其被分为 微任务(microtask)队列 == & == 宏任务(macrotask)队列
- 微任务: Promise的then、Mutation Observer、process.nextTick()等,会被放在微任务(microtask)队列。
- 宏任务: setTimeout、setInterval、ajax等,会被放在宏任务(macrotask)队列。
对内存泄漏的了解
- 定义:程序中已在堆中分配的内存,因为某种原因未释放或者无法释放的问题
- 简单理解: 无用的内存还在占用,得不到释放和归还,比较严重的时候,无用的内存还会增加,从而导致整个系统卡顿,甚至崩溃。
new 操作符具体干了什么?
- 创建一个空对象,并且把 this 指向这个对象,同时还继承了该对象的原型
- 属性和方法被加入到 this 引用的对象中
箭头函数与普通函数区别
- 箭头函数没有属于自己的this,箭头函数没有自己的 this,会继承其父作用域的 this。)(严格模式this是undefined)
- 不可以使用new命令(没有this),否则会抛出一个错误
- 没有自己的this.不能调用call和apply,没有prototype,new关键字内部需要把新对象的_proto_指向函数的prototype
- 不能使用arguments对象
JavaScript 原型,原型链 ? 有什么特点?
原型
- 原型分为隐式原型(proto) 和 显式原型(prototype),每个对象都有它的隐式原型(proto),指向它对应构造函数的显式原型(prototype)
- 无论何时,只要创建一个函数,就会为这个函数添加一个 prototype 属性,这个属性就指向原型对象,原型对象有一个 constructor 属性指回构造函数,每个构造函数生成的实例对象都有一个 proto 属性,这个属性也指向原型对象
原型链
- 每个对象都有 proto 属性,这个属性指向原型对象,当想访问对象的一个属性时,如果这个对象本身没有这个属性就会通过 __proto__属性 查找,原型对象也是对象,每个对象又有自己的 proto 属性,所以就会一直这样查找上去,直到找到这个属性,这就是原型链的概念。
- 原型链就是对象沿着 proto 这条链逐步向上搜索,最顶层是 Object,Object 的 proto 是 null。
事件代理(事件委托)
- 是
js
中常用绑定事件的常技巧。“事件代理”是把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是 DOM 元素的事件冒泡。使用事件委托的好处是可以提高性能。 - 可以大量节省内存占用,减少事件注册,当新增子对象时无需再次对其绑定。
什么是作用域,什么是作用域链(待修改)
作用域
- 规定变量和函数的可使用范围称为作用域
作用域链
- 查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作用域链。
浅拷贝 和 深拷贝的理解
浅拷贝:
- 如果拷贝的是基本数据类型相当于直接拷贝它的值,修改值互不影响
- 如果拷贝的是引用数据类型,拷贝的就是指向堆内存里面这个对象的内存地址,如果修改了其中一个对象的数据,那么另一个对象也会受到影响,因为内存地址指向堆里面同一块内存
- 常用 es6 0bject.assign() 实现
深拷贝:
- 深拷贝是将一个对象完整的独立拷贝一份出来,然后在堆内存中开辟一块新的内存块存储,所以不会互相影响
- 常用
es6扩展运算符
递归
Array.concat()
实现
防抖和节流的作用
防抖
- 在事件触发几秒后再去执行回调,如果在这几秒中再次触发,则重新及时 (输入框)
节流
-
规定在一定的时间内只执行一次,如果在规定的时间内多次触发,只有一次生效 (按钮)
两者的目的都是为了防止由于触发频率过高导致相应速度跟不上
js
数组操作
js
数组乱序去重
- sort()
js
数组去重的方法
- 利用 es6 Set 去重
- sort()
- includes()
- for+indexof
- forEach+indexof
js
数组排序的方法
- sort()
- 冒泡排序
- 快速排序
js
数组合并的方法
- arr1.concat
- […arr1, …arr2,······]
- push(…arr)
- arr1.push.apply(arr1, arr2)
- arr1.push.call(arr1, …arr2)
js
对象合并的方法
- Object.assign()
Object.assign()
实行的是浅拷贝,也就是说如果源对象的属性是一个对象,那么目标对象得到的是这个对象的引
说说es6的新增特性
- let、const: 声明变量和常量
- 模板字符串:增强版的字符串,用反引号标识,嵌入变量只需要放在${}中
- 箭头函数:ES6中函数定义不再使用关键字function(),而是利用了()=>来进行定义
- 解构赋值:按照类型的不同有不同的方式提取值,赋值
- Symbol:新增的基本数据类型,特点就是里面的值唯一
- Set 和 Map 数据结构
- 展开运算符(…): 可以将数组或对象里面的值展开, 还可以将 Set 数据结构转换为数组
- for…of 循环: 可以遍历数组对象以及 Set 和 Map 数据结构
- class 类:通过 extends 实现继承
- promise、(async/await): 都是用来解决异步编程的方案
- proxy:代理对象,直接监听对象的变化,然后触发相应的逻辑
Promise
- Promise 是 es6 引入解决异步编程问题的解决方案
- Promise 有三种状态:pending(进行中)、resolve(已完成)、reject(已失败)
- 当 Promise 的状态由 pending 转变为 resolved 或 reject 时,会执行相应的回调, 一旦从 pending 状态变成为其他状态就不能再更改状态了
- 可以链式调用,解决回调地狱的问题
Promise.all() 和 Promise.race()
Promise.all()
的作用是接收一组异步任务,然后并行执行任务,等所有任务执行完之后再执行回调Promise.all()
传入一组 Promise 数组,只有当所有的 Promise 状态都成功才返回成功,只要有一个失败就返回失败的 Promise 状态- `Promise.all( 的作用是接收一组异步任务,然后并行执行任务,等所有任务执行完之后再执行回调
Promise.all()
传入一组 Promise 数组,只有当所有的 Promise 状态都成功才返回成功,只要有一个失败就返回失败的 Promise 状态
什么是什么是async/await?
- async/await是写异步代码的新方式,以前的方法有回调函数和promise
- async/await是基于promose实现的,他不能用于普通的函数
- async/await与promise一样,是非阻塞的
- async/await使得异步代码看起来像同步代码
for-in 和 for-of 的区别
- 两者都可以用于遍历数组,只不过
for-in
遍历的是数组元素的索引 (index), 而for-of
遍历的是数组元素的值 for-in
可以遍历普通对象,获取的是对象的键名。for-of
不可以遍历普通对象for-in
不可以遍历Set/Mapfor-of
可以遍历Set/Map
for和foreach谁更快,为什么?
- forEach每次都要创建一个函数来调用,而for不会创建函数,
- 函数需要独立的作用域,会有额外的开销
- 越“低级”的代码,性能往往越好
- 日常开发别只考虑性能,forEach代码可读性更好
什么是 DOM 和 BOM?
- DOM:文档对象模型,就是把 文档 当做一个对象,顶级对象是document, dom主要是操作页面元素。
- BOM: 浏览器对象模型,把 浏览器 当做一个对象,顶级对象是window, bom主要是控制浏览器窗口交互的一些对象,除了window还有history,navigator,location
如何判断一个对象是否属于某个类型?
- Object.prototype.toString.call();
面向对象
什么是面向对象
- 面向对象不是新的东西,它只是过程式代码的一种高度封装,目的在于提高代码的开发效率和可维护性。
- 面向对象编程 —— Object Oriented Programming ,简称 OOP ,是一种编程开发思想。
- 面向对象编程具有灵活、代码可复用、高度模块化等特点,容易维护和开发,比起由一系列函数或指令组成的传统的 过程式编程(procedural programming),更适合多人合作的大型软件项目。
- 简而言之: 简而言之就是程序之中所有的操作都需要通过对象来完成
面向对象与面向过程
- 面向过程就是亲力亲为,事无巨细,面面俱到,步步紧跟,有条不紊
- 面向对象就是找一个对象,指挥得结果
- 面向对象将执行者转变成指挥者
- 面向对象不是面向过程的替代,而是面向过程的封装
面向对象的特性
封装性 继承性 [多态性 ]
js
如何实现异步编程
-
回调函数(callback)
优点:解决了同步的问题(只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。)
缺点:回调地狱,每个任务只能指定一个回调函数,不能 return. -
事件监听
这种思路是说异步任务的执行不取决于代码的顺序,而取决于某个事件是否发生。比如一个我们注册一个按钮的点 击事件或者注册一个自定义事件,然后通过点击或者trigger的方式触发这个事件。
-
Promise
-
Generator
-
生成器 async/await,是ES7提供的一种解决方案。
跨域解决办法
背景:
-
跨域是是因为浏览器的同源策略限制,是浏览器的一种安全机制,服务端之间是不存在跨域的。
-
所谓同源指的是两个页面具有相同的协议、主机和端口,三者有任一不相同即会产生跨域
解决办法
-
cors解决:只需要后端去配置响应头,就可以解决跨域(不安全)
Access-Control-Allow-Origin//允许跨域的域名
Access-Control-Allow-Headers//允许的header类型
Access-Control-Allow-Methods//跨域允许的请求方式 -
js
op解决:借助 script 标签的 src 属性,跳过同源策略,这种解决办法具有局限性,需要前后端配合解决,只能解决get请求 -
(在vue.config.
js
文件中)中 配置webpack-dev-server 其实就是借助webpack配置的服务器去访问后端,这样就只存在服务器之间的访问而服务器之间的访问又用的是http协议,这样就可以解决跨域
变量提升
我们js
引擎在运行js
的时候,分为两步,第一步是预解析,一步是代码执行,预解析分为变量预解析(变量提升)与函数预解析(函数提升)。函数提升优先级高于变量提升
- 变量提升就是把所有的变量声明提升到当前作用域的最前边,变量赋值不会提升。
- 函数提升是函数的声明会被提升到当前作用域的最前上边,但是不会调用函数
模块化
什么是模块
- 将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起
- 块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信
模块化的好处
- 避免命名冲突(减少命名空间污染)
- 更好的分离, 按需加载
- 更高复用性
- 高可维护性
实现模块化的方式
- Common
js
模块 - AMD
- CMD
- ES6 模块
js
常见的设计模式
- 单例模式
- 工厂模式
- 构造函数模式
- 发布订阅者模式
- 迭代器模式
- 代理模式
响应方式有哪几种
- 鼠标单击事件( onclick )
- 鼠标经过事件( onmouseover )
- 鼠标移开事件( onmouseout )
- 光标聚焦事件( onfocus )
- 失焦事件( onblur )
- 内容选中事件( onselect )
- 文本框内容改变事件( onchange )
- 加载事件( onload )
- 卸载事件( onunload )
数组扁平化
-
递归
-
toString
-
es6 展开运算符
let arr = [1, [2, [3, 4]]]; function flattern(arr) { let result = []; for(let i = 0; i < arr.length; i++) { if(Array.isArray(arr[i])) { flattern(arr[i]) } else { result.push(arr[i]) } } return result; } //递归
function flatten(arr) { return arr.reduce(function(prev, next){ return prev.concat(Array.isArray(next) ? flatten(next) : next) }, []) }//toString
function flatten(arr) { while (arr.some(item => Array.isArray(item))) { arr = [].concat(...arr); } //ES6新方法 return arr; }
js
的垃圾回收机制
js
的垃圾回收机制是为了以防内存泄漏,内存泄漏的含义就是当已经不需要某块内存时这块内存还存在着,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存
媒体查询
- 媒体查询是自 CSS3开始加入的一个功能。它可以进行响应式适配展示。
- 响应式适配 根据不同的屏幕尺寸, 显示不同的效果 (设置盒子的样式)
媒体查询由两部分组成:
- 一个可选的媒体类型(如 screen、print 等)
- 零个或多个媒体功能限定表达式(如 max-width: 500px、orientation: landscape 等)
对内存泄露的理解
- 定义:程序中已在堆中分配的内存,因为某种原因未释放或者无法释放的问题
- 简单理解: 无用的内存还在占用,得不到释放和归还,比较严重的时候,无用的内存还会增加,从而导致整个系统卡顿,甚至崩溃。
可能出现内存泄漏的原因
- 意外的全局变量
- DOM元素清空时,还存在引用
- 闭包
- 遗忘的定时器