JavaScript进阶(二十九): 走近 es6 之 new.target

文章目录

一、前言

源码阅读过程中,发现以下语句

javascript 复制代码
new.target.prototype

鉴于该语法为es6所有,项目在编译过程中,控制台报Unexpected token: punc(.)错误。按照常规处理,应用babel-loader即可解决此类问题。在.babelrc

javascript 复制代码
{
	"presets": [
		["es2015"]
	]
}

经过实践发现,build阶段依旧报错。

故采用第二套解决方案,使用es5语法重写es6

二、new.target 重写

es5的构造函数前面如果不用new调用,this指向window,对象的属性就得不到值了,所以之前都要在构造函数中通过判断this是否使用了new关键字来确保普通的函数调用方式都能让对象复制到属性。

javascript 复制代码
 1     function Person( uName ){
 2         if ( this instanceof Person ) {
 3             this.userName = uName;
 4         }else {
 5             return new Person( uName );
 6         }
 7     }
 8     Person.prototype.showUserName = function(){
 9         return this.userName;
10     }
11     console.log( Person( 'ghostwu' ).showUserName() );
12     console.log( new Person( 'ghostwu' ).showUserName() );

es6中,为了识别函数调用时,是否使用了new关键字,引入了一个新的属性new.target:

  1. 如果函数使用了new,那么new.target就是构造函数;

  2. 如果函数没有使用new,那么new.target就是undefined

  3. es6的类方法中,在调用时候,使用newnew.target指向类本身,没有使用new就是undefined

javascript 复制代码
1         function Person( uName ){
2             if( new.target !== undefined ){
3                 this.userName = uName;
4             }else {
5                 throw new Error( '必须用new实例化' );
6             }
7         }
8         // Person( 'ghostwu' ); //报错
9         console.log( new Person( 'ghostwu' ).userName ); //ghostwu

使用new之后,new.target就是Person这个构造函数,那么上例也可以用下面这种写法:

javascript 复制代码
 1         function Person( uName ){
 2             if ( new.target === Person ) {
 3                 this.userName = uName;
 4             }else {
 5                 throw new Error( '必须用new实例化' );
 6             }
 7         }
 8         
 9         // Person( 'ghostwu' ); //报错
10         console.log( new Person( 'ghostwu' ).userName ); //ghostwu
javascript 复制代码
 1         class Person{
 2             constructor( uName ){
 3                 if ( new.target === Person ) {
 4                     this.userName = uName;
 5                 }else {
 6                     throw new Error( '必须要用new关键字' );
 7                 }
 8             }            
 9         }
10 
11         // Person( 'ghostwu' ); //报错
12         console.log( new Person( 'ghostwu' ).userName ); //ghostwu

上例,在使用new的时候, new.target等于Person

掌握new.target之后,接下来,我们用es5语法改写上文中es6的类语法。

javascript 复制代码
 1         let Person = ( function(){
 2             'use strict';
 3             const Person = function( uName ){
 4                 if ( new.target !== undefined ){
 5                     this.userName = uName;
 6                 }else {
 7                     throw new Error( '必须使用new关键字' );
 8                 }
 9             }
10 
11             Object.defineProperty( Person.prototype, 'sayName', {
12                 value : function(){
13                     if ( typeof new.target !== 'undefined' ) {
14                         throw new Error( '类里面的方法不能使用new关键字' );
15                     }
16                     return this.userName;
17                 },
18                 enumerable : false,
19                 writable : true,
20                 configurable : true
21             } );
22 
23             return Person;
24         })();
25 
26         console.log( new Person( 'ghostwu' ).sayName() );
27         console.log( Person( 'ghostwu' ) ); //没有使用new,报错

三、拓展阅读

相关推荐
Lee川14 小时前
深度解构JavaScript:作用域链与闭包的内存全景图
javascript·面试
_Eleven15 小时前
Pinia vs Vuex 深度解析与完整实战指南
前端·javascript·vue.js
技术狂小子15 小时前
# 一个 Binder 通信中的多线程同步问题
javascript·vue.js
进击的尘埃16 小时前
Service Worker + stale-while-revalidate:让页面"假装"秒开的那些事
javascript
秋水无痕16 小时前
从零搭建个人博客系统:Spring Boot 多模块实践详解
前端·javascript·后端
进击的尘埃16 小时前
基于 Claude Streaming API 的多轮对话组件设计:状态机与流式渲染那些事
javascript
juejin_cn17 小时前
[转][译] 从零开始构建 OpenClaw — 第六部分(持久化记忆)
javascript
juejin_cn17 小时前
[转][译] 从零开始构建 OpenClaw — 第七部分(子智能体系统)
javascript
an3174218 小时前
解决 VSCode 中 ESLint 格式化不生效问题:新手也能看懂的配置指南
前端·javascript·vue.js
Lee川20 小时前
🚀《JavaScript 灵魂深处:从 V8 引擎的“双轨并行”看执行上下文的演进之路》
javascript·面试