返回顶部
首页 > 资讯 > 前端开发 > JavaScript >无constructor的class类还能new吗问题解析
  • 706
分享到

无constructor的class类还能new吗问题解析

constructor class类newclass类new 2023-03-07 14:03:50 706人浏览 独家记忆
摘要

目录前言class语法糖_createClass_classCallCheck_defineProperty_toPropertyKey_toPrimitive_typeof_def

前言

某一天晚上跟"混子瑶"聊天,下面模拟一下对话情景。

我:混子瑶,今天学了什么啊?

混子瑶:今天学习typescriptclass类高级类型啊!(然后发了一张截图...,图上有明显的两个类 )

 class Point { x: number; y: number };
 class Point2D ( x: number; y: number };
 const p: Point = new Point2D();

我:Point2D都没有constructor,它能被new吗?

混子瑶:可以啊,你看它又没报错:

image.png

我:这么神奇的嘛?

混子瑶: emmmm...

果真是这么神奇的嘛?来试一下不就知道咯!

class语法糖

classes6提供的一个语法糖,本质是一个函数,它具有constructorstatic默认方法... 咦?既然constructorclass类默认的,那岂不是显示,隐式都会默认去调用吗?文章的标题不就是一个子虚乌有的吗? 我们上babel来进行一下语法降级。

class A {
  x = 1;
  y = 2
}
const a = new A(10,20)
console.log(a); // {x: 1, y: 2}
class B {
  constructor(x, y){
    this.x = x;
    this.y = y;
  }
  x = 1;
  y = 2;
}
const b = new B(30,40)
console.log(b); // {x: 30, y: 40}
// 降级之后的代码
"use strict";
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
var A = _createClass(function A() {
  _classCallCheck(this, A);
  _defineProperty(this, "x", 1);
  _defineProperty(this, "y", 2);
});
var a = new A(10, 20);
console.log(a); // {x: 1, y: 2}
var B = _createClass(function B(x, y) {
  _classCallCheck(this, B);
  _defineProperty(this, "x", 1);
  _defineProperty(this, "y", 2);
  this.x = x;
  this.y = y;
});
var b = new B(30, 40);
console.log(b); // {x: 30, y: 40}

利用babel降级把ES6转化成了ES5代码,更能证明class只是一个语法糖,本质只是一个函数。那我们来研究一下这些函数吧!????

var B =  _createClass(function B(x, y) {
  _classCallCheck(this, B)
  _defineProperty(this, 'x', 1)
  _defineProperty(this, 'y', 2)
  this.x = x // 这里的this为new出来的 B{}
  this.y = y // 这里的this为new出来的 B{}
})
var b = new B(30, 40)
console.log(b) // {x: 30, y: 40}

_createClass

function _createClass(Constructor, protoProps, staticProps) {
  // 其中Constructor为f B(x,y),创造的一个ES5构造函数
  // protoProps :undefined 属性
  // staticProps: undefined 静态属性
  if (protoProps) _defineProperties(Constructor.prototype, protoProps)
  if (staticProps) _defineProperties(Constructor, staticProps)
  Object.defineProperty(Constructor, 'prototype', { writable: false })
  return Constructor // 返回f B(x,y)
}

_classCallCheck

function _classCallCheck(instance, Constructor) {
  // instance = B{} 由new创造出来
  // Constructor = f B(x, y)
  if (!(instance instanceof Constructor)) {
    throw new TypeError('Cannot call a class as a function')
  }
}

_defineProperty

function _defineProperty(obj, key, value) {
  // obj = B{}
  // key = "x"
  // value = 1
  key = _toPropertyKey(key) // 取到原始值key
  if (key in obj) { // 如果key是实例属性或者在原型链上,就做劫持
    Object.defineProperty(obj, key, {
      value: value,
      enumerable: true,
      configurable: true,
      writable: true
    })
  } else { // 不在的话,就添加key
    obj[key] = value
  }
  return obj // 返回实例对象
}

_toPropertyKey

function _toPropertyKey(arg) {
  // arg = "x"
  var key = _toPrimitive(arg, 'string') // "x"
  return _typeof(key) === 'symbol' ? key : String(key)
}

_toPrimitive

