├── 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 | --------------------------------------------------------------------------------