1.预编译执行过程
-
创建AO(activeation object)对象,执行期上下文。
-
寻找函数的形参和变量声明,将变量和形参名作为AO对象的属性名,值设定为undefined.
-
将形参和实参相统一,即更改形参后的undefined为具体的形参值。
-
寻找函数中的函数声明,将函数名作为AO属性名,值为函数体。
2.深浅拷贝
-
浅拷贝:仅仅是复制了引用,彼此之间的操作会互相影响
-
深拷贝:在堆中重新分配内存,不同的地址,相同的值,互不影响
-
深浅拷贝的主要区别就是:复制的是引用还是复制的是实例
实现浅拷贝的方法
let arr=[1,2,3] 1:let arr2=[...arrr] 2:let arr2=[].concat(arr)实现深拷贝的方法
let arr=[1,2,[3,4,[5,6]]] 1:let arr2=JSON.parse( JSON.stringify(arr))
3.原型和原型链
原型定义:每个函数都有一个prototype属性,这个属性指向一个对象,这个对象称之为原型;
每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性;
原型链定义:
- 1:Object.prototype为止,所有Object的原型,是一个对象的终极原型;
- 2:访问实例的一个属性,会先从实例内部查找,若没有,就到它的原型去查找,还没有,就继续向父一级原型查找,一直查找到Object.prototype位置,若有,就返回,没有在返回undefined
4:this指向场景
- 1.普通函数:this指向window,在严格模式下this是undefined
- 2:构造函数:this指向创建的实例对象
- 3:作为对象的方法:this指向调用者,谁调用,指向谁;
- 4:显示绑定this:通过call,apply,bind可以改变this指向
5.call,apply,bind的区别
相同:
三者的第一个参数都是this指向()
不同:call和apply传参方法不同,前者并排一个接着一个,而后者接受的是一个数组
bind会返回一个新函数,不会立即执行
6.作用域
定义:简单来说,作用域就是能够访问的变量区域范围
作用域分为:全局作用域,局部作用域(函数作用域),还有ES6新添的作用域
在函数内定义的变量,就是局部作用域,否者就是全局作用域,没有使用var关键字也是全局作用域
7.var,let和const的区别
-
var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。
-
let定义的变量,不可以重复声明,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。
-
const用来定义常量,不可以重复声明,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改
-
const定义的变量如果是基本数据类型,不可以改变,如果变量是对象(引用数据类型),不可以重新赋值,但是可以修改这个对象内部的值
-
new 关键字的作用
创建一个空对象
将构造函数的this指向创建的新对象
返回这个新对象
9.闭包
定义:就是能够访问其他函数内部的变量的函数,也就是说函数A返回函数B,函数B里保存函数A的变量,就会形成闭包
闭包的特性
-
函数嵌套函数
-
函数内的变量不会被垃圾回收机制清理
闭包的作用
- 实现私有数据
- 模拟块级作用域
- 实现js的模块划分
- 避免全局变量污染
注意点:过多的使用闭包,会造成内存泄漏,所以避免滥用闭包
内存泄漏:简单来说,就是会占满内存空间
10.async和defer的区别
defer与async的区别是:defer要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行;async一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。一句话,defer是“渲染完再执行”,async是“下载完就执行”。另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。