Purpose of _.extend/_.assign? - javascript

I've seen quite a few tutorials or code examples where the developer used either Underscore's _.extend method or Lodash's _.assign method when a simply adding the property would have sufficed, it's always confused me, what is the benefit of using extend/assign instead of simply adding the property? There are plenty of times where I can see the benefits of using these methods, when adding multiple properties from another object for instance but most often I've seen it used as in the example below where I don't see any benefit.
Is there a benefit that I am not aware of for the following code instead of assigning the property?
http://tech.pro/tutorial/1734/building-decoupled-javascript-applications-with-postaljs
var Weather = function() {
this.channel = postal.channel( "weather" );
this.channel.subscribe( "fetch", this.fetch ).withContext( this );
};
_.extend(Weather.prototype, {
fetch: function( city ) {
$.ajax({
url: "http://openweathermap.org/data/2.1/find/name?q=" + city + "&units=imperial",
dataType: "jsonp",
success: _.bind(function( data ) {
this.channel.publish( "fetched", data.list[ 0 ] );
}, this )
});
}
});
For instance, couldn't the above code be rewritten thusly:
Weather.prototype.fetch = function(...){...}
Or is there a negative to this?

It exists for the same reason jQuery has $.extend (including an npm port) and it has nothing to do with performance: to add one object's properies to a another object, thereby extending one with the other. Lodash' version allows for some more fine-grained control over the merge process using a customizer function.
Extending objects has a couple of uses, of which one is stated by the jQuery developers on writing plugins:
An improvement we can, and should, make to the code above is to expose the default plugin settings. This is important because it makes it very easy for plugin users to override/customize the plugin with minimal code. And this is where we begin to take advantage of the function object.
// Plugin definition.
$.fn.hilight = function( options ) {
// Extend our default options with those provided.
// Note that the first argument to extend is an empty
// object – this is to keep from overriding our "defaults" object.
var opts = $.extend( {}, $.fn.hilight.defaults, options );
// Our plugin implementation code goes here.
};
// Plugin defaults – added as a property on our plugin function.
$.fn.hilight.defaults = {
foreground: "red",
background: "yellow"
};
In the above example you can clearly see that with are dealing with a preset object with properties, which needs to be extended or even overwritten by an unknown object with unknown properties, because that object is out of the plugin-developer's control
Sometimes we simply don't know which properties are on the extension object, sometimes it just makes things more readable and sometimes it is just to cumbersome to do it manually especially if you need a deep merge.
Another application is where you want to simulate a simple inheritance hierarchy:
// very trivial example:
var Super = { superFoo: function() {} };
var Sub1 = { sub1Foo: function() {} };
var Sub2 = { sub2Foo: function() {} };
$.extend(Sub1, Super) // now Sub1 has Super powers
$.extend(Sub2, Super) // now Sub2 has Super powers too

In many cases, using Object.assign() (or the library-provided equivalent) lets one write in a more functional style. Instead of using multiple statements just to add a single property to an object, you can do everything in one big expression.
Procedural:
function doThing(options) {
options.x = 5;
return _doThing(options);
}
Functional:
function doThing(options) {
_doThing(Object.assign(options, {x: 5}));
}
Also, if used with an empty object it idiomatically creates a shallow copy so as not to disturb a passed-in object in ways that might confuse the caller:
function doThing(options) {
_doThing(Object.assign({}, options, {x: 5}));
}

Related

Preserve prototypes in ADVANCED mode

