lodash / lodash

A modern JavaScript utility library delivering modularity, performance, & extras.

Home Page:https://lodash.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

isNative issues

zloirock opened this issue · comments

  1. lodash uses Object#toString as template for isNative assuming that is native function. But ES6 changed Object#toString logic for support Symbol.toStringTag. core-js from first versions adds polyfill for this logic and replaces Object#toString. _.isNative works wrong for all native functions with core-js / babel and some other libraries:
require('core-js');
require('lodash').isNative(Object);   // => false
require('lodash').isNative(Function); // => false
require('lodash').isNative(isNaN);    // => false

I will add fallback for lodash in next version core-js, but lodash should use native function whose logic shouldn't be changed in ES6+.
2. lodash uses isNative for detect Set, WeakMap, some object methods - but why? In most polyfills, native methods wrapped for correct work by latest spec and, with this check, will not work with lodash. Related #981. Better use correct feature detection.

Yap, I picked Object.prototype.toString because it's used heavily in other libs and not likely to be mucked with as it's on the Object.prototype. I didn't think about those mucking with it using defineProperty. Any recommendations on a method you wouldn't likely touch?

I didn't think about those mucking with it using defineProperty.

Wrapping Object.prototype.toString not requires native defineProperty - it's already non-enumerable.

Object.prototype.toString = 42;
for(var key in {})console.log('key: ' + key); // nothing

+ DontEnum bug.

Any recommendations on a method you wouldn't likely touch?

Should be in ES3, not constructor, not Object.prototype method - someone wrapped them for store non-enum properties or something else, not Array.prototype method - most of them replaced in es6-shim, not Math method - also for better accuracy. Should be as simple as possible. Possible, global isNaN or isFinite, their ES6 versions - static Number methods, but not sure.

There's bugs in at least some engines where overwriting a built-in does make it enumerable. So there's that.

Are you working with @ljharb on your shims?

There's bugs in at least some engines where overwriting a built-in does make it enumerable.

Yep, but in old irrelevant engines :)

About es6-shim - it's not adds @@toStringTag logic and not wrapped Object#toString, but second issue similar:

require('es6-shim');
require('lodash').isNative(Object.keys); // => false
require('lodash').isNative(Object.getPrototypeOf); // => false
require('lodash').isNative(Object.preventExtensions); // => false

I like using an Object.prototype method as reference because Object.prototype is seen as off-limits to many devs. I'll kick around using constructor, propertyIsEnumerable, or toLocaleString.

They gotta make sure when they wrap they look like the built-in :)

Instead of Object#toString - it's impossible - current isNative uses Function#toString.call(method). Using .bind for fake native source will break #name property.

I'll kick around using constructor or toLocaleString.

I remember one library that wrapped Object#toLocaleString (non-enumerable method in Object.prototype for old IE). constructor will be replaced if someone wrap Object constructor. About propertyIsEnumerable - possible, I will wrap it for Symbol polyfill (all shimmed symbols are non enumerable). I think, possible use hasOwnProperty - for replace it you'd be crazy :)

Ah ya good old hasOwnProperty. I'll make that change then. I'm fine with isNative not being 100% bullet proof I just want to put a good effort in.