Binding `new`?
Closed this issue ยท 9 comments
The current syntax seems like it would work well with auto-binding constructors as well. Java also has a version for this, with its Class::new
shorthand. The same thing could be very useful for JavaScript as well, since classes can't be instantiated without new
.
class Foo {
constructor(value) { this.value = value }
}
const foos = args.map(Foo::new)
const foos = args.map(value => new Foo(value))
Only incidentally, I'm suggesting a very similar syntax. Since new
is a keyword in all contexts, it couldn't possibly be an identifier for a bound
function, so it would work very well.
As for the suggested semantics, expr::new
should function identically to the following when called:
function exprCreate() {
return Reflect.construct(expr, arguments)
}
More specific semantics:
Syntax:
BindExpression[Yield] :
LeftHandSideExpression[?Yield] :: `new`
Runtime Semantics: BoundConstructorCreate(target, boundArgs)
- Assert: Type(target) is Object.
- Assert: IsConstructible(target) is true.
- Let proto be target.[GetPrototypeOf].
- ReturnIfAbrupt(proto).
- Let obj be a newly created object.
- Set objโs essential internal methods to the default ordinary object definitions specified in 9.1.
- Set the [[Call]] internal method of obj to the [[Construct]] internal method implementation as described in 9.4.1.2.
- Set the [[Construct]] internal method of obj as described in 9.4.1.2.
- Set the [[Prototype]] internal slot of obj to proto.
- Set the [[Extensible]] internal slot of obj to true.
- Set the [[BoundTargetFunction]] internal slot of obj to targetFunction.
- Set the [[BoundThis]] internal slot of obj to null.
- Set the [[BoundArguments]] internal slot of obj to an empty List.
- Return obj.
Note: This is equivalent BoundFunctionCreate(target, null, empty List) where target is always a constructor, but with the exception that [[Call]] and [[Construct]] have the same implementation.
Runtime Semantics:
BindExpression :
LeftHandSideExpression :: `new`
- Let targetReference be the result of evaluating LeftHandSideExpression.
- Let target be GetValue(targetReference).
- ReturnIfAbrupt(target).
- If IsConstructor(target) is false, throw a TypeError exception.
- Return BoundConstructorCreate(target, boundArgs).
This could be a sweet addition. Being able to new
things is useful (and is useful in Java 8 too).
Thanks @IMPinball !
After @dtinth brought up Java method references over in #18, I considered this as well.
I think it would make a lot of sense provided that we split up this proposal into separate "method extraction" and "pipelining" operators. This would fit right in with a method extraction operator.
console::log; // => (...args) => console.log(...args) // or something like that
Array::new; // => (...args) => new Array(...args) // or something like that
๐ Referencing new (and methods) like this is super useful and pairs well with classes, especially when deserializing.
@ssube "deserializing"? Can you explain?
@zenparsing Instantiating classes with data, like xhr.get('example.com/books').then(JSON::parse).then(books => books.map(Book::new))
.
@ssube Gotcha.
See #26.
Rather than request to new syntax, we can just implement it under current frame.
class Foo {}
Foo.new( 'foo' );
array.map( Foo.new );
'foo' |> Foo.new;
Before proposal goes, we can just only do prototype modification to implement it.
Reflect.defineProperty( Function.prototype, 'new', {
get(){
const newer= ( ...args )=> new this( ...args, );
Reflect.defineProperty( newer, 'length', { value:this.length, }, );
Reflect.defineProperty( newer, 'name', { value:`${this.name}.new`, }, );
return newer;
},
}, );
Could you please not resurrect an issue closed 4 years ago for this? It's not helpful and I'd rather not deal with any more notification spam than I have to.