ES6学习——类语法:继承中的实例构造过程

原创 2016年01月12日 07:03:49

ES6的类中有个constructor函数是用来当构造函数的,如果你不写这个函数,ES6规范中会按照一定的条件给你自动添加上,在规范的14.5.14章节中有这样的描述:

ClassTail : ClassHeritageopt { ClassBodyopt }

10. If constructor is empty, then,
    a. If ClassHeritageopt is present, then
        i. Let constructor be the result of parsing the source text constructor(... args){ super (...args);} using the syntactic grammar with the goal symbol MethodDefinition.
    b. Else,
        i. Let constructor be the result of parsing the source text constructor( ){ } using the syntactic grammar with the goal symbol MethodDefinition.


在有父类的子类默认constructor里,会先调用一把super(),这里为什么要这样写呢?可不可以不写这句话呢?一旦你在自己的类中声明了constructor方法,那么

我们就需要先弄清几点constructor的规则:

1)在constructor里,默认this是没有初始化的,如果在调用super()之前,就使用this,会报异常

2)this被初始化后,再次调用super()同样报错

3)constructor里没有调用super(),也没有访问this,同样报错。因为constructor默认返回this,而this仍处在未初始化状态

4)constructor只能返回对象类型或者undefined,返回其它类型直接报错。

    4.1)如果返回对象类型,那么this可以不被初始化,也就是说可以不调用super()


下面我们用代码验证一下:

	'use strict';
	
	class Point{
	
	}
	
	class ColorPoint extends Point{
		constructor(x){
			this.x = 1;//Uncaught ReferenceError: this is not defined
		}
	}
	
	var cp = new ColorPoint(1);

		constructor(x){
			super();
			this.x = 1;
			super();//Uncaught ReferenceError: this is not defined
		}

		constructor(x){//Uncaught ReferenceError: this is not defined
		}

		constructor(x){
			super();
			return 1;//Uncaught TypeError: Derived constructors may only return object or undefined
		}

		constructor(x){//OK!
			return {};
		}

至于上面的几点规则具体在规范中的哪些位置我也并没有都找到,惭愧。想要研究的可以从14.5章节入手。


为什么我们说不调用super方法会导致this未被初始化呢?我们需要查看一下super方法中到底干了什么事,在规范的12.3.5.3章节中:

SuperCall : super Arguments
1. Let newTarget be GetNewTarget().
2. If newTarget is undefined, throw a ReferenceError exception.
3. Let func be
GetSuperConstructor().
4. ReturnIfAbrupt(func).
5. Let argList be ArgumentListEvaluation of Arguments.
6. ReturnIfAbrupt(argList).
7. Let result be Construct(func, argList, newTarget).
8. ReturnIfAbrupt(result).
9. Let thisER be GetThisEnvironment( ).
10. Return thisER.BindThisValue(result
).

我们继续看BindThisValue,在8.1.1.3.1:

1. Let envRec be the function Environment Record for which the method was invoked.
2. Assert: envRec.[[thisBindingStatus]] is not "lexical".
3. If envRec.[[thisBindingStatus]] is "initialized", throw a ReferenceError exception.
4. Set envRec.[[thisValue]] to V.
5. Set envRec.[[thisBindingStatus]] to "initialized".
6. Return V.


这个流程就比较清楚了。this是super中被构造出来的,而不是在子类的constructor中先被构造出来的。这和以往我们的用法完全不一样:

	function Point(){}
	
	function ColorPoint(){//原来我们使用这种方法模拟继承,可以清楚的看出,this是先被构造出来的,然后在传给父类的构造函数
		Point.call(this);
	}

为什么ES6中改了this的构造过程呢?因为ES6中允许我们继承内置的类,如Array,Error等。如果this先被创建出来,在传给Array等系统内置类的构造函数,这些内置类的构造函数是不认这个this的:

function MyArray(len) {
Array.call(this, len); //this被忽略了
}

MyArray.prototype = Object.create(Array.prototype);

var myArr = new MyArray(0);
myArr.length // 0

myArr[0] = 'foo';
myArr.length//0

*以上全部代码在Chrome 47下通过测试

ES6---通过class构造函数extends、public在其中的作用

在es5中,构造函数生成的对象实例一般包括私有属性和共用方法,其中共用方法一般是通过构造函数的原型进行定义。而es6中,通过class类进行定义构造函数则不用借助于原型….●class定义类:////...
  • Wbiokr
  • Wbiokr
  • 2017年04月05日 22:31
  • 1860

ES6之Object--构造函数与类静态方法

站在OOP的角度看待ES,其中的Object是非常关键的类,他为一切对象的基类。而其中的方法也是被绝大多数类继承。并且Object中的一些方法使用技巧在JS的框架设计中起到了很大的作用,本文主要是对E...
  • Allocator
  • Allocator
  • 2017年03月11日 21:39
  • 614

ES6详解三:class

class是es6引入的最重要特性之一。在没有class之前,我们只能通过原型链来模拟类。基本用法如果你用过java这样的纯面向对象语言,那么你会对class的语法非常熟悉。class People ...
  • lihongxun945
  • lihongxun945
  • 2015年09月17日 21:19
  • 32097

ES6详解六:赋值语法糖 destructing & spread

destructing这个不知道怎么翻译就不翻译了,意思就是可以通过析构表达式的右边值来同时对左边的多个值进行赋值。说起来有点绕,举几个简单的例子就可以理解:var [a,b,c]=[1,2,3]; ...
  • lihongxun945
  • lihongxun945
  • 2015年10月06日 20:45
  • 6039

析构函数

析构函数是提供一个在对象删除前可以释放这个对象所占有的资源的机会。比如: class A { A(){m_a=new int[10];} ~A(){delete [] m_a;} ...
  • irlwh
  • irlwh
  • 2017年01月10日 10:29
  • 109

创建对象中构造函数和析构函数

在创建一个对象实例,先调用父类的构造函数,再调用派生类 在销毁一个对象实例时,先销毁派生类,在销毁父类的析构函数 A继承B class A { private: char name[10]; ...
  • jxxiongxiaozhi
  • jxxiongxiaozhi
  • 2015年01月26日 19:16
  • 540

ES6 class的继承使用细节

ES6 class的继承与java的继承大同小异,如果学过java的话应该很容易理解,都是通过extends关键字继承。 class Animal{ constructor(color){ th...
  • qq_28506819
  • qq_28506819
  • 2017年04月28日 17:43
  • 921

(一一六)类的构造函数和析构函数

类构造函数: 构造函数 是专门用于构造新对象、将值赋给它们的数据成员。 C++为这些成员提供了名称和使用语法,而程序员需要提供方法定义。名称与类名相同。 例如:Stock类的一个可能的构造函数是...
  • qq20004604
  • qq20004604
  • 2016年01月19日 00:39
  • 273

ES6 解析赋值

解析赋值可是解决了之前es5的一大弊端,如果对一个对象取值,需要写好长的代码,现在使用解析赋值可以轻松的获取对应的元素。 解析赋值主要用在可以迭代的变量上。 例如 对象 数组 集合 等具有Iter...
  • leol77
  • leol77
  • 2016年12月14日 11:58
  • 273

es6+webpack+vue项目实践

最近开发一个铜盘功能,用了以上的技术栈开发。有一些心得可以记录下来。包括写的模块的经验。 构建 后台是用java实现,使用velocity模板。目录结构 ---webapp |-----...
  • sinat_17775997
  • sinat_17775997
  • 2016年10月12日 17:43
  • 3793
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:ES6学习——类语法:继承中的实例构造过程
举报原因:
原因补充:

(最多只允许输入30个字)