The <| operator (pronounced “prototype for”) is used in conjunction with a literal to create a new object whose [[Prototype]] is set to an explicitly specified value. It can be used to address several distinct use cases for which separate solutions have been proposed. Use cases include:
The <| operator may appears within a MemberExpression. Its basic syntax is:
MemberExpression : ...
MemberExpression <| ProtoLiteral
ProtoLiteral :
LiteralObject
LiteralValue
LiteralObject :
RegularExpressionLiteral
ArrayLiteral
ObjectLiteral
FunctionExpression
LiteralValue :
NumberLiteral
StringLiteral
BooleanLiteral
This basic semantics is to create a new object exactly as would normally be created by the ProtoLiteral except for the value of the object’s [[Prototype]] internal property. If the ProtoLiteral is a LiteralValue the new Object is created as if by ToObject except for the value of for the value of the object’s [[Prototype]] internal property.
The [[Prototype]] internal property of the new object is set to the value of the MemberExpression. The value of the MemberExpression must be typeof “object”. The value may be null. A TypeError exception is thrown if typeof the MemberExpression is not “object”.
If the LHS operand has a property named prototype and the RHS operand is a function expression then the [[Prototype]] of the function object is set to the LHS object and the prototype property of the new function is set to a new object whose [[Prototype]] is the value of the LHS’s prototype property. Here’s a picture of what happens in this case: function "subclassing" UML diagram
MyObject.prototype <| {a:1,b:2}
appBehavior <| [0,1,2,3,4,5]
Array.create=function(proto,props) {return Object.defineProperties(proto <| [ ], props)};
let f = EnhancedFunctionPrototype <| function () {}
let superclass = function () {}; //define a constructor method superclass.new = function () {return (new this()).initialize()}; //define a instance method superclass.prototype.initialize = function () {return this}; let subclass = superclass <| function () {}; let instance = subclass.new(); //subclass.new executes a method inherited from superclass which invokes //initialize on a new subclass instance. The initialize method is //inherited from superclass.prototype
var p = newRegExpMethods <| /[a-m][3-7]/
Replace:
var o = { __proto__ : myProto, a:0, b: function () {} }
With:
var o = myProto <| { a:0, b: function () {} }
We may still want to define Array.create, RegExp.create, and Function.create so they can be used in non-Harmony implementations and contexts. In that case they should be defined in terms of the semantics of the <| operator.
This proposal is an alternative to the array_subtypes and array_create proposals.
It is also an alternative to the [[Prototye]] functionality of the Object Initialiser Meta Properties proposal.
The function proposed in array_subtypes can be implemented in terms of <| as:
Array.createConstructor = function () { let constructor = function c(...args) { if (args.length!==1 || typeof args[0] !== 'number') return c.prototype <| [...args]; let len = args[0]; if (len !== len>>>0) throw new RangeError; let a = c.prototype <|[]; a.length = len; return a; } constructor.prototype.constructor = constructor; return constructor; }
The function in the original array_create proposals can be implemented as:
Array.create = function(proto, args ) { if (args!==undefined) return proto <| [...args]; return proto <| [ ]; }
proto was originally proposed as this operator symbol. Experimentation suggested that a keyword operator was harder to read and might commonly result in awkward code phrasing such as:function (proto) { return proto proto {a:1, b:2} }
var obj = someProto <| { prop1: expr, get prop2 () { return computeSomeValue(); }, method: function (a,b,c) { return this.prop2+a+b+c; } };
and
var obj = { prop1: expr, get prop2 () { return computeSomeValue(); }, method: function (a,b,c) { return this.prop2+a+b+c; } } |> someProto;
<|. For example, <:, :>, |>, ^^, *>, &>, ^|, <|-, etc. It isn’t clear that any of these is more meaningful or mnemonic than <|.<| symbol is somewhat suggestive of the UML Generalization arrow which is the way inheritance is represented in UML class diagrams. var ExtendedDate = Date <| function (...args) { super.constructor(...args); ExtendedDate.prototype.extendedMethod = function () {...} }
<| has been a controversial choice as the symbol for the prototype-of operator. Some people like it and other don’t. Some people feel the it “points” in the wrong direction. Some people don’t like the visual appearance of of how the < and | align, particularly in certain fonts.
An alternative that wasn’t previously seriously considered is to use -> as the prototype-of operator symbol. This usage had not been considered because -> was a candidate function expression shorthand symbol. More recently it appears that the function usage is an unlikely outcome given other alternatives and mounting interest in block lambda expressions. In that case, -> becomes available as an reasonable alternative for <|
For visual comparison purposes, the following shows many of the above examples, re-expressed using ->
MyObject.prototype -> {a:1,b:2} appBehavior -> [0,1,2,3,4,5] Array.create=function(proto,props) {return Object.defineProperties(proto -> [ ], props)}; let f = EnhancedFunctionPrototype -> function () {} let superclass = function () {}; //define a constructor method superclass.new = function () {return (new this()).initialize()}; //define a instance method superclass.prototype.initialize = function () {return this}; let subclass = superclass -> function () {}; let instance = subclass.new(); //subclass.new executes a method inherited from superclass which invokes //initialize on a new subclass instance. The initialize method is //inherited from superclass.prototype var p = newRegExpMethods -> /[a-m][3-7]/ var o = myProto -> { a:0, b: function () {} }