zoukankan      html  css  js  c++  java
  • JS基础知识点(二)

    == 与 ===

    对于 == 来说,如果对比双方的类型不一样的话,就会进行类型转换,就会进行如下判断流程:
    1.首先会判断两者类型是否相同,相同则会进行严格相等比较===

    2.判断是否在对比nullundefined,是的话就会返回true

    3.判断两者类型是否为stringnumber,是的话就会将字符串转换为number

    4.判断两者类型是否有boolean,有的话将boolean转换为number

    5.判断是否一方为object,另一方为stringnumbersymbol,是的话,将object转换为原始类型再进行判断

    ==类型判断流程图

    思考题:

    [] == ![], 为什么?

    根据上面判断流程, ![]false(上一节有涉及),然后进入4,转换为[] == 0,然后进入5,转换为'' == 0,进入3,转换为0 == 0,成立。
    更多对比,查看

    深浅拷贝

    浅拷贝

    1.使用Object.assign可以实现,它会拷贝所有的属性值到新的对象中,如果属性值是对象的话,拷贝的是地址。

    2.通过展开运算符...来实现浅拷贝

    深拷贝

    一般可以通过JSON.parse(JSON.stringify(object))来解决。

    let a = {
      age: 1,
      jobs: {
        first: 'FE'
      }
    }
    let b = JSON.parse(JSON.stringify(a))
    a.jobs.first = 'native'
    console.log(b.jobs.first) // FE
    

    但是该方法有局限性的:

    • 会忽略undefined
    • 会忽略symbol
    • 不能序列化函数
    • 不能解决循环引用的对象

    如果你所需拷贝的对象含有内置类型并且不包含函数,可以使用MessageChannel

    function structuralClone(obj) {
      return new Promise(resolve => {
        const { port1, port2 } = new MessageChannel()
        port2.onmessage = ev => resolve(ev.data)
        port1.postMessage(obj)
      })
    }
    
    var obj = {
      a: 1,
      b: {
        c: 2
      }
    }
    
    obj.b.d = obj.b
    
    // 注意该方法是异步的
    // 可以处理 undefined 和循环引用对象
    const test = async () => {
      const clone = await structuralClone(obj)
      console.log(clone)
    }
    test()
    

    也可以自己实现一个深拷贝,但是其实实现一个深拷贝是很困难的,需要我们考虑好多种边界情况,比如原型链如何处理、DOM 如何处理等等,下面实现的深拷贝只是简易版,更推荐使用lodash深拷贝

    function deepClone(obj) {
      function isObject(o) {
        return (typeof o === 'object' || typeof o === 'function') && o !== null
      }
    
      if (!isObject(obj)) {
        throw new Error('非对象')
      }
    
      let isArray = Array.isArray(obj)
      let newObj = isArray ? [...obj] : { ...obj }
      Reflect.ownKeys(newObj).forEach(key => {
        newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
      })
    
      return newObj
    }
    
    let obj = {
      a: [1, 2, 3],
      b: {
        c: 2,
        d: 3
      }
    }
    let newObj = deepClone(obj)
    newObj.b.c = 1
    console.log(obj.b.c) // 2
    

    原型

    函数对象都有prototype, 任何一个对象都有原型,我们可以通过非标准属性__proto__来访问一个对象的原型

    // 纯对象的原型默认是个空对象
    console.log({}.__proto__); // => {}
    
    function Student(name, grade) {
      this.name = name;
      this.grade = grade;
    }
    
    const stu = new Student('xiaoMing', 6);
    // Student 类型实例的原型,默认也是一个空对象
    console.log(stu.__proto__); // => Student {}
    

    理解几个名词:

    • constructor: 构造器,我们也可以称之为类,我们可以通过new构造器来构造一个实例。

    • __proto__: 一个访问器属性,非标准,暴露了通过它访问的对象的内部[[Prototype]](一个对象或null),不过更推荐使用ES6新增的Reflect.getPrototypeOf或者Object.getPrototypeOf()方法。

    • prototype: 原型对象,每个函数对象都有prototype

    它们之间的关系如下图

    原型与实例之间的关系

    原型链

    当在一个对象obj上访问某个属性时,如果不存在于obj,那么便会去对象的原型也就是obj.__proto__上去找这个属性。如果有则返回这个属性,没有则去对象obj的原型的原型也就是obj.__proto__.__proto__去找,重复以上步骤。一直到访问纯对象的原型也就是Object.prototype,没有的话续往上找也就是Object.prototype.__proto__,其实就是null,直接返回undefined

    举个例子

    function Student(name, grade) {
      this.name = name;
      this.grade = grade;
    }
    
    const stu = new Student();
    console.log(stu.notExists); // => undefined
    

    访问stu.notExists的整个过程是:

    1.先看stu上是否存在notExists,不存在,所以看stu.__proto__

    stu.__proto__ === Student.prototype // => true
    

    2.stu.__proto__上也不存在notExists属性,再看stu.__proto__.__proto__,其实就是纯对象的原型:Object.prototype

    console.log(stu.__proto__.__proto__ === {}.__proto__); // => true
    

    3.纯对象的原型上也不存在notExists属性,再往上,到stu.__proto__.__proto__.__proto__上去找,其实就是null

    console.log(new Object().__proto__.__proto__); // => null
    

    4.null不存在notExists属性,返回undefined

    各个原型之间构成的链,我们称之为原型链。

    stu的原型链

    函数Student的原型链:

    Student的原型链

    思考题

    function Page() {
      return this.hosts;
    }
    Page.hosts = ['h1'];
    Page.prototype.hosts = ['h2'];
    
    const p1 = new Page();
    const p2 = Page();
    
    console.log(p1.hosts);
    console.log(p2.hosts);
    

    运行结果是:先输出undefiend,然后报错TypeError: Cannot read property 'hosts' of undefined

    为什么console.log(p1.hosts)是输出undefiend呢,因为new的时候如果return了对象,会直接拿这个对象作为new的结果,因此,p1应该是this.hosts的结果,
    而在new Page()的时候,this是一个以Page.prototype为原型的target对象,所以这里this.hosts可以访问到Page.prototype.hosts也就是['h2']
    这样 p1 就是等于['h2']['h2']没有hosts属性所以返回undefined

    为什么console.log(p2.hosts)会报错呢,p2是直接调用Page构造函数的结果,直接调用page函数,这个时候this指向全局对象,全局对象并没hosts属性,因此返回undefined,往undefined上访问hosts当然报错。

  • 相关阅读:
    极大似然估计理解与应用
    逻辑回归理解及代码实现
    《剑指offer》---数值的整数次方
    线性回归理解及代码实现
    二叉搜索树(BST)---python实现
    《剑指offer》---顺时针打印矩阵
    《剑指offer》---二进制中1的个数
    《剑指offer》---输出链表倒数第k个结点
    版本控制-Git服务器搭建和常用命令使用
    hbase伪分布式平台搭建(centos 6.3)
  • 原文地址:https://www.cnblogs.com/wangxi01/p/12754976.html
Copyright © 2011-2022 走看看