Replace JS object by reference [refactor working code] - javascript

tl;dr Working code is at the bottom, can it be made more elegant.
I am building a metalsmith (static site generator) plugin. Metalsmith plugins always take the form:
const myPlugin = options => (files, metalsmith, done) => {
// Mutate `files` or `metalsmith` in place.
done()
}
I have written my plugin in a functional (immutable) style (with Ramda.js) and would like to completely overwrite files with the new value. The following is conceptually what I want, but won't work because it is reassigning files to updated not manipulating the files object on the heap.
const myPlugin = options => (files, metalsmith, done) => {
const updated = { foo: "foo" }
files = updated
done()
}
I have achieved the desired functionality, with the following, but it seems inelegant.
const myPlugin = options => (files, metalsmith, done) => {
const updated = { foo: "foo" }
deleteMissingKeys(old, updated)
Object.assign(old, updated)
done()
}
const deleteMissingKeys = (old, updated) => {
Object.keys(old).forEach(key => {
if (!updated.hasOwnProperty(key)) {
delete old[key]
}
})
}
Is there a better way to achieve these ends?

There is no super elegant way to do this in JavaScript, but this is not a bad thing. The truth is, well-written JavaScript should not need a behavior like this. There is no such thing as "pass-by-reference" in JavaScript, so it is natural that attempts like yours will be inelegant.
Shall a library need a behavior like this, instead of trying to work out a "hack" to pass-by-reference, there is a much more "javascriptonic" way to do it, which is pass around a wrapper object for the desired object:
// instead of trying to use a "hack" to pass-by-reference
var myObj = { /* ... */ };
function myFunc(obj) {
// your hack here to modify obj, since
// obj = { /* ... */ }
// won't work, of course
}
myFunc(myObj);
// you should use a wrapper object
var myWrapper = {
myObj: { /* ... */ }
}
function myFunc(wrapper) {
wrapper.myObj = { /* ... */ };
}
myFunc(myWrapper);
I strongly suggest you reconsider why you really want to do this in the first place.
But if you insist, your solution isn't that bad, I like how you used Object.assign() instead of a clunky for loop to add the fields.
I should add, though, that depending on the situation you might also want to set the prototype of the object to the intended value (if for example the old object was an instanceof Date and you want to make it a plain object, you certainly need to call Object.setPrototypeOf(old, Object.prototype)).

Related

Combining Functions to be more 'Functional' w/ JavaScript

I have some (pseudo) code that looks as follows
const { search, hash } = window.location // get search / hash from url
const tokenParts = queryParams(search || hash) // create an object
const { id_token, access_token } = tokenParts // extract from object
const isSessionValid = validateSession(id_token) // check exp time etc and return true / false
if (isSessionValid) {
store('id_token', id_token)
store('access_token', access_token)
window.history.replaceState(null, null, window.location.pathname)
}
I see this pattern a lot in the codebase I am working on, call a method with a value, assign that value to a variable, pass that variable into another method and assign the result to another variable....and so on until you have required value you require to move the program execution on.
From what I have read, functions should really, do-one-thing - rather than these massive, complex beats that can be difficult to test.
My question is, in the case of the pseudo code above, how can this be refactored into a function that returns the result of another function and so on?
I think I need something like
const sessionisValid = validateSession(window.location)
validateSession = ({search, hash}) => (queryParams(search || hash))=> hasTokenExp({id_token})
But I do not understand...
If this is how function programming / composition should work
Is the best approach
If I am just over complicating things
call a method with a value, assign that value to a variable, pass that variable into another method and assign the result to another variable... and so on until you have required value you require to move the program execution on.
This is totally fine. You're building on big function from multiple small functions - exactly how you should do it in functional programming. The variables are just necessary for the wiring.
What you have shown is not a massive, complex beast, it's very clear and clean code. It's easy to test all the individual small functions on their own if you want.
And because all those functions are pure and your variables are immutable, it's really easy to refactor your code from
const { search, hash } = window.location // get search / hash from url
const { id_token, access_token } = queryParams(search || hash)
const isSessionValid = validateSession(id_token) // check exp time etc
if (isSessionValid) {
store('id_token', id_token)
store('access_token', access_token)
window.history.replaceState(null, null, window.location.pathname)
}
to
function getSession({search, hash}) {
const { id_token, access_token } = queryParams(search || hash)
return {
id_token,
access_token,
isSessionValid: validateSession(id_token)
};
}
const { id_token, access_token, isSessionValid } = getSession(window.location);
if (isSessionValid) {
store('id_token', id_token)
store('access_token', access_token)
window.history.replaceState(null, null, window.location.pathname)
}
but unless you can use getSession in multiple places or you need this layer of abstraction for code organisation, the refactoring is unnecessary.
how can this be refactored to use function composition?
It can't really. Function composition works only when the result of one function are fed into another function and nowhere else. But in your code, access_token and id_token are used in multiple places. While it is possible to express this in pointfree style, it's complicated, slow and too abstract. Variables are much easier to use here.
I see this pattern a lot in the codebase I am working on
What exactly is the pattern? Whenever you see duplicated code, you might want to abstract out the common parts. But you need to be evaluate how many common parts and how many distinct parts there are in the code blocks. While always possible, often it's not worth it.

