React-native: Objects prototypes extending

Created on 24 Jan 2016  ·  20Comments  ·  Source: facebook/react-native

I was trying to polyfill my App by importing a file:

(function() {
  'use strict';

   String.prototype.format = function () {
     ....
   };
   ...
})()

And the error was caught

One of the sources for assign has an enumerable key on the prototype chain. This is an edge case that we do not support. This error is a performance optimization and not spec compliant.

It was totally ok in RN 0.15. It happens when I upgraded my project to RN 0.18

AsyncStorage Locked

Most helpful comment

Something is doing Object.assign(String.prototype, something)

I'm curious if you could give us the stack trace to see what does it and if we really need to do that.

In the meantime you can workaround the warning by doing

Object.defineProperty(String.prototype, 'format', {
  value: function() { ... },
  enumerable: false
});

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

All 20 comments

Hey AwesomeJerry, thanks for reporting this issue!

React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.

  • If you don't know how to do something or something is not working as you expect but not sure it's a bug, please ask on StackOverflow with the tag react-native or for more real time interactions, ask on Discord in the #react-native channel.
  • If this is a feature request or a bug that you would like to be fixed, please report it on Product Pains. It has a ranking feature that lets us focus on the most important issues the community is experiencing.
  • We welcome clear issues and PRs that are ready for in-depth discussion. Please provide screenshots where appropriate and always mention the version of React Native you're using. Thank you for your contributions!

Something is doing Object.assign(String.prototype, something)

I'm curious if you could give us the stack trace to see what does it and if we really need to do that.

In the meantime you can workaround the warning by doing

Object.defineProperty(String.prototype, 'format', {
  value: function() { ... },
  enumerable: false
});

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Thanks! By using Object.defineProperties, it works like a charm.

I only got the following logs from XCode, so it's hard to debug.

2016-01-24 11:57:15.642 [warn][tid:com.facebook.React.JavaScript] One of the sources for assign has an enumerable key on the prototype chain. This is an edge case that we do not support. This error is a performance optimization and not spec compliant.
2016-01-24 11:57:15.647 [trace][tid:com.facebook.React.JavaScript] 'Failed to print error: ', 'One of the sources for assign has an enumerable key on the prototype chain. This is an edge case that we do not support. This error is a performance optimization and not spec compliant.'

https://github.com/facebook/react-native/blob/master/packager/react-packager/src/Resolver/polyfills/polyfills.js#L56

Can you add a debugger; statement here and run it inside of Chrome and see what the stack trace is?

I added

Array.prototype.test = function(){};

in my index.ios.js, and print

console.log(nextSource, key)

in .../packager/src/Resolver/polyfills/polyfills.js#L56

it prints

[ 'multiGet',
  'multiSet',
  'multiMerge',
  'multiRemove',
  'clear',
  'getAllKeys' ], 'test'

Does this help??

This is strange. Those are AsyncStorage keys. Anyway, I'll let this rest since you got unblocked and if someone else has the same issue we can spend more time figuring out what's going on :)

I'm having a lot of problems with this, but with Chrome debugger its runs perfectly.

One of the sources for assign has an enumerable key on the prototype chain. This is an edge case that we do not support. This error is a performance optimization and not spec compliant.

I got stung by this for no apparent reason. I had a couple of functions I'd added to Array.prototype, and changing to Object.defineProperty to attach them got rid of the error. So thanks!

This was baffling to figure out. A couple of days ago I upgraded from RN 0.15 to RN 0.20. This involved quite a few changes (like pulling a thread from a sweater), but after a few hours I got the app working fine with the exception of one yellow box warning. Then my web app also needed to be upgraded because of the change to React 0.14. So I committed my changes and started working on the react side. I got that working --- a couple more npm modules needed to be upgraded, but when that was done, I committed that and went back to the RN app. It then started crashing with this error. I tried everything to figure out what had caused the regression-- I checked out the version that had been working from git, it no longer worked. I removed node_modules and reinstalled everything. I completely removed the modules that I'd upgraded for the web app, just in case they were contributing. So as far as I could determine, I had exactly the same code that had been working two days before, now failing with this error.

The other thing that's baffling is what this has to do with Object.assign. I use Object.assign 8 times in my app, and I'm quite sure none of the arguments are Array types --- they're all objects. Why does changing the enumerable property on an Array prototype affect the Object.assign polyfill?

