Appearance
深拷贝和浅拷贝
- 浅拷贝:把一个对象里面的所有的属性值和方法都复制给另一个对象
浅拷贝的方式:
Object.assign('要拷贝给谁','拷贝的是哪一个对象')
Array.prototype.slice()
扩展运算符 - 深拷贝:开辟一个新的栈,两个对象属性完全相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
深拷贝的方式:- JSON.parse(JSON.stringify('要拷贝的对象')) 有一个缺陷会忽略 undefined 和函数
- 递归循环 如果数据自己引用自己 拷贝会进入死循环 解决方法:使用 map 数据, map 的 key 可以是任意数据类型
- loadsh 的.cloneDeep()
- 使用扩展运算符 当拷贝对象的属性值对应的都是简单的基本类型数据,可以理解为深拷贝。当拷贝对象的属性对应的值为数组或对象等引用类型时,为浅拷贝。
闭包
- 什么是闭包:在内层函数访问它外层函数的作用域
- 内层函数访问外层函数的变量就会形成闭包
- 原理:利用作用域链的特性,先在当前作用域访问数据,如果访问不到,向父级访问,父级没有继续向上一层一层找,一直找到全局
- 作用:数据私有化,防止污染全局
- 缺点:可能会造成内存泄漏,解决方法:在退出函数之前,将不使用的局部变量全部删除
Promise
- 使异步操作更加容易,将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
- 三种状态:pending(等待,进行中) resolved(成功) rejected(失败)
- promise 的状态一旦由等待 pending 变为成功 resolved 或者失败 rejected。那么当前 promise 被标记为完成,后面则不会再次改变该状态。
localStorage、sessionStorage 和 cooKie 的区别
- localStorage 和 sessionStorage 存储大小 5MB,cookie 存储大小是 4kb
- locaStorage 数据得手动删除 sessionStorage 关闭页面或浏览器清除数据; cookie:如果在浏览器端生成 cookie 默认是关闭浏览器后失效
- localStorage 和 sessionStorage 只在浏览器中保存,不参与和服务器的通信; cookie:与服务器通信的时候每次都会携带在 HTTP 头中 如果使用 cookie 保存过多数据都会带来性能问题
垃圾回收
- 引用计数:计算当前内存被引用的次数,被引用一次计数+1.不被引用一次计数-1,当计数为 0,该内存释放回收
- 标记清除:通过根节点,标记所有从根节点开始的能够访问到的对象,未被标记得对象就是未被全局引用的垃圾对象,最终清除所有未被标记的对象
静态成员和实例成员
- 静态成员:类的属性
- 实例成员:实例对象的属性
作用域链
- 在某个函数作用域中,要使用一个变量的时候,会先看自己有没有,如果没有就向外面一层层找直到找到全局作用域,如果还没有就报错
如何检测一个数据是数组
- 变量 instanceof Array
- Array.isArray(变量)
- Object.prototype.toString.call(变量)
继承
- 原型链继承 (只能实现原型上方法的继承) Father.prototype.方法名 = function(){} Son.prototype = new Father() (引用类型值的原型属性会被所有的实例共享)
- 借用构造函数继承 (只能实现属性的继承) function Son(name) {Father.call(this,name)} 将 Father 类的 this 指向 Son
- 组合继承 = 原型链+借用构造函数 (原型链继承+借用构造函数继承,可以继承方法也可以继承属性,但是属性继承了两次)
- 寄生组合继承 Son.prototype = Object.create(Father.prototype)(解决了组合继承的缺陷)
- es6 的继承 extends
原型链的理解
- 访问实例的属性或方法的时候,会先看自己有没有,实例没有就通过__proto__找原型对象也就是对应的构造函数的 prototype,如果还没有就通过构造函数的 prototype.__proto__找 Object.prototype,如果还没有,最后就是 null 了
构造函数,实例和原型对象的三角关系
- 首先创建一个构造函数 构造函数通过 new 创建一个实例
- 将实例的__proto__指向了构造函数的 prototype
- 把构造函数的 this 指向这个实例 给这个实例添加属性和方法
- 此时实例就可以通过__proto__访问到构造函数的 prototype
new 的过程
- 在内存中创建一个空对象
- 将该空对象的__proto__指向了构造函数的 prototype
- 将 new 后面的构造函数的 this 指向 new 出来的空对象
- 把构造函数的属性和方法给这个对象
- 在构造函数内部返回实例化对象
this 的指向
- 全局 this 指向 window 严格模式指向 undefined
- 对象中的 this 指向这个对象
- 构造函数中 this 指向实例
- 事件绑定中 this 指向 DOM 元素 btn.onclick = cb 中 this 指向 btn
- 定时器中 this 指向 window
- 对象中的方法中定义的函数 this 指向 window
改变 this 指向
call() apply() bind()方法都可以改变 this 指向 区别
Call,apply 会立即调用,bind 不会立即调用,返回一个新的函数
apply 只有两个参数,第一个参数是调用者,第二个参数是函数的实参
使用场景
- call 可以用于借用构造函数继承的实现
- apply 可以用来求最大值
跨域
- 浏览器存在一个同源策略,必须域名、IP、端口三个全部一样才能同源,否则就是跨域,ajax 默认情况拿跨域的数据会报错,这个现象是浏览器的安全策略导致
解决跨域的问题的方案
- jsonp 原理利用 script 标签的 src 属性去请求数据 属于 Js 请求没有跨域这个问题,但是 src 只能去发起请求 所有 jsonP 只支持 get 请求, 服务器要返回给前端一个函数的调用,把数据放在实参里面,前端准备好一个全局函数,函数名字要和后台数据函数名一致(只支持 get 请求)
- cors(类似白名单) 后端人员再接口配置 cors
- 反向代理 开发的时候在 vue.config.js 中设置 proxy
什么是模块化
- 不把所有的 js 代码放在一个文件中,因为难以维护,变量命易起冲突,代码尽量一个功能一个 js 文件,一个文件最好要有一个自己的作用域,不会和别的文件起冲突,文件最终要合在一起,所以还有一个导入,这就是模块化
学过那些模块化的方案
ES6 的模块化规范
Export default export 导出
import 导入
数组的方法
- es3 (1) Join
(2) Sort
(3) Reverse
(4) Concat
(5) Push
(6) Pop
(7) Splice
(8) Shift
(9) Unshift
(10) slice - es5 (1) Map
(2) Filter
(3) Reduce 一堆数据加在一起
(4) Some
(5) Every - es6 (1) Find
(2) findIndex