I need to compile my code with closure compiler in ADVANCED mode. I also need to keep prototypes of my objects in my application because I'm looping on Javascript objects prototypes. Trying to get both results in some ReferenceError when starting the application.
When compiling with ADVANCED mode, some prototypes are removed and replaced by a function that is using an object parameter in order to recover "this" keyword. This is due to crossModuleCodeMotionNoStubMethods attribute of CompilerOptions.java.
Example of code before compilation :
function MyClass() = { // Some code }
MyClass.prototype.someFunc = function() { // Some code calling someOtherFunc };
MyClass.prototype.someOtherFunc = function(someParam) { // Some code };
Example of code after compilation :
function MyCompiledClass = { // Some code }
MyCompiledClass.prototype.someCompiledFunc = function() { // Some code calling someOtherFunc }
function someOtherCompiledFunc(that, someParam) = { // Some code }
I first tried to use #this and #preserve JSDoc tags to solve the problem, without success. Using #export is not a solution, because functions will then keep their original names.
I've found two options to solve my problem for now :
Refactor the code as seen here
Build a custom version of Closure Compiler as seen here
Option 1 will need to much modifications in my code and will make it less readable, if it's the only solution, I will have a go for this one.
Option 2 seems to be a nice workaround, but I've read that some changes on CompilationLevel.java may violate some core assumptions of the compiler. Can someone tell me if by modifying setCrossModuleMethodMotion from true to false, will it still respect all core assumptions of the compiler ?
I'm currently building a custom version of the compiler to check if the code is compiling properly, but even if the code is usable, I need to be sure it will be properly obfuscated.
Thank you !
The specific optimization pass you are referring to is DevirtualizePrototypeMethods. The best way to block the optimization would be to use the #nocollapse annotation. It will allow your method to be renamed but not allow it to be removed from the prototype.
I'm not 100% sure it will work for this case, but if it doesn't it should and you can file an issue to have that fixed: https://github.com/google/closure-compiler/issues
You can export constructors and prototype properties in the same way.
For example:
MyClass = function(name) {
this.myName = name;
};
MyClass.prototype.myMethod = function() {
alert(this.myName);
};
window['MyClass'] = MyClass; // <-- Constructor
MyClass.prototype['myMethod'] = MyClass.prototype.myMethod;
As in https://developers.google.com/closure/compiler/docs/api-tutorial3

JavaScript: Is the nesting of constructor instances inside a constructed 'wrapper' problematic?

Hopefully this question won't be flagged as too subjective but I'm newish to OOP and struggling a bit when it come to sharing data between parts of my code that I think should be separated to some extent.
I'm building a (non-geo) map thing (using leaflet.js which is superduper) which has a map (duh) and a sidebar that basically contains a UI (toggling markers both individually and en masse, searching said marker toggles as well as other standard UI behaviour). Slightly confused about organisation too (how modular is too modular but I can stumble through that myself I guess). I am using a simple JSON file for my settings for the time being.
I started with static methods stored in objects which is essentially unusable or rather un-reusable so I went for nested constructors (kinda) so I could pass the parent scope around for easier access to my settings and states properties:
function MainThing(settings) {
this.settings = options;
this.states = {};
}
function SubthingMaker(parent) {
this.parent = parent;
}
SubthingMaker.prototype.method = function() {
var data = this.parent.settings.optionOne;
console.log(data);
this.parent.states.isVisible = true;
};
MainThing.prototype.init = function() {
this.subthing = new SubthingMaker(this);
// and some other fun stuff
};
And then I could just create and instance of MainThing and run MainThing.init() and it should all work lovely. Like so:
var options = {
"optionOne": "Hello",
"optionTwo": "Goodbye"
}
var test = new MainThing(options);
test.init();
test.subthing.method();
Should I really be nesting in this manner or will it cause me problems in some way? If this is indeed okay, should I keep going deeper if needed (maybe the search part of my ui wants its own section, maybe the map controls should be separate from DOM manipulation, I dunno) or should I stay at this depth? Should I just have separate constructors and store them in an object when I create an instance of them? Will that make it difficult to share/reference data stored elsewhere?
As regards my data storage, is this an okay way to handle it or should I be creating a controller for my data and sending requests and submissions to it when necessary, even if that data is then tucked away in simple JSON format? this.parent does really start to get annoying after a while, I suppose I should really be binding if I want to change my scope but it just doesn't seem to be an elegant way to access the overall state data of the application especially since the UI needs to check the state for almost everything it does.
Hope you can help and I hope I don't come across as a complete idiot, thanks!
P.S. I think the code I posted works but if it doesn't, its the general idea I was hoping to capture not this specific example. I created a much simpler version of my actual code because I don't want incur the wrath of the SO gods with my first post. (Yes, I did just use a postscript.)
An object may contain as many other objects as are appropriate for doing it's job. For example, an object may contain an Array as part of its instance data. Or, it may contain some other custom object. This is normal and common.
You can create/initialize these other objects that are part of your instance data in either your constructor or in some other method such as a .init() method whichever is more appropriate for your usage and design.
For example, you might have a Queue object:
function Queue() {
this.q = [];
}
Queue.prototype.add = function(item) {
this.q.push(item);
return this;
}
Queue.prototype.next = function() {
return this.q.shift();
}
var q = new Queue();
q.add(1);
q.add(2);
console.log(q.next()); // 1
This creates an Array object as part of its constructor and then uses that Array object in the performance of its function. There is no difference here whether this creates a built-in Array object or it calls new on some custom constructor. It's just another Javascript object that is being used by the host object to perform its function. This is normal and common.
One note is that what you are doing with your MainThing and SubthingMaker violates OOP principles, because they are too tightly coupled and have too wide access to each other internals:
SubthingMaker.prototype.method = function() {
// it reads something from parent's settings
var data = this.parent.settings.optionOne;
console.log(data);
// it changes parent state directly
this.parent.states.isVisible = true;
};
While better idea could be to make them less dependent.
It is probably OK for the MainThing to have several "subthings" as your main thing looks like a top-level object which will coordinate smaller things.
But it would be better to isolate these smaller things, ideally they should work even there is no MainThing or if you have some different main thing:
function SubthingMaker(options) {
// no 'parent' here, it just receives own options
this.options = options;
}
SubthingMaker.prototype.method = function() {
// use own options, instead of reading then through the MainThing
var data = this.options.optionOne;
console.log(data);
// return the data from the method instead of
// directly modifying something in MainThing
return true;
this.parent.states.isVisible = true;
};
MainThing.prototype.doSomething = function() {
// MainThing calls the subthing and modifies own data
this.parent.states.isVisible = this.subthing.method();
// and some other fun stuff
};
Also to avoid confusion, it is better not to use parent / child terms in this case. What you have here is aggregation or composition of objects, while parent / child are usually used to describe the inheritance.

Convert a large javascript file into multiple files

My question: How would one best go about breaking a large, monolithic javascript object literal into multiple, discrete, files?
I have a single javascript file that consists of an object literal with many methods attached to it. It's getting quite long and I want to break it into smaller parts that can more easily be managed.
I've heard I can use AMD or CommonJS to organize things, I've heard I should use RequireJS, that I should use Webpack or Browserify, that I should use any number of other tools/techniques. After looking at these things I am confused as to what the best approach is.
How would you do it? How would you take a single object literal consisting of a few thousands lines of javascript (made up of functions like "search" and "login" and "user") and reorganize it into multiple files that are more easily dealt with by a group of developers? The single, giant file thing is just getting to unwieldy and the options seems to varied and unclear. This is a fairly simple app that uses vanilla JS, a little jQuery and sits on top of a Grails backend.
I think the question is pretty clear but if you really need code to look at here is an example of the sort of object literal I am talking about:
var myObj = {
foo: "one",
bar: "two",
baz: false,
deez: -1,
login: function() {
// lots and lots of code
},
user: function() {
// lots and lots of code
},
beers: function() {
// lots and lots of code
},
varieties: function() {
// lots and lots of code
}
init: function() {
myObj.login.init();
myObj.user.init();
// lots of jQuery document.ready stuff
}
}
myObj.init();
You will a lot of suggestions and approaches to solve your problems, and I can't say any of them are wrong, they are just different.
My approach would be to use ES6 and its native module support.
To accomplish this I always use my own boilerplate named fabric which uses Webpack to compile the modules, Browsersync to help you on your development, Tape for unit testing, SASS for your CSS preprocessing, and Babel to compile a compatible ES5 bundle that you can easily use in your application.
Now, the way to use the ES6 modules is something like this with named exports:
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
Or using default exports:
//------ myFunc.js ------
export default function () { ... };
//------ main1.js ------
import myFunc from 'myFunc';
myFunc();
You can learn more about ES6 modules at 2ality
Here's the pattern I use:
When possible, break concepts into their own sub-object
Regardless of sub-objects or not, declare any non-broken-up properties first, then add to it as needed
If the files are across multiple files and you do not wish to use sub-objects per-file, use a temporary object to hold additional properties, and then extend the original.
Sample:
var myObj = {
foo: "one",
bar: "two",
baz: false,
deez: -1
}
myObj.login = function() {
// lots and lots of code
};
myObj.user = function() {
// lots and lots of code
};
myObj.drinks = {
beer: function() {},
wine: function() {},
sunnyDelight: {
drinkIt: function() {},
burp: function() {}
}
};
myObj.init = function() {
myObj.login.init();
myObj.user.init();
// lots of jQuery document.ready stuff
}
myObj.init();
Note that "drinks" is a concept unto itself, containing multiple properties and methods. Your concepts might be something like "ui", "utils", "data" or whatever the role of the contained properties happens to be.
For the extend point I made, there's not much code needed there either
// "utilities.js"
var myObj = {
// a bunch of properties and/or methods
};
myObj.moreStuff = "more stuff!";
and then in another file you have two choices. Either add to the object without overwriting it (you will need the dot-notation to do this):
// "ui.js"
var myObj = myObj || {};
// adds the render object to the existing myObj
myObj.render = {
header: function() {},
dialogBox: function() {}
}
The above works particularly well if you sub-divide your concepts... because you can still have fairly monolithic objects that will not trample over the rest of myObj. But maybe you want to add directly to myObj without trampling and without subdividing concerns:
// "ui.js"
var myObj = myObj || {};
// ultimately, the CONTENTS of this object get merged into the existing myObj
var myObjSupplement = {
header: function() {},
dialogBox: function() {},
heroBiscuit: "A yummy biscuit made from heroes!"
}
// using jQuery here, but it's not the only way to extend an object
$.extend(myObj, myObjSupplement)
I don't see TOO many opportunities to use the above, since myObjSupplement is now in the global namespace and defeats the purpose of limiting additions to the global namespace, but it's there if you need it.
[edited to add: ]
It might not go "without saying" as I thought-- but dividing into many different files probably works best if you have a build process in place that can concatenate them into one file suitable for minifying. You don't want to have 100 or even 6 separate files each requiring a synchronous HTTP call to fetch.
There are more modern and possibly 'better' approaches with technologies like AMD/RequireJS... but if the question is, "how do I divide up an object literal into several files", the above answer I've given is one I can stand behind.
While there are automated ways of doing this I'm sure, and I am also interested in seeing the answers this question gets, I would recommend simply going in and moving the method definitions into different files and calling the functions normally method(param); and linking the files to your html page.
This would serve multiple purposes, including the one you are looking to acheive of breaking your code down into more manageable modules. Among those purposes also include the fact that instead of having those definitions written to memory for every instance of the object, you would only define it once and make references to it whenever you need it.
Sorry I can't be of more help without actually seeing the JavaScript File.
You can reference this stack overflow example if you need more guidance in achieving this.
You don't have to have all of the methods defined in your objects or classes, it's better to modularize these methods into different files and use the <script src="path/to/your/script.js"> </script> tags to include them all with your html/php page

dojo 1.9: what annotation does declare.safeMixin add?

I have been reading through the dojo 1.9 documentation about declare.safeMixin(), focusing on the difference between it and lang.mixin.
Here is the explanation I found...
safeMixin() is a function defined in dojo/declare. It has the same functionality as dojo/_base/lang::mixin(), but additionally it annotates all copied methods compatibly with dojo/declare. This decoration can affect how this.inherited() works in mixed-in methods.
I can follow the example but it doesn't really explain exactly what is added and where, can anyone give any further examples of what annotation is added to each copied method?
So to be clear, I'm not asking for an explanation of inheritance, I'm just asking specifically about the annotations added by using declare.safeMixin() instead of lang.mixin.
Using safeMixin allows you to mix functions into an instance that can take advantage of this.inherited the same way that prototype methods defined using declare can.
For example, the following will log 2 messages:
require([
"dojo/_base/lang",
"dojo/_base/declare"
], function(lang, declare){
var A = declare(null, {
method: function () {
console.log('method in prototype');
}
});
var a = new A();
declare.safeMixin(a, {
method: function () {
this.inherited(arguments);
console.log('method in instance');
}
});
a.method();
});
Without safeMixin, you wouldn't be able to call this.inherited(arguments) from the overriding method (at least, not without additional parameters) - you'd end up getting an error:
Error: declare: can't deduce a name to call inherited()
safeMixin adds the nom property to functions that are mixed in to the target. This property is set to the key from the source object that the function was assigned to. e.g. if you call declare.safeMixin(target, { foo: function() {} }), the nom property for that function is "foo". This is necessary for this.inherited(arguments) to automatically figure out that it should call the parent "foo". The alternative to using safeMixin would be to explicitly specify the name of the parent function: this.inherited('foo', arguments);.

Extending javascript object and it's properties

Hello I know that this question has been asked many times but there are too many opinions and arguments. I don't have the greatest experience to validate the answers so here it goes I'll explain what I'm looking for and perhaps you can point me to the right direction.
In my app I have created an object with some methods, most of them have a set of predefined default values, like so:
module.exports = {
submit: function(options) {
var defaults = {
_id: 1453,
text: 'Some text',
dataObj:{
links: 3532,
arr: ['James','Paul','Lina'],
},
dims:{
width: getClientWidth(),
height: getClientHeight()
}
}
options.extend(defaults);
return sendData(defaults);
}
// other similar methods - functions
};
What I'm interested in is to extend the properties and attributes of the defaults local variable. As you can see defaults is a complex structured object. Keep in mind that options structure might be even more complex. So A simple shallow merge / copy might not be ideal here if I'm not mistaken.
Usage as you can imagine:
var app = {
// stuff
}
app.fn = require('common/lib.js');
app.initialize(function(){
var settings = {
// hell here
}
app.fn.submit(settings)
})
Thank you in advance.
PS. No libraries are being used and I'm interested of in a pure javascript implementation of extend() function in any way.
Similar question asked here:
deep extend (like jQuery's) for nodeJS
Just copy the extend function from the accepted answer into your project, so that it is available within the correct scope. Then use it like so:
options = extend(true, defaults, options);
Your settings object could look something like the following and will be merged on top of the defaults correctly:
var settings = {
text: "Other text",
dataObj:{
links: 3531
}
};

Categories

Resources