美文网首页让前端飞Web前端之路前端开发
JavaScript 之 九阳神功(第一式)

JavaScript 之 九阳神功(第一式)

作者: 1kesou | 来源:发表于2019-06-28 16:06 被阅读5次

    招式与内功并修,根本与潮流兼顾!!!

    扎实的内功

    通俗易懂的讲法就是最牛逼的讲法(不认同这个观点的其实就没必要往下看了, 哈哈哈。。。)

    1.变量类型与内存的关系

    • 基本数据类型: Sting Number Boolean null undefined Symbol

    基本数据类型保存在栈内存中 闭包中的基本数据类型变量不保存在栈内存中,而是保存在堆内存中。

    • 引用数据类型 Array,Function,Object.. 除了上文提到的基本数据类型以外,所有类型都是引用数据类型

    引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。 当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体

    为了更好的搞懂变量对象与堆内存,我们结合以下例子与图解进行理解。

        // 基本数据类型-栈内存
        let a1 = 0;
        // 基本数据类型-栈内存
        let a2 = 'this is string';
        // 基本数据类型-栈内存
        let a3 = null;
    
        // 对象的指针存放在栈内存中,指针指向的对象存放在堆内存中
        let b = { m: 20 };
        // 数组的指针存放在栈内存中,指针指向的数组存放在堆内存中
        let c = [1, 2, 3];
    
    
    image.png

    因此当我们要访问堆内存中的引用数据类型时,实际上我们首先是从变量中获取了该对象的地址指针, 然后再从堆内存中取得我们需要的数据。

    2.深拷贝和浅拷贝的区别是什么?实现一个深拷贝

    浅拷贝只拷贝一层,而深拷贝是层层拷贝。

    • 深拷贝

    深拷贝复制变量值,对于引用类型的变量,递归至基本类型后,再复制,复制后与源对象完全隔离互不影响。

    • 浅拷贝

    浅拷贝是将对象的每个属性进行复制,当对象的属性是引用类型时,实质复制的是其引用堆里面的指向路径,当引用指向的值发生变化时也会发生变化。

    • 实现

    1.深拷贝最简单的实现是JSON.parse(JSON.stringify(obj))

    缺点

    1.对象的属性值是函数时,无法拷贝。
    2.原型链上的属性无法拷贝
    3.会忽略 undefined
    4.不能正确的处理 Date 类型的数据
    5.不能处理 RegExp
    6.会忽略 symbol

    2.使用 deepClone方法递归实现

      //使用递归的方式实现数组、对象的深拷贝
      function deepClone(obj, hash = new WeakMap()) {
        if (obj instanceof RegExp) return new RegExp(obj)
        if (obj instanceof Date) return new Date(obj)
        if (obj === null || typeof obj !== 'object') {
          return obj
        }
        if (hash.has(obj)) {
          return hash.get(obj)
        }
        /**
         * 如果obj 是数组, 那么obj.constructor 是 [Function: Array]
         * 如果obj 是对象, 那么obj.constructor 是 [Function: Object]
         */
        let cloneObj = new obj.constructor();
        hash.set(obj, cloneObj);
        for (let key in obj) {
          console.log(key)
          //递归
          if (obj.hasOwnProperty(key)) {
            cloneObj[key] = deepClone(obj[key], hash)
          }
        }
        return cloneObj
      }
    

    3.如何正确判断this的指向?

    谁调用它,this 就指向谁。

    • 全局环境中的 this

    浏览器环境: this 都指向全局对象 window;

    node 环境:this 都是空对象 {};

    • 是否是 new 绑定

    构造函数返回值不是 function 或 object。new Super() 返回的是 this 对象。

    构造函数返回值是 function 或 object,new Super()是返回的是Super种返回的对象。

    • 箭头函数的情况

    箭头函数没有自己的this,继承外层上下文绑定的this。

    4.柯里化函数

    概念

    函数柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

    作用

    • 参数复用
    • 提前返回 – 返回接受余下的参数且返回结果的新函数
    • 延迟执行 – 返回新函数,等待执行

    应用场景

    重复调用一个函数参数很多重复的

      const curry = (fn, ...args) => args.length < fn.length
                                          ? (...arguments) => curry(fn, ...args, ...arguments) : fn(...args)
      
      function sumFn(a, b, c) {
        return a + b + c
      }
      var sum = curry(sumFn)
    
      console.log(sum(2, 3, 4)) // 10
      console.log(sum(2)(3)(4)) // 10
      console.log(sum(2, 3)(4)) // 10
    
    

    5.let为啥变量提升了以及let const var 区别

    一个变量或者方法是需要经过「创建」「初始化」「赋值」到使用的过程

    created (创建)
    initialized (初始化)
    assigned (赋值)

                                                |      
                  created x                     |            created fn
                  initialized x                 |            initialized fn      
                  var x = 1 <= assigned         |            assigned fn              
                                                |            funtion fn() {}
                  ______________________________|_____________________________________  
                                                |  
                  created x                     |             created x
                  let x = 1 <= initialized      |             const x = 1 <=initialized x 
                  x = 2                         |             x = 2 Error: no assign ment
                                                |  
    

    结论补充

    • let变量也会提升其实是创建过程被提升了,初始化过程没有被提升
    • var 的「创建」和「初始化」都被提升了
    • function 的「创建」「初始化」和「赋值」都被提升了

    最后看 const,其实 const 和 let 只有一个区别,那就是 const 只有「创建」和「初始化」,没有「赋值」过程。

    所谓暂时死区,就是不能在初始化之前,使用变量。

    • 区别
    1. let/const 定义的变量不会出现变量提升,而 var 定义的变量会提升。
    2. 相同作用域中,let 和 const 不允许重复声明,var 允许重复声明。
    3. const 声明变量时必须设置初始值
    4. const 声明一个只读的常量,这个常量不可改变。

    6.什么是闭包,什么是内存销毁

    请移步 通俗易懂的解释就是最牛逼的讲法

    欢迎关注公众号加群交流

    干货都给你

    相关文章

      网友评论

        本文标题:JavaScript 之 九阳神功(第一式)

        本文链接:https://www.haomeiwen.com/subject/hwbscctx.html