It was impossible to use the Chrome debugger to debug this problem, because the crash occurs very early and there isn't time to open the debugging menu and select "Debug in Chrome"

Sorry about that @chetstone. Now that you found the issue, is there any way you could spend some time trying to figure out why changing the array prototype causes this error to pop up? There's no reason it should, there must be something unexpected going on.

Not sure how to do it. It turns out the real reason I couldn't use the debugger is that I was using the Release scheme. Switching to the Debug scheme and turning on Debug in Chrome and, voila, ... ... ... the crash doesn't happen any more! (as previously reported) Umm..How to do a stack trace without the debugger?

I tried inserting console.log(new Error().stack); before line 56 and got this. It doesn't mean much to me, but I notice AsyncStorage is mentioned (and I also had seen something similar to @AwesomeJerry).

2016-02-29 22:59:05.094 [info][tid:com.facebook.React.JavaScript][RCTJSCProfiler.m:63] JSC profiler is not supported.
2016-02-29 22:59:05.567 [info][tid:com.facebook.React.JavaScript] assign@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:191:22
_genLookup@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:21395:43
processModuleConfig@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:21231:16
get@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:21013:49
http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:61715:38
requireImpl@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:76:17
_require@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:36:19
AsyncStorage@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:20053:34
http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:67093:6
requireImpl@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:76:17
_require@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:36:19
http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:67030:24
requireImpl@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:76:17
_require@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:36:19
http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:66854:112
requireImpl@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:76:17
_require@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:36:19
http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:65029:26
requireImpl@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:76:17
_require@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:36:19
http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:19921:22
requireImpl@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:76:17
requireImpl@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:44:30
_require@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:36:19
global code@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:72874:9
2016-02-29 22:59:05.568 [error][tid:com.facebook.React.JavaScript] One of the sources for assign has an enumerable key on the prototype chain. This is an edge case that we do not support. This error is a performance optimization and not spec compliant.
2016-02-29 22:59:05.569 [info][tid:com.facebook.React.JavaScript] assign@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:191:22
_genLookup@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:21395:43
processModuleConfig@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:21231:16
get@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:21013:49
reportException@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:25133:50
handleException@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:25174:16
handleError@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:24972:45
reportFatalError@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:737:53
requireImpl@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:46:35
_require@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:36:19
global code@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:72874:9
2016-02-29 22:59:05.570 [info][tid:com.facebook.React.JavaScript] 'Failed to print error: ', 'One of the sources for assign has an enumerable key on the prototype chain. This is an edge case that we do not support. This error is a performance optimization and not spec compliant.'
2016-02-29 22:59:05.575 [info][tid:com.facebook.React.JavaScript] Running application "Sadhana" with appParams: {"rootTag":1,"initialProps":{}}. __DEV__ === true, development-level warning are ON, performance optimizations are OFF
2016-02-29 22:59:05.575 [error][tid:com.facebook.React.JavaScript] Application Sadhana has not been registered. This is either due to a require() error during initialization or failure to call AppRegistry.registerComponent.
2016-02-29 22:59:05.575 [info][tid:com.facebook.React.JavaScript] assign@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:191:22
_genLookup@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:21395:43
processModuleConfig@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:21231:16
get@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:21013:49
reportException@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:25133:50
handleException@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:25174:16
handleError@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:24972:45
reportFatalError@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:737:53
guard@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:21161:28
callFunctionReturnFlushedQueue@http://Kurukulle.local:8081/index.ios.bundle?platform=ios&dev=true:21204:6
callFunctionReturnFlushedQueue@[native code]
apply@[native code]
2016-02-29 22:59:05.576 [info][tid:com.facebook.React.JavaScript] 'Failed to print error: ', 'One of the sources for assign has an enumerable key on the prototype chain. This is an edge case that we do not support. This error is a performance optimization and not spec compliant.'
2016-02-29 22:59:05.577 [info][tid:com.facebook.React.RCTWebSocketModuleQueue][RCTSRWebSocket.m:543] SocketRocket: In debug mode.  Allowing connection to any root cert
2016-02-29 22:59:05.901 [info][tid:com.facebook.React.RCTWebSocketModuleQueue][RCTSRWebSocket.m:543] SocketRocket: In debug mode.  Allowing connection to any root cert

Oh, one other thing. The error doesn't happen when Scheme === Release and running on a device with a pre-bundled file. So now I can think of a couple of reasons why my app was working the other day...

