1. new 关键字
例如:var a = new F();
其实际操作如下:
1. var a = {};
2. a.__proto__ = F.prototype;
3. F.prototype.call(a, [...param]);
2. 闭包
闭包是有权限访问父函数作用域中变量的函数,即在一个函数内部创建另外一个函数。
例如:function F() {
var i = 0;
return function() {
console.log(i ++);
}
}
var a = F(); a(); // 0 a(); // 1
var b = F(); b(); // 0 b(); // 1
为什么子函数可以访问父函数变量
1. JavaScript语言特有的"链式作用域"结构,子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
2. JavaScript的垃圾回收机制,并没有清除引用变量的内存。
垃圾回收机制
标记清除(mark and sweep):垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了,因为环境中的变量已经无法访问到这些变量了,然后垃圾回收器相会这些带有标记的变量机器所占空间。
大部分浏览器都是使用这种方式进行垃圾回收,区别在于如何标记及垃圾回收间隔而已,除了低版本IE。
引用计数(reference counting):引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加1,如果该变量的值变成了另外一个,则这个值得引用次数减1,当这个值的引用次数变为0的时候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为0的值占用的空间。
如果存在相互引用的情况下该策略就无法清除内存,照成内存泄漏,在低版本IE中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。
引用于:https://www.cnblogs.com/dolphinX/p/3348468.html
闭包所引起的常见问题
例如:var a = [];
function f() {
var b= [1, 2, 3];
for (var i = 0; i < b.length; i++) {
var item = b[i];
var _a = function() {
console.log(item);
}
a.push(_a);
}
}
f();
a[0](); // 3
a[1](); // 3
a[2](); // 3
造成这个结果的原因是,1. 闭包所引用的是变量是地址,而不是其值。2. 变量item被所有子函数共享,所以改变item的值其他子函数都会变化。
解决办法:(function(item) {
var _a = function() {
console.log(item);
}
a.push(_a);
})(item)
使用立即执行函数将item变量转变每个子函数的私有变量,从而互不干扰。