• 自己实现JavaScript的new


    new操作符是JavaScript中实例化对象时使用的操作符。自己动手实现一个new,能帮我们理解它背后的机理。

    前情提要

    本问题讨论基于如下类定义(人有名字,“说名字”在原型上):

    function Person(name) {
      this.name = name
    }
    Person.prototype.sayMyName = function () {
      console.log(this.name)
    }
    

    原理分析

    我们知道,对象是形如{k: v}的键值对的集合,其中v可为各种类型。

    如果用空对象x = {}调用构造函数,则构造函数做的this.name = name,就相当于x.name = name,即给x新增了name属性并赋值。这便是在”构造“(或者说构建、填充)这一对象的过程。

    x调用构造函数后,x确实有了name属性,但却不一定是Person——小猫小狗也可以有名字。因此,我们需要指定x原型为Person,相当于说明x是按Person的坯子制造出来的。

    在指定了原型后,自然而然的,x也可以调用原型链上的方法如sayMyName了。

    代码实现

    根据上面的分析,不难写出如下代码:

    function New(cons, ...args) { // cons为构造函数,...args为构造函数的参数
      let x = {}
      cons.apply(x, args) // 应用构造函数,填充属性
      x.__proto__ = cons.prototype // 修改原型。注意对象上的是__proto__,构造函数(类)上的是prototype
      // 注:形如__xxx__的属性显然是不希望被直接修改的属性,因此平时没有必要,就不要操作__proto__
      return x
    }
    

    进行测试:

    let p = New(Person, 'Bob')
    console.log(p) // { name: 'Bob', ... }
    console.log(p instanceof Person) // true
    

    一点小问题

    虽然很少这么做,但还是要提到:构造函数中可以中途返回值!

    如果这个值是基本类型,则单纯退出构造函数,不再执行下面的构造操作,也就是这个对象只构造到当前状态;如果这个值是引用数据类型,例如一个对象,则构造的结果就是这个对象,之前的所有构造操作都失去作用。

    因此,代码实现中可能出现应用x = cons.apply({}, args)的情况,可以考虑进行特别处理。

  • 相关阅读:
    spring的控制器如何传递数据到视图
    spring的控制器如何获取参数
    thymeleaf的官方网站
    如何编写spring mvc 项目
    如何创建spring web 工程(maven工程)
    如何下载spring sts
    使用请求包装器RequestWrapper 对博客内容进行编码
    使用apache-commons-lang3架构对HTML内容进行编码和反编码
    (转)Nginx+Php-fpm运行原理详解
    (转)FastCgi与PHP-fpm之间是个什么样的关系
  • 原文地址:https://www.cnblogs.com/zxuuu/p/12741655.html
Copyright © 2020-2023  润新知