Having troubles implement my app in an Object Oriented manner

I've been coding JS for a while, but I've never did anything object oriented. I usually just defined all my variables at the top, and then just used them all. I kept hearing over and over to use OO, but now I can't do what I want and I can't get any help.
Here is a fiddle, along with semi identical code:
http://jsfiddle.net/zDeAJ/1/
var App = {
options: {
/* ------------------------------------
Options (PREFERABLY DONT CHANGE)
--------------------------------------- */
baseDomain : 'google.com',
apiVersion : '/api/v1'
},
state: {
current: App.options.baseDomain + App.options.apiVersion
}
}
So doing App.options.baseDomain (or this.options.baseDomain) won't work for me. What's the usefulness of defining Application level variables if I can't define other application level values based on them? I know this is a vague question but I really don't know what I'm asking... I just have a problem in that what I was easily able to accomplish with just a bunch of variables that held not only settings, but state within my application, is not so easy with my knowledge of Javascript OO patterns....
​
Edit: Alright, this is specifically what I want to do:
http://i.imgur.com/ak5YD.png
But I wasn't aware of the limitations... so I need a way around it, which sticks as close and elegant as possible to this implementation.
You can think of your approach as creating an "Instance" object called App.
Here's a slightly different approach.
function App () {
// Save a reference to the object
var that = this;
that.options = {
baseDomain: "google.com",
apiVersion: "/api/v1"
};
that.state = {
current: that.options.baseDomain + that.options.apiVersion
};
}
var myApp = new App();
// Write the current state to the screen
document.write(myApp.state.current);
Here's the JSFiddle: http://jsfiddle.net/zDeAJ/1/
Hope this helps!
Your question is quite generic; you should be more specific about what you're trying to accomplish.
That aside, read the documentation on objects;
Taken from w3schools:
With JavaScript you can define and create your own objects.
There are 2 different ways to create a new object:
1. Define and create a direct instance of an object.
2. Use a function to define an object, then create new object instances.
Way 1:
personObj=new Object();
personObj.firstname="John";
personObj.lastname="Doe";
personObj.age=50;
personObj.eyecolor="blue";
Way 2:
function person(firstname,lastname,age,eyecolor)
{
this.firstname=firstname;
this.lastname=lastname;
this.age=age;
this.eyecolor=eyecolor;
this.changeName=changeName;
function changeName(name) {
this.lastname=name;
}
}
Not one of you answered my question.... I thought about it a little... I could use a named function inside of the literal to access it... and if I wanted (not necessary) I could even assign it back to the options object
http://jsfiddle.net/zDeAJ/9/
var App = {
options: {
/* ------------------------------------
Options (PREFERABLY DONT CHANGE)
--------------------------------------- */
baseDomain : 'google.com',
apiVersion : '/api/v1',
blah: ''
},
state: function(){
this.options.blah = this.options.baseDomain + this.options.apiVersion;
}
}
App.state();
console.log(App.options.blah);
​
JavaScript is an interpreted language. That means your code is evaluated from the inside out or the most inner expression is evaluated and passed to the next outer expression.
In your example the value of options get's evaluated first and next the value of state. The problem is that you can't access the associative array of App before it is fully evaluated, wich is not the case during the evaluation of the value of state.
EDITED
Sorry for not answering correctly. Here is a refined approach from your second:
var App = {
options: {
/* ------------------------------------
Options (PREFERABLY DONT CHANGE)
--------------------------------------- */
baseDomain : 'google.com',
apiVersion : '/api/v1',
blah: ''
},
blah: function(){
return App.options.baseDomain + App.options.apiVersion;
}
}
console.log(App.blah());
You could do the following (in JavaScript, functions are objects):
function App () {
// Save a reference to the object
this.options = {
baseDomain: "google.com",
apiVersion: "/api/v1"
};
this.state = {
current: this.options.baseDomain + this.options.apiVersion
};
}
var myApp = new App();
console.log(myApp);