UPDATE: Works the same with device and simulator. I got really confused with behavior with all the different conditions so I made the following table:

| Scheme | Static Bundle? | Chrome Dbg | Result |
| --- | --- | --- | --- |
| Debug | No | No | FAIL |
| Debug | No | Yes | PASS |
| Debug | Yes | No | FAIL |
| Debug | Yes | Yes | FAIL * |
| Release | No | No | FAIL |
| Release | No | Yes | FAIL |
| Release | Yes | No | PASS |
| Release | Yes | Yes | PASS |

_Notes:_

  • -- This case also fails when the workaround is in place with the following error in the debugger:
Uncaught NetworkError: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at
 'file:///var/mobile/Containers/Bundle/Application/70DABFF5-277F-490D-B9B1-8203D12E61E8/Accumulations.app/main.jsbundle' 
failed to load.

One of my additions to Array.prototype, like @AwesomeJerry, attaches to an array of AsyncStorage keys. The other one,

Array.prototype.shuffle = function() { ...}

is attached to this array when seen in Object.assign:

[ 'getContentSize',
  'calculateChildFrames',
  'endRefreshing',
  'scrollTo',
  'zoomToRect' ], 'shuffle'

So I've studied this one a bit. By testing for this array, I can stop in the debugger. (Note that in the debugger, 'shuffle' is not present as a key, so the bug is not triggered.) Here is the stack trace:

Object.assign (polyfills.js:39)
_genLookup (MessageQueue.js:278)
(anonymous function) (MessageQueue.js:261)
_genLookupTables (MessageQueue.js:260)
MessageQueue (MessageQueue.js:78)
(anonymous function) (BatchedBridge.js:15)
requireImpl (require.js:71)
_require (require.js:31)
(anonymous function) (NativeModules.js:14)
requireImpl (require.js:71)
_require (require.js:31)
(anonymous function) (JSTimers.js:15)
requireImpl (require.js:71)
_require (require.js:31)
setUpTimers (InitializeJavaS…pEngine.js:107)
(anonymous function) (InitializeJavaS…pEngine.js:205)
requireImpl (require.js:71)
requireImpl (require.js:39)
_require (require.js:31)
(anonymous function) (require-Initial…AppEngine.js:1)
messageHandlers.executeApplicationScript (debuggerWorker.js:18)
onmessage (debuggerWorker.js:33)

The calling function, _genLookup, has these local variables:

moduleName = "RCTScrollViewManager", methods = ["getContentSize", "calculateChildFrames", "endRefreshing", "scrollTo", "zoomToRect"]

@vjeux, I'm afraid this is all the time I can devote to this. I have no idea why an array prototype function would get attached to an array of RCTScrollViewManager methods or RCTAsyncLocalStorage methods and not other ones (and only when not in the debugger). Maybe something to do with the order modules are required in?

thanks

I'm not really sure what's going on here, this seems very unlikely that any of this is intended. I'm currently in paternity leave so won't dig into it but hopefully someone else can pick up where you left off and solve that mistery

Ah, well congratulations!

On Tue, Mar 1, 2016 at 4:29 PM, Christopher Chedeau <
[email protected]> wrote:

I'm not really sure what's going on here, this seems very unlikely that
any of this is intended. I'm currently in paternity leave so won't dig into
it but hopefully someone else can pick up where you left off and solve that
mistery


Reply to this email directly or view it on GitHub
https://github.com/facebook/react-native/issues/5507#issuecomment-190963051
.

@AwesomeJerry Please don't ever "polyfill" things that aren't in the standard :-( http://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/

Regardless, your polyfill shouldn't be using assignment to install itself - you want to use Object.defineProperty and set "enumerable" to false (in browsers that support ES5 property descriptors). I have a package that makes this easy.

Also - Object.assign should only be touching own properties. Perhaps your polyfills.js polyfill of Object.assign is not spec-compliant? I recommend https://www.npmjs.com/package/object.assign

Got that in mind already! Thanks anyway!

FWIW, got this error by being lazy and using object spread on a fetch response:

fetchResponse.json().then(json => {
  return { ...fetchResponse, json }; 
});

fixed by changing to the equally lazy

fetchResponse.json().then(json => {
    fetchResponse.json = json;
    return fetchResponse;
});

I'm using object.defineProperties, it doesn't work. Can somebody share code as of how to do it?

Was this page helpful?
0 / 5 - 0 ratings