Change meaning of ["foo"] in Javascript? - javascript

I'd like to make foo["bar"] return the bar field value normally, but if it doesn't exist, look it up in another object to find it there. Is it possible to replace how [] works?
Why? I am porting a 6 year old Javascript application to AngularJS. In the existing app, there's (of course) one global variable (let's call it i2) that's used as a namespace that has everything in the app attached to it.
i2.models.fooModel.bar += 1; //and the rest of the app is similar
If that's not enough responsibility, i2 is also used as a registry of application "cells" like so:
var myCell = i2["MyCell"];
I'm breaking the global's fields into AngularJS services. The cell lookup feature is also broken out into another servicer "cell registry" service. Since this application has existing plugins that we'd like to be backwards compatible with, I'd like the code in the existing plugins like:
var myCell = i2["MyCell"];
... to still work (though deprecated). Is there a way I can replace the [] function in i2 to look up the field in i2, and if it doesn't exist, look it up in another object (the cell registry)?

No, you cannot directly and literally change the meaning of
i2["MyCell"]
because this is the design of the language and that typically can't be changed (and it would be terrible if you could). However, you can do something like this:
function lookupVar(key) {
var value = i2[key];
if(typeof value !== "undefined") {
return value;
}
// do whatever you want to do now that it couldn't be found
}
var myCell = lookupVar("MyCell");
Of course this can be extended to handle other things than just a single variable i2. It might also not be needed at all and a simple
var myCell = typeof i2["MyCell"] !== "undefined" ? i2["MyCell"] : somethingElse["MyCell"];
might be enough (though it contains annoying duplication). If you know that if they key exists in i2["MyCell"], it won't be a falsy value (0, "", false, …), then this will suffice
var myCell = i2["MyCell"] || somethingElse["myCell"];
Though it's not very future-proof.

