内存管理
基本数据类型在内存中的存放方式
复杂数据类型在内存中的存放方式
V8引擎有多大 64位有1.4G,32位700M,不同浏览器还有些许扩容 其中又分为
新生代:短时间存活的新变量会存在新生代中,新生代的内存量极小,64位下大概是32MB
老生代:生存时间比较长的变量,会转存到老生代,老生代占据了几乎所有内存。64位下大概是1400MB
新生代的回收算法:分为两个空间to,from,一开始都存放在from空间,死亡的变量依然放在from空间,把存活着的变量复制到to空间,from 空间清空,然后对调from和to。这样可以提升回收速度,空间换时间。
老生代的回收算法:标记已死变量,清除已死变量,整理磁盘(否则内存碎片太多,浪费空间)
新生代转换为老生代:这个对象经历过一次新生代的回收(即在 from 和 to空间内进行互换一次),并且新生代发现本次复制,会占用超过百分之25的to空间。
什么时候会触发回收:执行完一次代码或者内存不够时(这个情况比较极端)
变量什么时候会被回收:全局变量会直到程序执行完毕才会回收。普通变量,就是当他们失去引用
优化:
- 尽量不要定义全局,定义了及时手动释放。
- 注意闭包
Node端的一些特殊点:
- Node可以手动进行垃圾回收
- Node可以设置新老生代内存大小
为什么V8设置成1.4G:
- 对于浏览器脚本够用
- 回收的时候是阻塞式的,也就是进行垃圾回收的时候会中断代码的执行。如果不限制内存大小,垃圾回收时间变长。
高阶函数
一个函数接收另一个函数作为参数
手写forEach,map
forEach接受一个函数,这个函数参数有遍历的那一项,序号
Array.prototype.myForeach=function(callback){
var len = this.length//数组长度,this代表调用函数的数组
if(typeof callback !== 'function'){
throw new Error("Invalid callback")
}//健壮性
for (let i = 0; i < len; i++) {
callback.call(this,this[i],i)
}
}
与forEach不同map会返回一个新数组
Array.prototype.myMap = function (callback) {
var len = this.length;
var arr = [];//与forEach相比只需要返回一个新数组
if (typeof callback !== "function") {
throw new Error("Invalid callback");
}
for (let i = 0; i < len; i++) {
arr.push(callback.call(this, this[i], i));//注意这里是浅引用,要换成深拷贝
}
return arr
};
手写reduce
累计求和,求积,或者对象的转化 reduce(pre,now,index) :pre是上次循环的返回值,now是当前循环值,index是数组下标,后面,还有一个参数作为开始的默认值,如果不指定 默认数组第一项为默认值,函数直接从第二项开始.
//对象转化
var arr = [
{ path: "/", component: "login" },
{ path: "/sign", component: "sign" },
];
console.log(
arr.reduce((pre, now) => {
pre[now.path] = now.component;
return pre;
}, {})
);
Array.prototype.myReduce = function (callback, init) {
var i = 0;
var len = this.length;
var pre = init;
if (typeof callback !== "function") {
throw new Error("Invalid callback");
}
if (init == undefined) {
i = 1;
pre = this[0];
}
for (; i < len; i++) {
pre = callback.call(this, pre, this[i]);
}
return pre;
};
手写filter
var arr = [
{ path: "/", component: "login" },
{ path: "/sign", component: "sign" },
];
Array.prototype.myFilter = function (callback) {
var len = this.length;
var arr = [];
for (let i = 0; i < len; i++) {
if (callback.call(this, this[i], i)) {
arr.push(this[i]);//这里要深拷贝
}
}
return arr;
};
console.log(arr.myFilter((i) => i.path == "/sign"));
函数科里化
使用场景:函数在很多情况下调用参数固定
bind函数: 会创建一个新的函数,新函数使用指定的 this 值和参数调用原始函数,以该指定值作为新函数的 this 值返回一个新的函数