JavaScript

75 阅读2分钟

内存管理

基本数据类型在内存中的存放方式

image.png 复杂数据类型在内存中的存放方式

image.png

V8引擎有多大 64位有1.4G,32位700M,不同浏览器还有些许扩容 其中又分为

新生代:短时间存活的新变量会存在新生代中,新生代的内存量极小,64位下大概是32MB

老生代:生存时间比较长的变量,会转存到老生代,老生代占据了几乎所有内存。64位下大概是1400MB

新生代的回收算法:分为两个空间to,from,一开始都存放在from空间,死亡的变量依然放在from空间,把存活着的变量复制到to空间,from 空间清空,然后对调fromto。这样可以提升回收速度,空间换时间。

老生代的回收算法:标记已死变量,清除已死变量,整理磁盘(否则内存碎片太多,浪费空间)

新生代转换为老生代:这个对象经历过一次新生代的回收(即在 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 值返回一个新的函数