Yes, you can use getters (don't work in IE8) or Proxy (not recommended for production code)...
Is there a way I can replace the [] function in i2 to look up the field in i2, and if it doesn't exist, look it up in another object (the cell registry)?
Or just think about prototypes.

Related

Extract SOAP/XML namespaces as a list of key/value pairs using JavaScript

Here's a SOAP response that I want to use javascript to extract a list of key value pairs where the key is the local namespace element prefix, such as:
SOAP-ENVns98ns70
and the value is the namespace definition, such as:
http://schemas.xmlsoap.org/soap/envelope/urn:vertexinc:enterprise:platform:security:messages:1:0urn:vertexinc:enterprise:platform:security:1:0
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns98:ExecuteLoginResponse
xmlns:ns70="urn:vertexinc:enterprise:platform:security:1:0"
xmlns:ns98="urn:vertexinc:enterprise:platform:security:messages:1:0">
<ns70:UserLoginConfirmation>
<ns70:UserName>platformadmin</ns70:UserName>
<ns70:LoginResult>SUCCESS</ns70:LoginResult>
<ns70:LastLoginDate>2016-01-26T17:28:02.109</ns70:LastLoginDate>
<ns70:DefaultAsOfDate>2016-01-26</ns70:DefaultAsOfDate>
<ns70:ForcePasswordChange>false</ns70:ForcePasswordChange>
</ns70:UserLoginConfirmation>
</ns98:ExecuteLoginResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
My research thus far indicates a general lack of need to do something like this, most people either strip the name space from the elements of the part of the document that they care about, or they simply ignore the namespace. At the moment I am stripping the namespace values, but for debugging purposes would like to inspect the namespaces that were used in the response.
An interesting aspect of the service being used is that the nsXX values can vary for each invocation (e.g. ns70 could be ns78 next time the method is invoked). This means that I cannot key on a fixed namespace value. Additionally, the namespace values for these messages in the WSDL don't seem to have any correspondence to the namespace values in the response.
XPath seems like it might be able to help here, or I could just write my own, but I'd prefer to leverage an existing approach. At this point I'm just trying to understand the problem space and would appreciate some guidance with regard to where to start my education process. (please point me in the right direction)
The approach I took was to fork angular-soap and add the ability to build a list of response namespaces as the XML response is converted into an object tree:
SOAPClient._node2object = function (node, wsdlTypes, namespaces) {
var namespaceURI = node.namespaceURI;
var prefix = node.prefix;
if ('undefined' != typeof namespaceURI) {
namespaces[prefix] = namespaceURI;
}
...
}
To get the list of namespaces a namespaces object must be passed to the $soap.post() method, as follows.
var namespaces = new Object();
...
$soap.post(webserviceurl, "SomeWebservice", parameters, namespaces).then(function (response) {
...
}
The alteration to the angular-soap code required modification of all functions between the $soap.post(url, action, parameters, namespaces) method and SOAPClient._node2object(node, wsdlTypes, namespaces) function to propagate the namespaces parameter.
http://www.w3schools.com/xml/dom_element.asp

Set property value

I need to change the value of a javascript property but nothing seem to work. This is what I tried:
var test = allProducts[i]; // allProducts[i] comes from the database
console.log("TestProp BEFORE = " + test.get("TestProp"));
This prints out my TestValue.
Now I try to change the value and I tried all 3 syntax suggestions below (not at the same time of course):
test.TestProp = "kisses";
test["TestProp"] = "kisses2";
test['TestProp'] = "kisses3";
console.log("TestProp AFTER = " + test.get("TestProp"));
But this once again prints my TestValue.
What am I missing? Could it be that the object is somehow locked?
Usually, when you see something like SomeObject.get('attrName') in the code, it's a sure-sign SomeObject is actually not a plain JS object. Many popular frameworks (including Backbone) and libraries (jQuery) use the following approach: instead of enhancing native/host Objects, they put those into properly formed containers ('favor composition over inheritance' principle).
The bottom line is that while it might be possible to assign properties to these wrapper-objects (with bracket or dot notation), it's meaningless. Instead one has to use proper setter methods - most commonly, it's set().
In your case, that resolves to...
test.set('TestProp', 'some_kisses_value');
... where the first param is the name of attribute/property, the second one is its value.

Javascript prototype reflection function

I'm not exactly sure of the name of what I'd like to do but it goes like this:
Currently, I have a bunch of variables in my javascript context that look like $A126 or $B15.
Before running, I have to load in all 9000 of these variables and their current values so later parts of the code can just reference $xxx for the value.
The preloading is not efficient at all and is causing a bottleneck.
As there is a substantial amount of code that uses this $xxx notation I was wondering if it would be possible to make a universal change to $.xxx where $ is a function that performed a lookup of the value passed to it via what was after the period.
So $.xxx would be analogous to GetItem(xxx)
This is for a javascript environment in C# using clearscript, though I don't think that would impact the answer.
It looks like
function Field(val){
var value = val;
this.__defineGetter__("xxx", function(){
return value;
});
this.__defineSetter__("value2", function(val){
value = val;
});
}
var field = new Field("test");
console.log(field.xxx)
---> 'test'
That is almost an example of what I'm looking for. The problem is that I would like to have a general defineGetter that doesn't look for a particular getter by name.

Quick Way to "Un-Angularize" a JS Object

Angular adds expando properties, "hashes," etc., to my deep object structure when two-way binding is in use. That's fine, but I'm interested in retrieving a JSON snapshot of my object tree with only the things that originally belonged there. Does Angular provide a way to get a "vanilla" version of a bound object?
(I wouldn't want to merely store the "original value" before binding kicks in, since I would want to reflect any changes made via the UI.)
short answer:
There's a nice built in function:
angular.toJson(yourObj);
longer explanation:
The only difference between angular.toJson and JSON.stringify is that it runs it through a filter which strips out the hashes/ids and turns window, document, and scope into strings. If you want to roll your own function to do this: here is relevant snippet from Angular.JS source code:
if(/^\$+/.test(key)) {
val = undefined;
} else if (isWindow(value)) {
val = '$WINDOW';
} else if (value && document === value) {
val = '$DOCUMENT';
} else if (isScope(value)) {
val = '$SCOPE';
}
note: the isWindow and isScope functions are not exported, so you'd need a little more hacking to get that function to work exactly the same way.
source: http://docs.angularjs.org/api/angular.toJson and https://github.com/angular/angular.js/blob/master/src/Angular.js
There's also a angular.fromJSon function which is essentially JSON.parse.
Update It's worth noting that the $http service does this automatically for you when you specify a model as the data for an $http request.

How might one look at an object in JavaScript to find out what it is?

Note: I’m going to use a specific object as an example here, but please don’t post answers specific to this example; the question is more general.
Specific example
I wrote some jQuery code like this...
$('#some_button').click(function(event) {
$.post('<some URL>', { <some parameters> },
function() { <do something on success> })
.error(function(x) {
// What is x?
});
event.preventDefault();
});
Now, for the purpose of this question, let’s assume that there is no documentation about that object x that is passed in.
An obvious thing to do might be
alert(x);
but all that will output is [object Object].
General question
What might be an easy way to find out what properties/methods an unknown object has? I’m thinking something that I’d just write during the debugging phase, no production code of course.
You may assume that jQuery is available.
Edit:
I’m fully aware of for (...), but surely that doesn’t mean there can’t be a better/easier way — I thought jQuery might have something built-in...
A general and single level basic javascript solution
Basic functionality looks like this:
var s = "";
for(var p in obj)
{
s += p + " = " + obj[p] + "\n";
}
alert(s);
Object graph issue
It will enumerate over all properties of an object. If this particular object has deep object trees you should better put this into a function and then recall it on sub object. enumerate internal sub object using the same technique. Arrays are a similar issue.
But I suppose you'll be able to provide this kind of functionality from this starting example code.
Browser console solution
If you have development console open in your browser (in Firefox that would be Firebug) then you can easily just call this:
console.log(obj);
But there's a problem with IE, because when it comes to a complex object is just displays {...} which isn't really helpful. So this approach can only be used in Chrome and Firefox+Firebug.
A jQuery plugin for any browser
This is a small and simple plugin I've come up to enumerate an arbitrary object and display its content in browser's console:
$.extend({
inspect: function(obj,n){
n = n || "this";
if ($.isArray(obj)) {
for (var x = 0; x < obj.length; x++) {
$.inspect(obj[x], n + "[" + x + "]");
}
return;
}
if ($.isPlainObject(‌​obj)) {
for (var p in obj){
$.inspect(obj[p], n + "." + p);
}
return;
}
console.log(n + " = " + obj.toString());
}
});
This code works with any browser (I actually needed it for IE, because of the previously mentioned issue with {...} display.
It parses an object graph into console provided that your browser's console is open. In IE and Chrome that's the built in development console and in Firefox it's Firebug console.
You can use it as:
$.inspect(yourObject);
or
$.inspect(yourObject, "person");
The second optional parameter is used to give your object a name when displaying it. If you don't provide the name it will be set as "this". Your object will be displayed as:
this.name = "John"
this.lastname = "Doe"
console.log was built for that.
Alternatively (although I'm not sure what could be better than the first option) your own recursive implementation that loops through the objects properties with a simple for(parameter in obj){ ... }
console.log
will usually give you a better idea of the properties an object has.
Your best bet would be to use a browser like Google Chrome or Firefox with the Firebug plugin then you can add a breakpoint and inspect the object. If it is just a simple Javascript object you could just loop through the properties like so:
for(name in object) {
alert("name: " + name + "value:" + object[name]);
}
Another option might be to serialize to JSON and output that. A solution for doing that can be found here.
It is difficult in javascript to write a general function to determine whether an identifier references any particular type of value. Most such functions are limited to specific cases. A general "what is this" function is practically impossible if not limited to specific bounds.
If such a function was available, what would you do with it?
The general approach in javascript is to test for the properties or capabilities that are required for a particular purpose. What is the point in going further?
console.log
and typeof obj
will suffice.

Categories

Resources