利用es6 new.target来对模拟抽象类的方法

起源

最近在使用 Symbol 来做为唯一值,发现 Symbol 无法进行 new 操作,只能当作函数使用,只要进行了new 就会发生类型错误

new Symbol()

// error
Uncaught TypeError: Symbol is not a constructor
  at new Symbol (<anonymous>)
  at <anonymous>:1:1

在不考虑底层实现的情况下,在代码层面是否能够实现一个函数只可以进行调用而不可以进行 new 操作呢?思考之后如下写出:

function disConstructor() {
 if (this !== window) {
  throw new TypeError(' disConstructor is not a constructor')
 }
 console.log('gogo go')
}

// 测试结果如下
disConstructor() // gogo go

new disConstructor()

// error
Uncaught TypeError: disConstructor is not a constructor
  at new disConstructor (<anonymous>:3:15)
  at <anonymous>:1:1

如果使用 nodejs,window 可以切换为 global, 代码运行结果不变,因为对于个人而言没有适用场景。于是就没有继续研究下去,可是最近在从新翻阅 es6 时候发现 new.target这个属性。

new.target 属性

介绍(引用 mdn 文档)

new.target属性允许你检测函数或构造方法是否是通过new运算符被调用的。

在通过new运算符被初始化的函数或构造方法中,new.target返回一个指向构造方法或函数的引用。在普通的函数调用中,new.target 的值是undefined。

这样的话 我们的代码就可以这样改为

function disConstructor() {
 // 普通的函数调用中,new.target 的值是undefined。
 if (new.target) {
  throw new TypeError(' disConstructor is not a constructor')
 }
 console.log('gogo go')
}

得到与上述代码一样的答案。

深入

难道 es6 特地添加的功能仅仅只能用于检查一下我们的函数调用方式吗?

在查阅的过程各种发现了大多数都方案都是用 new.target 写出只能被继承的类。类似于实现java的抽象类。

class Animal {
 constructor(name, age) {
  if (new.target === Animal) {
   throw new Error('Animal class can`t instantiate');
  }
  this.name = name
  this.age = age
 }
 // 其他代码
 ...
}

class Dog extends Animal{
 constructor(name, age, sex) {
  super(name, age)
  this.sex = sex
 }
}

