作用域、闭包、GC垃圾回收、js运行机制
作用域([[scope]]
):函数创建/声明的时候,就会形成一个函数的作用域。
var f = function(){}
//f[[scope]]
作用域链(scopeChain
):函数执行的时候形成的,执行上下文确定的时候就形成了。
执行上下文(EC
):函数执行的时候所依赖的环境。
执行环境栈(EStack
)
GO:全局对象、VO:变量对象、AO:活动对象
GC垃圾回收:变量和函数不再被使用后(引用次数为0),会被js垃圾回收机制回收,全局环境下的变量不会被回收。
内存泄漏:该销毁的不能销毁
GC垃圾回收机制:该销毁的销毁
闭包:
一个函数和他周围状态(词法环境)的引用捆绑在一起的组合叫做闭包。也可以说是函数或者作用域的嵌套,闭包可以让你在内部函数中访问其外部函数的作用域。
闭包的作用:
-
保存:eg:for循环保存每次循环的i
-
保护:eg:计数器内部变量count不受污染
闭包的优缺点:
- 优点:可以避免使用全局变量造成变量污染,局部变量可以常驻内存中。
- 缺点:可能会造成内存泄露
一道闭包的面试题:
var a = 0,
b = 0;
function A(a) {
A = function (b) {
alert(a + b++)
};
alert(a++);
}
A(1); //输出?
A(2); //输出?
//执行了A(1)之后重写了A
//作用域是在创建的时候形成的而非运行的时候
A(1); //1
A(2); //4
js运行机制
通过一个简单的闭包来看懂js运行机制、作用域和作用域链:
let x= 1;
let A = function(y){
let x = 2;
let B = function B(z){
console.log(x+y+z)
}
return B;
};
let C = A(2);
C(3); //输出?
C(3); //7
进栈顺序:EC(G) – EC(A) – EC(B)
原型、原型链、new
原型: 函数的原型通过 prototype
获取,对象的原型通过 __proto__
获得
原型链:基本每个对象都有__proto__
属性,查找属性时,沿着对象的__proto__
向上查找的关系就叫原型链,hasOwnProperty
可以用来判断某个属性是否存在对象自身(实例)中,而非原型链中。isPrototypeOf
用来判断某个属性是否存在对象的原型原型链中。
创建无原型对象的两种方式:object.create(null)
和 setPrototypeOf({},null)
new操作符的实现机制:
- 创建一个新的空对象
- 把新对象的原型绑定到构造函数的原型上
- 构造函数执行,this绑定到新的对象
- 返回新对象
代码实现:
function newOperator(constructor, arguments) {
const obj = {}
Object.setPrototypeOf(obj, constructor.prototype)
constructor.call(obj, arguments)
return obj
}
function Person(name) {
this.name = name
}
const personQ = newOperator(Person, 'QQ')
console.log(personQ)