function _toPrimitive(input, hint) {
  // input = "x"
  // hint = "string"
  // 如果input是原始值,并且不等于null,则直接返回
  if (_typeof(input) !== 'object' || input === null) return input
  var prim = input[Symbol.toPrimitive] // 如果是对象,则需要拆箱得到原始值
  if (prim !== undefined) { // 如果是不等于undefined,则表示有原始值
    var res = prim.call(input, hint || 'default')
    if (_typeof(res) !== 'object') return res
    throw new TypeError('@@toPrimitive must return a primitive value.')
  }
  return (hint === 'string' ? String : Number)(input) // 如果是undefined则表示,没有取到原始值,需要继续拆箱调用Sting("x")取到原始值
}

_typeof

function _typeof(obj) {
  // obj = "x"
  '@babel/helpers - typeof' // babel提供的解析模块
  return (
    (_typeof =
      // 验证是否支持Symbol
      'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator
        ? function (obj) {
            return typeof obj // "string"
          } // 支持Symbol,则_typeof = fucntion(obj){return typeof obj}
        : function (obj) { // 不支持Symbol的话,则会判断当前的单一职责,保证一个实例的情况
            return obj && 
              'function' == typeof Symbol &&
              obj.constructor === Symbol &&
              obj !== Symbol.prototype
              ? 'symbol'
              : typeof obj // "string"
          }),
    _typeof(obj)
  )
}

_defineProperties

function _defineProperties(target, props) {
  // target = Constructor.prototype
  // props = props属性
  for (var i = 0; i < props.length; i++) {
    var descriptor = props[i] // 遍历属性
    descriptor.enumerable = descriptor.enumerable || false // 设置不可枚举 静态属性无法被实例化
    descriptor.configurable = true // 可扩展
    if ('value' in descriptor) descriptor.writable = true // 科协
    Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor)
  }
}

静态属性无法被实例化

image.png

关于class的继承

我们有如下代码

// class B
class B {
  static q = 1;
  m = 3;
  constructor(x, y){
    this.x = x;
    this.y = y;
  }
}
// class E
class E extends B {
    constructor(x,y){
      super(x,y)
      this.x = x;
      this.y  =y
    }
  m = 10;
  n = 20;
}
const e = new E(100,200)
const b = new B(30,40)
console.log(e);
console.log(b);

执行结果:

image.png

代码降级:

"use strict";
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
var B = _createClass(function B(x, y) {
  _classCallCheck(this, B);
  _defineProperty(this, "m", 3);
  this.x = x;
  this.y = y;
});
_defineProperty(B, "q", 1);
var b = new B(30, 40);
console.log(b);
var E = function (_B) {
  _inherits(E, _B); // _B为f B(x,y) E 为f E(x, y)
  var _super = _createSuper(E);
  function E(x, y) {
    var _this;
    _classCallCheck(this, E);
    _this = _super.call(this, x, y);
    _defineProperty(_assertThisInitialized(_this), "m", 10);
    _defineProperty(_assertThisInitialized(_this), "n", 20);
    _this.x = x;
    _this.y = y;
    return _this;
  }
  return _createClass(E);
}(B);
var e = new E(100, 200);
console.log(e);

在这里我们看到了super关键字被_inherits_createSuper代替,extends关键字也被函数替代,那么我们来研究一下这个代码。

_inherits

function _inherits(subClass, superClass) { // subClass为子类的构造函数,superClass为父类的构造函数
  if (typeof superClass !== 'function' && superClass !== null) {
    throw new TypeError('Super expression must either be null or a function')
  }
  // 创建子类的原型
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: { value: subClass, writable: true, configurable: true }
  })
  Object.defineProperty(subClass, 'prototype', { writable: false })
  // 绑定子类原型
  if (superClass) _setPrototypeOf(subClass, superClass)
}

_setPrototypeOf

function _setPrototypeOf(o, p) { // o为子类的构造函数,p为父类的构造函数
  _setPrototypeOf = Object.setPrototypeOf
    ? Object.setPrototypeOf.bind()
    : function _setPrototypeOf(o, p) {
        o.__proto__ = p
        return o
      }
  return _setPrototypeOf(o, p) // 绑定原型
}

_createSuper

