As you know, a single String can define many key/value properties. For instance, a query String can be defined as
someKey=someValue&anotherKey=anotherValue
Now i need to define a pattern in which a single String can define many key/value properties to be stored in a class attribute. But each value can be a String, an Array, A reference to a JavaScript function etc. Something like (Hypothetical pattern)
class="p=[1,2,3,4]&a=aaa&c=f()"
Its purpose: post-processing input Field through class atribute
Any advice to define a good pattern ?
You might want to look into Javascript Object Notation (JSON) at http://www.json.org/.
It describes basically what you are looking for, and is an industry standard way of packaging data nicely, so you won't be alone in using it.
EDIT: Given that the problem requires function references and/or runtime evaluation of functions, and that the whole thing is meant to be wrangled into a double quoted html class attribute, I second Gumbo's answer of just using javascript.
The easiest would be to use plain JavaScript:
attr="p=[1,2,3,4];a='aaa';c=f"
Note that c=f() is not assigning the function f to c but the return value of the function f. c=f is assigning the function f to c.
You can evaluate that code with eval:
eval(element.getAttribute("attr"));
Here is a string formatted as JSON:
var dataString = "'FirstName' : 'David', 'LastName' : 'Robbins', 'Dates' : {'BirthDate' : '12/12/1966', 'Graduated': '6/21/1984'}"
You can de-serialize the string to a Javascript object with the following call:
var userData = eval("(" + dataString +")");
You could natrually wrap the eval in another function.
Related
I've looked everywhere, and it seems like the kind of thing that should be simple, so forgive me if this IS simple or violates best practices or I just missed it.
I want to be able to convert an object reference into a string. Not the object being referred to, but the reference itself.
Let's say I have a method nested in an object, for example:
a.b.c.d()
where a is the object and d is the method, how do I retrieve the string:
"a.b.c.d" ?
To be a little more specific, I want to pass the object reference as an argument to a function and be able to convert it to a string representing the key path:
function convertPath ( a.b.c.d ) {
...
}
could return the string "a.b.c.d". (I'd perform some other operations with it instead of just returning it, but I'm keeping this simple.)
Methods like "toString", etc. return the actual function being referenced as a string.
I've seen plenty of references to do the opposite (pass a string and convert it to an object reference), which would create other complications for me, but not this.
Any help would be appreciated. Thanks!
Example use case:
I have an object with an attribute "myProperty", having getter and setter ("Property Getters and Setters" are supported since EcmaScript 5: https://www.w3schools.com/js/js_es5.asp):
var obj = {
myProperty:'myPropertyValue',
get myProperty(){
return this.property;
},
set myProperty(value){
this.property=value;
}
};
I would like to bind that attribute to a view, which is the task of a custom function that is called bindProperty.
In order to pass the property myProperty to the function, I could do something like
bindProperty(obj, 'myProperty');
However, I would like to avoid to pass the property name as a hard coded String. Strings have the disadvantage, that they are not updated when the attribute name changes during refactoring.
If I would use
bindProperty(obj, obj.myProperty);
the function would only know the property value 'myPropertyValue' and not where the value comes from.
=>How can I pass/identify the property itself, without using a String?
A. Using reflection?
I could imagine something like
bindProperty(obj, ()=>obj.myProperty);
The function bindProperty would then have to do some reflection magic to find out the name of the attribute in the body of the lambda expression (pseudo code):
let attributeName = getNameofArgumentFromBodyOfLambdaExpression(lambda);
obj[attributeName] = 'newValue';
=>Is it possible in JavaScript to evaluate the body of the lambda expression using reflection to get the name of the property?
(I know that this can be done in .NET languages, e.g.
Private Sub BindProperty(Of T)(propertyExpression As Expression(Of Func(Of T)))
Dim propertyName As String = GetPropertyName(propertyExpression)
'...
)
B. Using complex attributes
An alternative whould be that I use wrapping property objects, having their own getters and setters. Howerver, then I would have to use the property like
obj.myProperty.set('newValue')
or
obj.myProperty('newValue') //similar to knockout observables
I still want to be able to use the great Getter/Setter feature. With other words: I want to use my properties like plain attributes:
obj.myProperty = 'newValue'
Therefore, this is not an option for me and I would prefer to use Strings instead of B.
C. Any other alternatives?
An object in javascript is more or less just a mapping of strings or symbols to values. There is no real reflection that you can call upon in the runtime environment that would enable you to move backward from the value to the property name.
If all you need is refactoring, the one way to do this would be to just configure your IDE to recognize string accessors by providing some sort of type information either via Flow or Typescript or something of that sort (the type information is likely what allows reflection to work in languages like .NET). Or you could just settle for a unique prefix like "viewable_propName" and just do simple find and replace if you need to rename.
If you are really focused on getting this to work without type information and in current ES6 syntax, you could do the following:
function getNameofPropFromVal(obj, val){
for(let prop in obj){
if(obj[prop] === val) return prop;
}
}
obj[getNameofPropFromVal(obj, obj.myProp)] = 'newVal';
Though this has shortcomings:
(1) There is no guarantee that two properties won't share the same value.
(2) It introduces unnecessary runtime overhead.
Finally, if you're willing to be cutting edge and use a transformer like babel you could use decorators for your bindProperty method. That way you can just do the binding in the object definition itself. Here is an article explaining the gist and here is the more formal ECMAScript proposal.
I just found following simple work around that might fullfill my needs:
function bindProperty(obj, lambdaExpression){
let expression = lambdaExpression.toString(); // "()=> obj.myProperty"
let subStrings = expression.split(".");
let propertyName = subStrings[1];
console.info(propertyName );
//...
}
I want to know how is the string length of a string calculated in js.
Is is a function call or a class data member.
I want to know what happens when we execute the following code :
a = 'this is a string';
console.log(a.length); // what actually happens at this point?
Also if a do this :
a += ' added something';
console.log(a.length); // at what point is the new length calculated
//and/or updated for the object 'a';
And at last, do I need to store the string length in a temp variable while using a loop over the string or can I directly use the following (which one is faster/processor efficient) :
for(var i=0;i<a.length;i++){
// doing anything here
}
Summing up my question, I want to know the processing behind String.length and which practice is better while looping over strings?
A string is immutable in JavaScript.
a += "somestring" doesn't change the length of a string but makes a new string.
This means there is no "new length", but the length is just part of the definition of the string (more precisely it is stored in the same structure in implementations).
Regarding
for(i=0;i<a.length;i++){ // did you forget the 'var' keyword ?
a not so uncommon practice (if you don't change a) was to optimize it as
for (var i=0, l=a.length; i<l; i++)
in order to avoid the reading of the length but if you compare the performances with modern engines, you'll see this doesn't make the code any faster now.
What you must remember : querying the length of a string is fast because there is no computation. What's a little less fast is building strings (for example with concatenation).
Strings are a primitive type. At least that's what the documentation says. But we can access the length of the string as if we are accessing the property of an object(with the dot notation). Which indicates it's an object, Right?
Turns out, whenever we make a call from the string primitive to some property using the dot notation (for example, say length), the Js engine will take this primitive string and wrap it into an equivalent wrapper object, which is a String object. And then, the .length on that String object returns the length.
Interesting thing to note here is, that when we do something like this, our string still stays the same primitive string during all of this. And a temporary object is created to make our string operation work. Once the required property is fetched, this temporary object is deleted from the memory.
Hope this gives some high level understanding.
I'm answering your first question.
I'm also curious about this puzzle so I did some search myself, ended up finding -
Based on String documentation from Mozilla:
String literals (denoted by double or single quotes) and strings
returned from String calls in a non-constructor context (i.e., without
using the new keyword) are primitive strings. JavaScript automatically
converts primitives to String objects, so that it's possible to use
String object methods for primitive strings. In contexts where a
method is to be invoked on a primitive string or a property lookup
occurs, JavaScript will automatically wrap the string primitive and
call the method or perform the property lookup.
So as I understand, when you use somestring.length, the primitive string will first be wrapped as a String object, and then since the object has its property length, so it's just a internal method call to access and return.
For example, I'm trying to isolate the first 5 characters of window.location.
var ltype, string = 'string';
console.log(window.location); // file:///C:/for example
console.log(typeof window.location); // [OBJECT]
lType=window.location.substr(0,5); // 'not a function' (quite so)
string=window.location;
lType=string.substr(0,5); // fails similarly
Q1: Can I somehow 'bind' substr() to window.location?
I can see that string=window.location replicates a reference and not
a value, so
Q2: How can a separate, discrete copy of a complex structure such as an object or an array be created [without using JSON.stringify() or JSON.parse() - which is what I am presently resorting to]?
try
string = window.location.href.toString();
instead of
string=window.location;
Because window.location will return object not a string.
window.location is an object, so you can't use string functions on it - as you've noticed. In order to get the actual location as a string (to perform string operations on it), you'll need to convert it to a string somehow.
window.location.href is a property provided by the object itself.
window.location.toString() is a method on all JavaScript objects, overridden here.
However, beware of the XY problem. It looks to me like you're trying to retrieve the protocol (the http: bit) of the URI. There's a property for that too - window.location.protocol.
lType = window.location.protocol;
You should use that - it's more robust (consider https:// or, worse, ftp://...).
When you have a multi-tiered object like a json object that say has 3 tiers
i = {'id':1{'name':'austin', 'lives':'college'{'name':'eckerd', 'major':'compsci'}}}
To reference the object is it better to reference it like so
for (x in i)
i[x]['lives']['name']
//or
i[x].lives.name
I think that gets my idea across. Pretty much use Associative arrays or the 'dot' method and why?
i[x].lives.name is equivalent to i[x]["lives"]["name"].
i[x][lives][name] means that you have variables called lives and name that you want to reference:
There's no real benefit to using one form over the other; imho it's clearest to use the dot notation unless you need the variable property names.
"Values can be retrieved from an object by wrapping a string expression in a [ ] suffix. If the string expression is a string literal, and if it is a legal JavaScript name and not a reserved word, then the . notation can be used instead. The . notation is preferred because it is more compact and reads better."
Crockford, D. (2008), JavaScript: The Good Parts. (pp. 21). Sebastopol, CA, U.S.A.: O'Reilly.