new Animal()
// error
Uncaught Error: Animal class can`t instantiate
  at new Animal (<anonymous>:4:13)
  at <anonymous>:1:1

new Dog('mimi', 12, '公')
// Dog {name: "mimi", age: 12, sex: "公"}

但是 java抽象类抽象方法需要重写,这个是没有方案的。于是在测试与使用的过程中,却意外发现了超类可以在构造期间访问派生类的原型,利用起来。

class Animal {
 constructor(name, age) {
  console.log(new.target.prototype)
 }
 // 其他代码
 ...
}

之前运行时调用需要重写的方法报错是这样写的。

class Animal {
 constructor(name, age) {
  this.name = name
  this.age = age
 }

 getName () {
  throw new Error('please overwrite getName method')
 }
}

class Dog extends Animal{
 constructor(name, age, sex) {
  super(name, age)
  this.sex = sex
 }
}

const pite = new Dog('pite', 2, '公')
a.getName()
// error
Uncaught Error: please overwrite getName method
  at Dog.getName (<anonymous>:8:11)
  at <anonymous>:1:3

然而此时利用 new.target ,我就可以利用 构造期间 对子类进行操作报错。

class Animal {
 constructor(name, age) {
  // 如果 target 不是 基类 且 没有 getName 报错
  if (new.target !== Animal && !new.target.prototype.hasOwnProperty('getName')) {
   throw new Error('please overwrite getName method')
  }
  this.name = name
  this.age = age
 }
}

class Dog extends Animal{
 constructor(name, age, sex) {
  super(name, age)
  this.sex = sex
 }
}

const pite = new Dog('pite', 2, '公')
// error
Uncaught Error: please overwrite getName method
  at new Animal (<anonymous>:5:13)
  at new Dog (<anonymous>:14:5)
  at <anonymous>:1:1

此时可以把运行方法时候发生的错误提前到构造时期,虽然都是在运行期,但是该错误触发机制要早危害要大。反而对代码是一种保护。

当然了,利用超类可以在构造期间访问派生类的原型作用远远不是那么简单,必然是很强大的,可以结合业务场景谈一谈理解和作用。

其他方案

  • 增加 编辑器插件
  • proxy
  • 修饰器

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • js es6系列教程 - 基于new.target属性与es5改造es6的类语法

    es5的构造函数前面如果不用new调用,this指向window,对象的属性就得不到值了,所以以前我们都要在构造函数中通过判断this是否使用了new关键字来确保普通的函数调用方式都能让对象复制到属性 function Person( uName ){ if ( this instanceof Person ) { this.userName = uName; }else { return new Person( uName ); } } Person.prototype.showUserNam

  • 利用es6 new.target来对模拟抽象类的方法

    起源 最近在使用 Symbol 来做为唯一值,发现 Symbol 无法进行 new 操作,只能当作函数使用,只要进行了new 就会发生类型错误 new Symbol() // error Uncaught TypeError: Symbol is not a constructor at new Symbol (<anonymous>) at <anonymous>:1:1 在不考虑底层实现的情况下,在代码层面是否能够实现一个函数只可以进行调用而不可以进行 new 操作呢?思考之后

  • 如何利用ES6进行Promise封装总结

    原生Promise解析 简介 promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和强大. promise简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果,从语法上来说,Promise是一个对象,从它可以获取异步操作的消息,Promise提供统一的API,各种异步操作都可以用同样的方法进行处理 特点 对象的状态不受外界影响,Promise对象代表一个异步操作,有三种状态:Pendding.fulfilled.rejected.只有异

  • 利用ES6的Promise.all实现至少请求多长时间的实例

    1.背景 我们都知道ajax请求可以加个timeout,就是最多请求多少时间,如果超过这个时间直接就报错. 这个是最多请求多长时间,我现在要做的是,最少要请求多长时间,然后才能执行后续的逻辑. 比如,一个ajax请求 x 毫秒就执行完毕了,但我要让他至少执行1秒钟,那我们会这么想: ajax完成后 , 1. 如果x<1s, 那我们先setTimeout => 1s - x ,然后执行后续操作. 2 如果x>=1s, 那我们直接执行后续操作. 想想这可繁琐了,我们还要在前面记录一下开始时间

  • 利用Python自动监控网站并发送邮件告警的方法

    前言 因为有一些网站需要每日检查是否有问题,所以需要一个报警监控的机制,这个需要你指定你发送的邮箱和你接收的邮箱,就可以做到对网站自动监控了. 这里用的是python3.5 需要安装的插件: 1.smtplib:发邮件需要用到 2.pycurl:访问网站时会需要用到 3.linecache:在读取txt网站清单时需要用到 具体思路: python程序从txt里面批量读取到网站的信息,通过Curl.py模拟浏览器去访问网站,并且把访问的结果写入到以自己的网站名称-日期.txt格式的文件中记录;有几

  • 利用vue.js实现被选中状态的改变方法

    在使用原型实现使不选中状态改变之后,接触到vue,就想着能不能使用vue再把功能实现一边,在上篇中的页面并没有动态实现页面,所有的数据也都是直接写在html中.而使用vue之后,已经能够实现页面根据数据的多少动态生成.而且代码量也大幅度减少. html部分的代码: <div data-role="page " class="page "> <div class="center " id="app"> &

  • js利用递归与promise 按顺序请求数据的方法

    问题:项目中有一个需求,一个tabBar下面如果没有内容就不让该tabBar显示,当然至于有没有内容,需要我们通过请求的来判断,但是由于请求是异步的,如何让请求按照tabBar的顺序进行? 方案:我们可以将promise变成下一个请求,可以利用递归来实现 实施: //定义初始数据 requestlist就像tabBar列表 let requestlist = [1, 2, 3, 4, 5, 6, 7,8,9]; //每个tabBar的返回数据使用reslist装起来 let reslist =

  • 利用FlubuCore用C#来写DevOps脚本的方法详解

    前言 随着近些年微服务的流行,有越来越多的开发者和团队所采纳和使用,它的确提供了很多的优势也解决了很多的问题,但是我们也知道也并不是银弹,提供优势的同时它也给我们的开发人员和团队也带来了很多的挑战. 为了迎接或者采用这些新技术,开发团队需要更加注重一些流程或工具的使用,这样才能更好的适应这些新技术所带来的一些问题. 对于流程行问题,敏捷的Scrum能够很好的提升产品开发团队之间的协作问题,那么对于应用变的越来越复杂这种情况,它最直接的问题就是带来了开发运维的复杂性,这个时候我们就需要使用工具来解

  • 利用For循环遍历Python字典的三种方法实例

    目录 前言 方法 1:使用 For 循环 + 索引进行迭代 方法 2:使用 .keys( ) + 索引进行迭代 方法 3:使用 .items( ) 进行迭代 进阶:遍历嵌套字典 总结 前言 在Python中,如何使用“for”循环遍历字典? 今天我们将会演示三种方法,并学会遍历嵌套字典. 在实战前,我们需要先创建一个模拟数据的字典. dict_1 = {'Name': 'Zara', 'Age': 7, 'Class': 'First','Address':'Beijing'} 方法 1:使用

  • 利用JS将图标字体渲染为图片的方法详解

    目录 前言 实现方式 html css js 效果 前言 在软件开发中肯定要用到图标,比如下图的 Groove 音乐中就用到了许多图标.一种获取这些图标的方法是把 Groove 音乐截个图,然后熟练地开启 Photoshop,开始抠图.这种方式很逊,效率也很低(虽然我刚开始就是这么干的). 如果打开 C:/Program File/WindowsApps(需要修改权限才能进入),可以发现几个名字里带 ZuneMusic 的文件夹,其中的某一个文件夹中会有字体文件 SegMVR2.ttf.这是一个

  • asp.net利用cookie保存用户密码实现自动登录的方法

    本文实例讲述了asp.net利用cookie保存用户密码实现自动登录的方法.分享给大家供大家参考.具体分析如下: 在asp.net中可以用cookie保存用户的帐户密码实现自动登录的功能,但是需要强调一下,cookie在客户端保存,是不安全的,推荐使用md5加密保存. 下面分析一下在asp.net中cookie的创建.提取与销毁的方法: 创建cookie 复制代码 代码如下: //向客户端写入Cookie HttpCookie hcUserName1 = new HttpCookie("unam

随机推荐