JS extend functionality of a method

I'm trying to extend the functionality of some methods of the 2dcontext object, however I can't get it to work the way I want: I want to override a method, but I want to call the original method from the overridden method like this:
//First get the original context
var ctx = canvas.getContext("2d");
//Create a class which uses ctx as it's prototype
var ExtendedContext = function (){};
ExtendedContext.prototype = ctx;
//And extend a method
ExtendedContext.prototype.fillRect = function(x, y, width, height) {
//Do some stuff
this.prototype.fillRect(x, y, width, height); //Doesn't work
//Do some more stuff
};
How can I call the original fillRect method from inside my own method?
You can store the reference of the original function just like that:
var oldFillRect = ctx.fillRect;
and then call it like
ExtendedContext.prototype.fillRect = function() {
//Do some stuff
oldFillRect.apply(this, arguments);
//Do some more stuff
};
This technique is sometimes called 'duck punching' or a 'function hook'. In this particular instance, you should also be able to use the Object.getPrototypeOf method to get the original function reference. This would look like
ExtendedContext.prototype.fillRect = function() {
//Do some stuff
Object.getPrototypeOf(ExtendedContext.prototype).fillRect.apply(this, arguments);
//Do some more stuff
};
So you don't even need to store a reference.
No need to save the old names in a separate object, use closures :
ExtendedContext.prototype.fillRect = (function () {
var oldf = ExtendedContext.prototype.fillRect;
return function () {
//Do some stuff
oldf.apply (this, arguments);
//Do some more stuff
};
}) ();
If you have a bunch to do this might help :
function extend (fnc) {
var mthd = (fnc.toString ().match (/^function\s+(\w+)\s*\(/) || ['', ''])[1];
if (mthd in ExtendedContext.prototype)
throw ('ExtendContext method ' + mthd + 'does not exist');
ExtendedContext.prototype['_' + mthd] = ExtendedContext.prototype[mthd];
ExtendedContext.prototype[mthd] = fnc;
}
Then you can call extend as follows
extend (function fillrect () {
// Do some stuff
this._fillrect.apply (this, arguments);
// Do some more stuff
});
To refer to the old method use its name prefixed with '_'
I'm a few months late, but I'm using a fairly simple design to accomplish this functionality.The structure of our JavaScript runs off of a global object to keep our code secured from global vars.
For each page/usercontrol we are modifying our global object to hold a new object, but some code needs different functionality in different places, requiring extension methods. We don't want to duplicate code and redefine the whole object for the extended instance, and we don't want the code to care how it is being extended.
Instead of punching a duck until it does what you want it to, why not create a generic extension method? Using our case, here is an example:
// Using a Global JavaScript object:
GlobalNameSpace.ExtensionFunction = function(oParam1, oParam2, oParam3)
{
/// <summary>All parameters are optional</summary>
return; // For instances when it is not being overwritten, simply return
}
//In the Code to be extended:
GlobalNameSpace.Control.ControlFunction(oSender, oArgs)
{
///<summary>Control's function</summary>
// Function-y stuff..
GlobalNameSpace.ExtensionFunction(oSender, oArgs);
}
//and finally in the code to extend the functionality
GlobalNameSpace.Page.Init
{
///<summary>Initializes the page</summary>
// redefine the extension function:
GlobalNameSpace.ExtensionFunction = function(oSender, oArgs)
{
// Call the extension function, or just code the extension here
GlobalNameSpace.Page.Function(oSender, oArgs);
}
}
The short coming of this method is if you want to do this for multiple objects at a time, at which point it may be a better idea to move an extension method into the code you are specifically wanting to extend. Doing this will make that extension code less generic, but that can be decided according to your needs.

Javascript OOP events

I want to create an object that can parse a certain filetype. I've looked at some of the files in the File API and I want my object to work about the same. So basically, what I want is this:
A function, called CustomFileParser. I want to be able to use it as the following:
var customFileParser = new CustomFileParser();
customFileParser.parsed = paresed;
customFileParser.progress = progress;
customFileParser.parse(file);
function parsed(event){
//The file is loaded, you can do stuff with it here.
}
function progess(event){
//The file load has progressed, you can do stuff with it here.
}
So I was thinking on how to define this object, but I'm not sure how to define these events and how I should do this.
function customFileParser(){
this.parse = function(){
//Do stuff here and trigger event when it's done...
}
}
However, I'm not sure how to define these events, and how I can do this. Anyone can give me a hand?
Javscript is prototype-based OOP language, not class-based like most other popular languages. Therefore, the OOP constructs are a bit different from what you might be used to. You should ignore most websites that try to implement class-based inheritance in JS, since that's not how the language is meant to be used.
The reason people are doing it because they are used to the class-based system and are usually not even aware that are alternatives to that, so instead of trying to learn the correct way, they try to implement the way that they are more familiar with, which usually results in loads and loads of hacks or external libraries that are essentially unnecessary.
Just use the prototype.
function CustomFileParser(onParsed, onProgress) {
// constructor
this.onParsed = onParsed;
this.onProgress = onProgress;
};
CustomFileParser.prototype.parse = function(file) {
// parse the file here
var event = { foo: 'bar' };
this.onProgress(event);
// finish parsing
this.onParsed(event);
};
And you can use it like so
function parsed(event) {
alert(event);
}
function progress(event) {
alert(event);
}
var customFileParser = new CustomFileParser(parsed, progress);
var file = ''; // pseudo-file
customFileParser.parse(file);
From what it sounds to me i think you need your program to look like this
function customFileParser( onparse , progress){
this.onparse = onparse;
this.progressStatus = 0;
this.progress = progress;
this.parser = function (chunk)
}
this.parse = function(){
// Do stuff of parsing
// Determine how much data is it
// Now make a function that parses a bit of data in every run
// Keep on calling the function till the data is getting parsed
// THat function should also increase the percentage it think this can be done via setTimeout.
// After every run of the semi parser function call the progress via something like
this.parser();
if(progressStatus <100){
this.progress(this.progressStatus);
}else{
this.parsed();
}
}
}
and u can create instance of that object like
var dark = new customFileParser( function () { // this tells what to
do what parsed is complete } , function (status) { // this tells what
to do with the progress status } ) ;
using the method i suggested. you can actually define different methods for all the instances of the object you have !

