ES6学习——类语法:继承中的实例构造过程
2016-01-12 07:03
363 查看
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()
下面我们用代码验证一下:
至于上面的几点规则具体在规范中的哪些位置我也并没有都找到,惭愧。想要研究的可以从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中先被构造出来的。这和以往我们的用法完全不一样:
为什么ES6中改了this的构造过程呢?因为ES6中允许我们继承内置的类,如Array,Error等。如果this先被创建出来,在传给Array等系统内置类的构造函数,这些内置类的构造函数是不认这个this的:
*以上全部代码在Chrome 47下通过测试
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下通过测试
相关文章推荐
- clojure on the beginning
- [leetcode] 222. Count Complete Tree Nodes 解题报告
- BZOJ 3211: 花神游历各国 |树状数组|并查集
- udig中配置style对于中文标注设置问题
- *Maximum Size Subarray Sum Equals k
- What is virtual memory, how is it implemented, and why do operating systems use it?
- *Find Peak Element
- CAD导板框方法
- struts2 标签中read-only=true 和disabled的区别
- mysql的连接字符串
- IntelliJ IDEA
- [leetcode] 199. Binary Tree Right Side View 解题报告
- 使用TestFlight进行内部测试
- maven 本地仓库 删除 lastUpdated 文件
- 1.40-手工绘制板框方法
- 黑马程序员——正则表达式的总结及案例
- [leetcode] 114. Flatten Binary Tree to Linked List 解题报告
- HTTP安全验证机制和Spring Security
- What happens when you visit a website? What exactly goes on after you type a URL into a browser?
- git