├── README.md
├── tc39-reflect-isconstructor-iscallable.md
└── tc39-well-known-symbol-clone.md
/README.md:
--------------------------------------------------------------------------------
1 | TC39-Proposals
2 | ==============
3 |
4 | Things that might be good to include in ECMA 262
5 |
6 | - [@@clone / Reflect.clone()](./tc39-well-known-symbol-clone.md)
7 | - [Reflect.isCallable() / Reflect.isConstructor()](./tc39-reflect-isconstructor-iscallable.md)
8 |
--------------------------------------------------------------------------------
/tc39-reflect-isconstructor-iscallable.md:
--------------------------------------------------------------------------------
1 | Function.isCallable() / Function.isConstructor()
2 | ==============================================
3 |
4 | ## Why are these useful?
5 |
6 | - Help support classes/other new function definitions in legacy framework code without significant changes
7 | - Expose a pretty important part of the runtime to applications, who also may wish to use them
8 | - Not require depending on slow (and inconsistent across implementations) `Function.toString()` processing or try/catch statements
9 |
10 | ## The very tiny normative language:
11 |
12 | ### Function.isCallable ( argument )
13 |
14 | When the `isCallable` function is called with argument argument, the following steps are taken:
15 |
16 | 1. If [IsCallable](https://tc39.es/ecma262/#sec-iscallable)(argument) is **false**, return **false**.
17 | 1. If argument has a \[\[IsClassConstructor]] internal slot with value **true**, return **false**.
18 | 1. Return **true**.
19 |
20 | (Should be "Return [IsCallable](https://tc39.es/ecma262/#sec-iscallable)(argument)", but adjusted to not report Class constructors as callable, as they throw unconditionally without invoking any author code)
21 |
22 | ### Function.isConstructor ( argument )
23 |
24 | When the `isConstructor` function is called with argument argument, the following steps are taken:
25 |
26 | 1. Return [IsConstructor](https://tc39.es/ecma262/#sec-isconstructor)(argument).
27 |
--------------------------------------------------------------------------------
/tc39-well-known-symbol-clone.md:
--------------------------------------------------------------------------------
1 | @@clone
2 | =======
3 |
4 | ## Rationale
5 |
6 | It is useful to construct copies of objects, for use in dirty checking (tracking a new state vs old state of an object), or for creating an immutable/hidden clone. An abstract convention for cloning objects is useful as it allows simplifying the code needed for generalized cloning operations.
7 |
8 | In ES5, naive strategies for doing this are used:
9 |
10 | ```js
11 | function Clone(O) {
12 | var clone = Object.create(Object.getPrototypeOf(O));
13 | Object.getOwnPropertyNames(O).forEach(function(key) {
14 | clone[key] = O[key];
15 | });
16 | return clone;
17 | }
18 | ```
19 |
20 | Unfortunately, this strategy is problematic in the following cases:
21 |
22 | 1. **Cloning host objects**
23 |
24 | Despite creating the clone object using the host object's prototype, a native C++ instance of the host object is not created.
25 |
26 | In some engines, accessing any properties of this object specified in IDL will result in an exception.
27 |
28 | 2. **Cloning collections introduced in ES2015**
29 |
30 | Data in collections is not stored as properties of the collection, and as such, copying properties does not accomplish the requested task. It takes a fair bit of special casing code in order to handle cloning these objects.
31 |
32 | Weak collections can't be cloned as engines have rejected providing any API that would require iteration, such as the `clear()` method.
33 |
34 | ## @@clone conventions:
35 |
36 | The `@@clone` function is a method whose `this` value is the object being cloned, and which receives a parameter indicating
37 | whether the clone should be a "deep" clone (whereby nested objects should be similarly cloned). As such, a shallow clone
38 | would create copies of object values, while a deep clone would create new objects.
39 |
40 | ## Reflect.clone ( O [, deep] )
41 |
42 | When the `clone` function is called with arguments O and deep, the following steps are taken:
43 |
44 | 1. If [Type](https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values)(O) is not Object, then return O.
45 | 1. Let deep be ! [ToBoolean](https://tc39.es/ecma262/#sec-toboolean)(deep).
46 | 1. Let cloneFn be ? [GetMethod](https://tc39.es/ecma262/#sec-getmethod)(obj, @@clone).
47 | 1. If cloneFn is **undefined**, then set cloneFn to [%Object.prototype[@@clone]%](#objectprototype--clone---deep-).
48 | 1. Else if [IsCallable](https://tc39.es/ecma262/#sec-iscallable)(cloneFn) is **false**, then throw a **TypeError** exception.
49 | 1. Let result be ? [Call](https://tc39.es/ecma262/#sec-call)(cloneFn, obj, « deep »).
50 | 1. If [Type](https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values)(result) is not Object, then throw a **TypeError** exception.
51 | 1. Return result.
52 |
53 | ## Set.prototype \[ @@clone ] ( deep )
54 |
55 | 1. Let O be ? [ToObject](https://tc39.es/ecma262/#sec-toobject)(**this** value).
56 | 1. Let deep be ! [ToBoolean](https://tc39.es/ecma262/#sec-toboolean)(deep).
57 | 1. Let ctor be ? [SpeciesConstructor](https://tc39.es/ecma262/#sec-speciesconstructor)(O, [%Set%](https://tc39.es/ecma262/#sec-set-constructor))
58 | 1. Let result be ? [Construct](https://tc39.es/ecma262/#sec-construct)(ctor).
59 | 1. Let iterator be ? [GetIterator](https://tc39.es/ecma262/#sec-getiterator)(O).
60 | 1. Repeat,
61 | 1. Let next be ? [IteratorStep](https://tc39.es/ecma262/#sec-iteratorstep)(iterator).
62 | 1. If next is **false**, then return result.
63 | 1. Let nextValue be ? [IteratorValue](https://tc39.es/ecma262/#sec-iteratorvalue)(next).
64 | 1. If [Type](https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values)(nextValue) is Object, then
65 | 1. If deep is **true**, then set nextValue to ? [Call](https://tc39.es/ecma262/#sec-call)([%Reflect.clone%](#reflectclone-o-deep-), undefined, « nextValue, **true** »).
66 | 1. Let result be ? [Invoke](https://tc39.es/ecma262/#sec-invoke)(result, **"add"**, « nextValue »).
67 |
68 | ## Map.prototype \[ @@clone ] ( deep )
69 |
70 | 1. Let O be ? [ToObject](https://tc39.es/ecma262/#sec-toobject)(**this** value).
71 | 1. Let deep be ! [ToBoolean](https://tc39.es/ecma262/#sec-toboolean)(deep).
72 | 1. Let ctor be ? [SpeciesConstructor](https://tc39.es/ecma262/#sec-speciesconstructor)(O, [%Map%](https://tc39.es/ecma262/#sec-map-constructor))
73 | 1. Let result be ? [Construct](https://tc39.es/ecma262/#sec-construct)(ctor).
74 | 1. Let iterator be ? [GetIterator](https://tc39.es/ecma262/#sec-getiterator)(O).
75 | 1. Repeat,
76 | 1. Let next be ? [IteratorStep](https://tc39.es/ecma262/#sec-iteratorstep)(iterator).
77 | 1. If next is **false**, then return result.
78 | 1. Let nextValue be ? [IteratorValue](https://tc39.es/ecma262/#sec-iteratorvalue)(next).
79 | 1. Let nextKey be Get(nextValue, 0).
80 | 1. Set nextValue to Get(nextValue, 1).
81 | 1. If [Type](https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values)(nextValue) is Object, then
82 | 1. If deep is **true**, then set nextValue to ? [Call](https://tc39.es/ecma262/#sec-call)([%Reflect.clone%](#reflectclone-o-deep-), undefined, « nextValue, **true** »).
83 | 1. Let result be ? [Invoke](https://tc39.es/ecma262/#sec-invoke)(result, **"set"**, « nextKey, nextValue »).
84 |
85 | ## Object.prototype \[ @@clone ] ( deep )
86 |
87 | 1. Let O be ? [RequireObjectCoercible](https://tc39.es/ecma262/#sec-requireobjectcoercible)(**this** value).
88 | 1. If [Type](https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values)(O) is not Object, then return O.
89 | 1. Let deep be ! [ToBoolean](https://tc39.es/ecma262/#sec-toboolean)(deep).
90 | 1. Let proto be ? O.\[\[GetPrototypeOf]]().
91 | 1. Let result be [ObjectCreate](https://tc39.es/ecma262/#sec-objectcreate)(proto).
92 | 1. Let keys be ? O.\[\[OwnPropertyKeys]]().
93 | 1. For each element key of keys, do
94 | 1. Let desc be ? O.\[\[GetOwnProperty]](key).
95 | 1. If [Type](https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values)(desc.\[\[Value]]) is Object, then
96 | 1. If deep is **true**, then set desc.\[\[Value]] to ? [Call](https://tc39.es/ecma262/#sec-call)([%Reflect.clone%](#reflectclone-o-deep-), undefined, « nextValue, **true** »).
97 | 1. ! [DefinePropertyOrThrow](https://tc39.es/ecma262/#sec-definepropertyorthrow)(result, key, desc).
98 |
99 | ## Similar Proposals:
100 |
101 | 1. [Structured cloning and transfer](https://github.com/dslomov-chromium/ecmascript-structured-clone)
102 | Advantages: Deals with cloning between realms --- Disadvantages: limited to host objects and builtins
103 |
--------------------------------------------------------------------------------