zoukankan      html  css  js  c++  java
  • 自己实现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)的情况,可以考虑进行特别处理。

  • 相关阅读:
    Android高斯模糊技术,实现毛玻璃效果(转)
    设计模式笔记之六:生产消费者模式
    设计模式笔记之五:观察者模式
    设计模式笔记之四:MVP+Retrofit+RxJava组合使用
    设计模式笔记之三:Android DataBinding库(MVVM设计模式)
    Eclipse Code Recommenders 自动补全(联想)神器
    java根据freeMark模板生成内容
    通过java反射机制,获取对象的属性和值(包括所有继承的父类)
    win7下自动更新svn目录
    jdk11 eclipse下开启ZGC
  • 原文地址:https://www.cnblogs.com/zxuuu/p/12741655.html
Copyright © 2011-2022 走看看