Closed Xotic750 closed 7 years ago
You'd need to do Function.toString.call
to get the actual source of the function, just in case - the es6-shim
definitely modifies the toString
of many of its shims.
Ok, but I didn't think that node 0.10 and 0.8 had native Map/Set.
They don't :-) that comes in 0.12.
The code in question seems a very strange way to detect the presence of MapIterator
and SetIterator
. But regardless, #391 contains a fix.
Thanks, I haven't tested it yet. The code I posted was just to demonstrate what I was seeing. The actual code is more like
var SET = typeof Set === 'function' && isSet(new Set()) && Set;
var testSet = SET && new SET(['SetSentinel']);
var sValues = SET && SET.prototype.values;
function isSetIterator(value) {
if (!SET || !isObjectLike(value) || !ES.IsCallable(value.next)) {
return false;
}
try {
return ES.Call(
value.next,
ES.Call(sValues, testSet)
).value === 'SetSentinel';
} catch (ignore) {}
return false;
}
It's fairly expensive, I know, but accuracy is more important than performance for me and I couldn't figure out a better cross environment/realm way of doing it?
This seems like it would be sufficient:
var SetIteratorProto = Object.getPrototypeOf(new Set().values());
var isSetIterator(value) { return Object.getPrototypeOf(value) === SetIteratorProto; }
Does not work cross frame.
function getXSet() {
var iframe = document.createElement('iframe');
var parent = document.body || document.documentElement;
var set;
iframe.style.display = 'none';
parent.appendChild(iframe);
iframe.src = 'javascript:';
set = iframe.contentWindow.Set;
parent.removeChild(iframe);
iframe = null;
return set;
};
var XSet = getXSet();
var SetIteratorProto = Object.getPrototypeOf(new Set().values());
function isSetIterator1(value) {
return Object.getPrototypeOf(value) === SetIteratorProto;
}
var testSet = new Set(['SetSentinel']);
var sValues = Set.prototype.values;
function isSetIterator2(value) {
if (typeof value !== 'object' || typeof value.next !== 'function') {
return false;
}
try {
return value.next.call(sValues.call(testSet)).value === 'SetSentinel';
} catch (ignore) {}
return false;
}
var setIt1 = new Set().values();
var setIt2 = new XSet().values();
console.log(setIt1, setIt2);
console.log(isSetIterator1(setIt1), isSetIterator1(setIt2));
console.log(isSetIterator2(setIt1), isSetIterator2(setIt2));
@Xotic750 there's simply not enough machinery on non-globally-exposed items, like GeneratorFunction, or IteratorPrototype, etc, for you to determine them cross-realm. They don't have methods that pivot on internal slots nor is toString
reliable.
Is there a situation where isSetIterator2
gets it wrong (I guess something could be fabricated to make it fail, but you'd really be wanting to), I haven't found one yet?
Node uses some internal machinery for its inspect
module, but of course that is not available cross-browser for my inspect-x
. This was the best that I could come up with, and it has passed every test that I can throw at it, so far (until adding es6-shim
). Otherwise I may as well go back to toString.call(value)==="[object Set Iterator]"
, which also works cross-frame on all native implementations that I have tested, but es6-shim
will also fail, and it could be a modified value. Of course I could leave the detection and tests out completely, but I'd like to port it as faithfully as I can and would like it to work with es6-shim
.
I am detecting
MapIterator
andSetIterator
for my inpect-x module. On native ES6Map
andSet
, the following code will alerttrue
andTypeError: Method Map Iterator.prototype.next called on incompatible receiver
.http://jsfiddle.net/Xotic750/xw2Lpbwz/
But on
es6-shim
iterators it alertstrue
andtrue
.(I think it is the shim and not the native versions, but I have not tested thoroughly yet)
Safari8, FF26, IE10, node0.10 and 0.8 are examples.
I just did a
toString
of thenext
function and it is the shim version.