function _createSuper(Derived) { // Derived = f E(x,y)
  // 校验能不能用Reflect
  var hasNativeReflectConstruct = _isNativeReflectConstruct()
  return function _createSuperInternal() {
    var Super = _getPrototypeOf(Derived), // 获得原型对象
      result // 创建实例结果
    if (hasNativeReflectConstruct) { // 如果能用Reflect,则调用Reflect.construct来创建实例对象
      var NewTarget = _getPrototypeOf(this).constructor
      result = Reflect.construct(Super, arguments, NewTarget)
    } else {
      result = Super.apply(this, arguments) // 不能则把父类当做普通函数执行,this改变为子类实例对象
    }
    return _possibleConstructorReturn(this, result)
  }
}

_isNativeReflectConstruct

function _isNativeReflectConstruct() {
  // 判断是否可用Reflect, 不可被new,因为没有construct
  if (typeof Reflect === 'undefined' || !Reflect.construct) return false
  if (Reflect.construct.sham) return false
  if (typeof Proxy === 'function') return true
  try {
    Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}))
    return true
  } catch (e) {
    return false
  }
}

_getPrototypeOf

// 获取原型对象
function _getPrototypeOf(o) {
  _getPrototypeOf = Object.setPrototypeOf
    ? Object.getPrototypeOf.bind()
    : function _getPrototypeOf(o) {
        return o.__proto__ || Object.getPrototypeOf(o)
      }
  return _getPrototypeOf(o)
}

_possibleConstructorReturn_assertThisInitialized则是检验子类constructor规则与实例存在与否。 之后便是走_createclass那一套逻辑,所以这就是class继承相关的东西,跟ES5中的组合寄生继承实现的很类似。

总结

经过这么一转换,一阅读,我们不仅仅知道了class类的一个本身的概念,而且还知道了他的一个实现原理,能够深入了解他的一个实例化的过程,当我们在被问到class类没有constructor还能被new吗?

以上就是无constructor的class类还能new吗问题解析的详细内容,更多关于无constructor class类new的资料请关注编程网其它相关文章!

--结束END--

本文标题: 无constructor的class类还能new吗问题解析

