3

I am working on a project where I have to attach a few utility functions to Javascript Object object as follows:

function isEmpty(a, b) {...}
Object.prototype.isEmpty = isEmpty;

Now the problem i am facing is, since I am working with react, I am guessing the above code is also attaching the isEmpty function to the constructed Components. And this works fine as long as I don't use the native html tags i.e. div, span inside my components which is not possible. I get the following warning

Warning: Unknown prop `isEmpty` on <div> tag. 
Remove these props from the element. For details, see
https://facebook.github.io/react/warnings/unknown-prop.html

when I use the native html tags. Is there any way to augment the Object object without getting this error in react?

Nahush Farkande
  • 5,290
  • 3
  • 25
  • 35
  • How are you implementing the component? Can you share your HTML or component that loads the component in question? – Brett DeWoody Nov 22 '16 at 12:15
  • It happens even if I render a simple div i.e `
    Hello world
    ` inside ReactDOM render
    – Nahush Farkande Nov 22 '16 at 12:27
  • Can you share the code? – Brett DeWoody Nov 22 '16 at 12:34
  • 2
    Do you really have to augment `Object`? http://stackoverflow.com/questions/14034180/why-is-extending-native-objects-a-bad-practice – Ruan Mendes Nov 22 '16 at 12:34
  • 1
    The problem is that an object extension like this is enumerable. You need to use "defineProperty" see -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty BTW: this is still a bad idea – Martin Bonetti Nov 22 '16 at 12:39
  • Hmm.. i had no idea that augmenting the native javascript object was a bad practice. Anyways, the reason i am trying to augment `Object` is because i want the functions to be available to all the objects i interact with. I am aware that i can simply define a function which would do what i want. But the functions i am creating would be more readable if i augmented Object. eg. a function which checks whether an object is empty(`isEmpty`). Now considering i have a object `var a = {}`, I believe `a.isEmpty()` would be more readable than `isEmpty(a)`. Out of simple curiousity, can this be done? – Nahush Farkande Nov 22 '16 at 12:43
  • Again `isEmpty` is just an example in the above comment – Nahush Farkande Nov 22 '16 at 12:44
  • @Brett DeWoody. I can but the reason I am not is because the code is quite lasrge to be completely frank, and in my opinion quite unnecessary, In this situation. Even if i manage to render `
    Hello world
    ` without the above error, that should be more than enough to solve my problem
    – Nahush Farkande Nov 22 '16 at 12:46
  • 1
    Just do what @bonoparte (why don't you post it) said, this is correct answer. – dfsq Nov 22 '16 at 12:48
  • The `isEmpty` kind of makes sense if you understand why augmenting is bad and you're OK with it. However, `Object.prototype.sum = sum;` doesn't make any sense, that function won't use any of the context from `this`. – Ruan Mendes Nov 22 '16 at 14:09
  • @JuanMendes I guess you're right. Updating the question – Nahush Farkande Nov 23 '16 at 04:32

3 Answers3

1

When you write jsx tags in react it gets transpiled to objects (React elements).

So

<div id="test">
</div>

is transformed into following object -

var divElement = React.createElement("div", { id: "test" });

Now since you are attaching

function sum(a, b) {...}
Object.prototype.sum = sum;

It gets attached to every objects present.

May be you should consider providing a Util.js which will contain all utility methods and do not attach to Object prototype. Because It can cause undesired side effects.

You can import Util.js where ever you need and use those methods.

e.g. -

module.exports = {
    sum(a, b) {...}
};
WitVault
  • 23,445
  • 19
  • 103
  • 133
  • Yes I guess I would have to do that if my approach doesn't work and to be completely frank i am inclined towards this approach now that i know that augmenting is a bad practice. Thanks! :) – Nahush Farkande Nov 22 '16 at 12:47
1

The problem is that an object extension like this is enumerable. You need to use defineProperty

BTW: this is still a bad idea

Martin Bonetti
  • 452
  • 4
  • 9
0

Problem

All JSX elements are first created as objects (WitVault explains how JSX is transpiled to plain JS that can run in the browser). React takes those objects and their properties that React supports and maps them to DOM elements. If there are properties that React does not know about, it will show a warning because it's likely a case of either "you don't know what you are doing" or "you made a typo", and therefore you won't get the behavior that you expect.

Since you edited the prototype of Object, all objects, also those created by React, get the property sum, and for primitive html elements React does not know how to map a sum property.

As Juan Mendes pointed out, extending native objects is bad practice. If you extend Object.prototype in a React project you really cant avoid the problem you are experiencing.

Solution 1: Export/Import util function

Since React comes with browserify you can instead import utility methods. This has two advantages:

  • You don't need to extend native objects
  • You clearly express where the methods used come from, be cause they have an import statement in the file where it's used.

In ES6

// util/objectSum.js
export default function objectSum(object) { ... };

// anotherFile.js
import objectSum from 'utils/objectSum.js'; // assuming utils/ is directly under the root path of your project (root path can be configured in webpack.config if you use webpack)

const object = ?; // the object you want to sum
const sum = objectSum(object);

In ES5

// util/objectSum.js
module.exports = function(object) { ... };

// anotherFile.js
var objectSum = require('utils/objectSum.js'); // assuming utils/ is directly under the root path of your project (root path can be configured in webpack.config if you use webpack)

const object = ?; // the object you want to sum
const sum = objectSum(object);

Solution 2: Using ES6 classes

In ES6 you can also create a class with the sum method. Here's an example:

class NumberList {
    constructor(arrayOfNumbers) {
        this.numbers = arrayOfNumbers;
        this.sum = this.sum.bind(this);
    }

    sum() {
        return this.numbers.reduce((sum, next) => sum + next, 0);
    }
}

const numberList = new NumberList([1, 2, 3]);
numberList.sum(); // -> 6
Community
  • 1
  • 1
ArneHugo
  • 6,051
  • 1
  • 26
  • 47