A function and a form of encapsulation?

I'm sorry if this question has been asked before, but I'm not even sure what search terms to use to find the answer and when I try to search I never get anything specific to this question.
I'm using Javascript and I am wondering if it is possible to do something like this:
find(x); // find a document (for example)
find.inFolder(y); // find a folder's documents (for example)
In other words, can I have a function that can also be used as an object/class? I know I could run find() once and return a hash so that find.inFolder() would work, but I'm hoping there's a way where I could continue to call find().
Can it be done with prototype? (my "prototype" knowledge is very limited)
function find() {}
find.prototype.inFolder = function() {}
Can it be done inside a hash? [I know this code doesn't work]
var find = {
() : function() {},
inFolder : function() {}
}
To push it even further, is there a way to have the results of .inFolder() be sent to the find() function this way:
find().inFolder();
I know you might say that I don't understand the concept of javascript, and you'd be mostly correct, but I've seen people do some pretty amazing stuff with JS so I thought I'd ask the pros out there.
Thanks in advance for any help.
What you're describing is a Fluent interface (if you want something to search for). You could accomplish something like what you're trying to achieve like this:
var find = function() {
this.inFolder = function() {
return this; // Although to stop chaining, you could return nothing here.
};
return this;
};
find().inFolder(); // .inFolder().inFolder()...
This is a great pattern, especially when leveraged in projects like jQuery:
$("#element").find(".child_element").first();
Each call returns a jQuery object with .find(), .first() and many other functions, which lets you write intuitive and fluid code.
I kind of liked your find().inFolder() example, so here's an expanded version:
var find = function(file) {
this.folders = {
"Documents": ["Foo.txt", "Bar.txt"],
"Downloads": ["File.exe"],
"Misc": ["Picture.jpg"]
};
this.file = file;
this.inFolder = function(folder) {
var files = this.folders[folder];
return files.indexOf(this.file) >= 0;
};
return this;
};
alert(find("Foo.txt").inFolder("Documents")); // True
alert(find("File.exe").inFolder("Downloads")); // True
alert(find("Picture.jpg").inFolder("Downloads")); // False
http://jsfiddle.net/andrewwhitaker/TCdTd/
You can assign, a function to a member of another function:
find = function(x) { .... }
find.inFolder = function(y) { ... }
jsFiddle.
I'm not sure I understand the question however.

Categories