Constructor virtual by default
* lib/ClassBuilder.js (_keywordParser): Make __construct virtual. * test/Class/ConstructorTest.js: Add test. * doc/classes.texi (Constructors): Update documentation.master
parent
e39ff83b40
commit
92c57c8ffe
|
@ -568,6 +568,25 @@ Constructors are always public;
|
|||
It is not permitted to make a constructor protected or private
|
||||
(@pxref{Access Modifiers}).
|
||||
|
||||
Unlike all other methods,
|
||||
constructors are @ref{Member Keywords,,@code{virtual}} by default.
|
||||
Many other languages (C++, Java, C#, and others) do not inherit
|
||||
class constructors from their supertypes.
|
||||
ease.js classes are prototypes,
|
||||
and uninstantiated prototypes are functions (constructors),
|
||||
so classes are effectively first-class objects in JavaScript.
|
||||
Consequently,
|
||||
they can be passed around and invoked like any other function,
|
||||
which can be a convenient alternative to factories
|
||||
(and a transparent alternative to functions that create objects).
|
||||
It is therefore useful to have the constructor as part of the class's
|
||||
public API.
|
||||
However,
|
||||
it is also important that subtypes always be able to override the
|
||||
constructor (@pxref{Overriding Methods});
|
||||
otherwise subtypes may not be able to initialize properly,
|
||||
making for a very clumsy implementation.
|
||||
|
||||
Constructors are optional,
|
||||
and no constructor is defined by default.@footnote{
|
||||
That is, no user-facing constructor is defined by default;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/**
|
||||
* Handles building of classes
|
||||
*
|
||||
* Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017
|
||||
* Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNU ease.js.
|
||||
*
|
||||
|
@ -687,9 +688,8 @@ exports.prototype.buildMembers = function buildMembers(
|
|||
/**
|
||||
* Member keyword parser
|
||||
*
|
||||
* In reality, this parser is simply intended to override names where there
|
||||
* are applicable aliases; all keyword parsing is kept to the original
|
||||
* implementation.
|
||||
* This parser handles aliases and constructor virtualization; all keyword
|
||||
* parsing is kept to the original implementation.
|
||||
*
|
||||
* @param {string} prop property to parse
|
||||
*
|
||||
|
@ -705,6 +705,12 @@ function _keywordParser( prop )
|
|||
result.name = alias;
|
||||
}
|
||||
|
||||
// constructors are always virtual by default (exception to the rule)
|
||||
if ( result.name === '__construct' )
|
||||
{
|
||||
result.keywords[ 'virtual' ] = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -218,6 +218,39 @@ require( 'common' ).testCase(
|
|||
},
|
||||
|
||||
|
||||
/**
|
||||
* This one is a bit of an interesting case. Information can be found
|
||||
* in the manual, but for the sake of this test, all we need to know is
|
||||
* that we should be able to override `__construct' without having
|
||||
* provided the `virtual' keyword on the supertype. This differs from
|
||||
* all other methods which are non-virtual by default.
|
||||
*/
|
||||
'@each(ctors) Constructor is virtual by default': function( name )
|
||||
{
|
||||
var _self = this;
|
||||
|
||||
this.assertDoesNotThrow( function()
|
||||
{
|
||||
var sub_called = false;
|
||||
|
||||
// not explicitly virtual
|
||||
var base_dfn = {};
|
||||
base_dfn[ name ] = function() {};
|
||||
|
||||
var sub_dfn = {};
|
||||
sub_dfn[ 'override ' + name ] = function()
|
||||
{
|
||||
sub_called = true;
|
||||
};
|
||||
|
||||
_self.Sut.extend( _self.Sut( base_dfn ), sub_dfn )();
|
||||
|
||||
// sanity check
|
||||
_self.assertOk( sub_called );
|
||||
}, Error );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* When a constructor is instantiated conventionally in ECMAScript, the
|
||||
* instance's `constructor' property is set to the constructor that was
|
||||
|
|
Loading…
Reference in New Issue