本文链接: https://lsjlt.com/news/198859.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 无constructor的class类还能new吗问题解析
    目录前言class语法糖_createClass_classCallCheck_defineProperty_toPropertyKey_toPrimitive_typeof_def...
    99+
    2023-03-07
    constructor class类new class类new
  • 无constructor的class类还能new吗
    本篇内容主要讲解“无constructor的class类还能new吗”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“无constructor的class类还能new吗”吧!前言某一天晚上跟&quo...
    99+
    2023-07-05
  • 解决@RequestBody使用不能class类型匹配的问题
    @RequestBody不能class类型匹配 在首次第一次尝试使用@RequestBody注解 开始加载字符串使用post提交(貌似只能post),加Json数据格式传输的时候, ...
    99+
    2024-04-02
  • 【漫画】CAS原理分析!无锁原子类也能解决并发问题!
    本文来源于微信公众号【胖滚猪学编程】、转载请注明出处 在漫画并发编程系统博文中,我们讲了N篇关于锁的知识,确实,锁是解决并发问题的万能钥匙,可是并发问题只有锁能解决吗?今天要出场一个大BOSS:CAS无锁算法,可谓是并发编程核...
    99+
    2017-11-07
    【漫画】CAS原理分析!无锁原子类也能解决并发问题!
  • 解决Yum Httpd无法解析PHP的问题
    解决Yum Httpd无法解析PHP的问题,需要具体代码示例 在搭建网站时,经常会遇到Yum安装的Httpd无法解析PHP的问题,导致无法正常访问网站页面。这个问题一直困扰着很多网站管...
    99+
    2024-04-02
  • 了解Golang常见问题的分析吗?
    Golang常见问题解析,你了解吗? 在当下的编程领域中,Golang(又称Go语言)作为一门快速、高效、强大的编程语言,越来越受到开发者们的关注和喜爱。但是即使是经验丰富的Golan...
    99+
    2024-02-26
    golang 解析 常见问题 go语言 并发访问 golang开发 同步机制
  • 关于@Component注解下的类无法@Autowired问题
    目录@Component注解下类无法@Autowired这个问题心累@Component注解下@Autowired报错下面是我的解决方案@Component注解下类无法@Autowi...
    99+
    2024-04-02
  • 如何解决CSS的active伪类无效的问题
    这篇文章主要介绍“如何解决CSS的active伪类无效的问题”,在日常操作中,相信很多人在如何解决CSS的active伪类无效的问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解...
    99+
    2024-04-02
  • java无法解析的编译问题怎么解决
    当Java编译器无法解析编译问题时,可以尝试以下几种方法来解决:1. 检查语法错误:首先检查代码中是否存在语法错误,如拼写错误、缺少...
    99+
    2023-08-28
    java
  • eclipse无法解析的编译问题怎么解决
    要解决Eclipse无法解析的编译问题,您可以尝试以下几个步骤:1. 清理项目:在Eclipse中,选择“Project”菜单,然后...
    99+
    2023-09-14
    eclipse
  • 分析讲解Java Random类里的种子问题
    可以说在现在的计算机语言里面,以及普通用户这里,都是没有办法获得真正的 随机数的。真正的随机数现在也只有在量子计算机当中才有获得。 所以我们现在所说的随机数,也可以称为伪随机数,伪随...
    99+
    2024-04-02
  • 解析 PostgreSQL TIMESTAMP 类型的值时出现问题
    今天编程网给大家带来了《解析 PostgreSQL TIMESTAMP 类型的值时出现问题》,其中涉及到的知识点包括等等,无论你是小白还是老手,都适合看一看哦~有好的建议也欢迎大家在评论留言,若是看...
    99+
    2024-04-05
  • 分析和解决IIS无法加载CSS的问题
    IIS 是一种常用的 Web 服务器软件,它能够处理和响应客户端的请求,并向客户端发送网页文件和其他静态资源。在 Web 开发中,CSS(层叠样式表)是一个非常重要的组成部分,它用于定义网页的样式、布局和外观。然而,有时候使用 IIS 时,...
    99+
    2023-05-14
  • 解决idea无法导入识别本地类的问题
    目录1背景2 解决方法1背景 今天做实验不知道按了哪里不能导入识别本地的类,只有jar包的类, 这是问题的还原,不是本来的项目。 经过各种百度和csdn都没有找到答案,无论是重启...
    99+
    2024-04-02
  • ubuntu无法解析亚马逊的DNS问题如何解决
    本篇内容介绍了“ubuntu无法解析亚马逊的DNS问题如何解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!ubuntu无法解析亚马逊的DN...
    99+
    2023-06-13
  • c++隐式类型转换存在的问题解析
    目录什么是隐式转换:为什么要进行隐式转换:隐式转换的原则:目标代码构造函数定义的隐式类型转换分析a1分析a2分析a3什么是隐式转换: c++中的基本类型并非完全对立,部分类型之间是可...
    99+
    2024-04-02
  • MySQL 实例无法启动的问题分析及解决
    前言 前几天,有位朋友微信联系我,告知一个生产数据库,在机器宕机恢复后,实例启动失败,而且该实例没有做任何的高可用、容灾、备份等,对业务影响非常大,希望能够协助排查一下,我也在第一时间就加入到排查中。 场景分析 ...
    99+
    2022-05-26
    MySQL 实例启动 MySQL 多实例
  • dataguard中MRP无法启动的问题分析和解决
    自己手头有一套dataguard环境,因为也有些日子没有用了,结果突然心血来潮准备启动起来学习一下,突然发现在敲了命令 recover managed standby database disconnect...
    99+
    2024-04-02
  • 解决Lombok使用@Builder无法build父类属性的问题
    目录Lombok使用@Builder无法build父类属性问题描述解决方案使用示例lombok @Builder注解和build父类属性问题1、简介2、使用3、@Builder注解对...
    99+
    2024-04-02
  • openwrt的dns无法解析内网地址的问题解决方案
    知乎上看到大佬的解决方案 最近买了电犀牛的R66S,想整个那个上网,下面挂个ap,给树莓派、香橙派的一些linux用,免得换源改地址什么的,然后网络环境是校园网,就遇到了这个问题,刚开始一直以为问题是来自于那个上网的插件,甚至还去官方git...
    99+
    2023-09-04
    linux 网络 服务器
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作