During a code refactoring exercise, eval() was put into service to parse a template string and instantiate a class. The running code is linked to below.
eval(`let ${tempid} = new Accordian(${"[j]"})`)
Why does this string appear to need quotes around the object referenced by [j] to work?
My other question has to do with class instances, and whether they've been created?
So, the variable tempid is supposed to be a string extracted from a nodeList, but the error I'm getting seems to suggest otherwise, despite the fact the code runs which, to my mind, it wouldn't do unless it has actually instantiated a new class for each of the accordian objects extracted as unique from the markup.
Have two new class instances been created?
I'm getting the following errors:
'Accordian' is defined but never used. (no-unused-vars) eslint
'use strict' is unnecessary inside of modules. (strict) eslint
eval can be harmful. (no-eval) eslint
https://codesandbox.io/embed/eager-morning-9s5ti?fontsize=14
Why quotes?
"[j]" is the String inserted into the template string by ${ }. As far as I can tell, the whole ${"[j]"} part could just be replaced with [j].
"Accordian never used"
Your linter doesn't know what eval will do at runtime. Since you're only using Accordian in a string, it's not actually used in your code.
"eval can be harmful"
eval is evil. Depending on the value of the inserted tempid, the evaluated string could contain arbitrary (potentially harmful) code. You might wanna use tempid to set an attribute on some object instead, e.g. global[tempid] = new Accordian([j]). This would let the linter see the class' usage as well.
Related
I use VS Code for JavaScript.
Definitions within a file work sometimes, but not others. Does anyone know why they fail?
In this example, VS Code finds the definition for edit easily. There is no occurrence of the word 'something' anywhere else in this file. Completely unique. So, why can't VS Code find its definition?
If I knew why, maybe I could change my code to work around it.
VS Code also can't find any references to these 'lost' properties. Which is very frustrating for tracking down where a function is called etc.
You should use this.
const edit = {
something: 5,
test() {
this.something;
},
};
You must not use an arrow function for test field, or this would point elsewhere but not the edit object.
EDIT: In TypeScript 4.3.5, the latest version of TS at the time of writing, TS is able to detect self-references in object literals, and both edit.something and this.something would work. For the case of working with JavaScript, upgrading VS Code should do the trick.
A TS playground link for reference.
There is a length limit. IntelliSense will define type :any if an object description is too long.
There is no way around this at all. The :any type will overwrite imported type definitions (e.g., a .d.ts file).
Two solutions:
Don't write long object declarations in your code.
Don't use VS Code or IntelliSense.
As for specifics:
The behavior is unpredictable.
If a type definition does not generate, reducing the object description length will not cause it to generate
Reducing an object description length to below the limit and re-launching VS Code will cause it to re-generate.
The length limit is unpredictable.
A function definition is 'longer' than a string, even if they have the same character count.
A nested ('deep') object declaration is longer than a shallow ('flat') object declaration, even if they have the same character count.
In short: IntelliSense breaks irreparably if you try to write long object declarations in a JS file.
I'm working on a dojo project and stumbled on code below:
format: function ( /*Date*/ value, /*locale.__FormatOptions*/ constraints) {
....
},
"parse": function ( /*String*/ value, /*locale.__FormatOptions*/ constraints) {
.....
},
As you can see parse method name is a string. I haven't seen something like this before. Is there any reason for doing this?
Link to original file.
According to JavaScript / ECMAScript standard, object property (or functions) identifiers (as used before the colon : in your example) can be any valid identifier (i.e. like the format without quotes), any string (like "parse") or even any number.
Using "parse" in that case is strictly equivalent as using parse, but that would have been different in the case for example of "parse that value", which is a valid string identifier for an object property, even though it has spaces!
Then you can use either myObject.parse or myObject["parse"] to access your property, whereas in my last example you have no choice but using myObject["parse that value"] to access it.
I think we should also mention a specific case where using quotes for object keys is different from without quotes: if you were to use Google Closure minifier in ADVANCED_OPTIMIZATIONS mode, it would replace any non-quoted identifier to try and save space, whereas it would leave intact quoted identifiers, as Google team took this as the indicator that you will try to access it later on with the square brackets method and string, or if you check the actual key name like this:
for (var i in myObject) {
if (i === "parse") { // if i is replaced by the minifier, you will never execute the block below
// do something...
}
}
This specificity which forces you to use quoted identifiers sometimes (but not always, if you do not need to keep the original name) is one of the reasons that push people not using this advanced optimizations mode.
I don't see any reason for using extra quotes.
JSON requires it, but your object literal is not JSON. ES3 required this for keywords, but parse never was a keyword.
In this particular case there is no reason to do that, but I've faced scenarios where I needed to use quotes to define elements. For example:
var httpHeadersToAdd= {
'User-Agent': 'whatever',
Date: new Date()
};
With no quotes the interpreter understands that your are trying to do a subtract operation with variables User and Agent and throws a syntax error SyntaxError: Unexpected token -. Same can be made with functions, and then you have to call them with brackets:
var obj= {
'my-function': function (){}
}
obj['my-function']();
Going back to the code you linked, maybe someone wrote that in a JSON-ish way because that's how JSON strings looks like (double quotes are mandatory in JSON, single quotes don't work)
I'm leaning JavaScript and I've read about the constructor property.
I tried
[].constructor
false.constructor
'abc'.constructor
And they all worked. However to my surprise when trying:
123.constructor
{}.constructor
They did not, why is that?
This is a parse issue.
When you do 123.constructor the engine experts a decimal after the 123 like 123.123
When you do {}.constructor the engine reads {} as an empty block and then reads . as the first thing in the outer block which is meaningless.
Both of which can be fixed by wrapping these with ()s
(123).constructor; // Number, note this 'boxes'
({}).constructor; // Object
I'm sure someone is going to shout at me for asking this question, but here goes: in Javascript, what is the best strategy for coping with the fact that the properties of objects are case-sensitive? If I create an object with a property called FavouriteDrink, but then I later start referring to it as favouriteDrink then I could end up in a mess.
I don't want a big library here, but is there any way to define the object so that FavouriteDrink is defined somewhere, and where in Visual Studio 2012 some intellisense will help me choose the correct property name if I can somehow contextualise the object I'm dealing with? It is only properties I'm pondering here.
Thanks.
It doesn't work this way
if i look at your your code and see :
FavouriteDrink() {}
the first thing will popup in my mind is this is a constructor function not just a normal function
and by looking at this following one
favouriteDrink() {}
i would tell that this is a normal function and i can't use it as a constructor - can't be called with new
Here is some other examples
first_name // variable
FIRST_NAME // uppercase variables shouldn't change
_first_name // local variable not intended to be used out of its scope
var FIRSTNAME = {} // name space
it’s a good idea to follow a convention as to how the words will be separated
see this Code Conventions for the JavaScript Programming Language
For the other part of your question i'm using VS 2012 and i installed JSEnhancements
and i can see all my object element
JavaScript shares the following conventions with Java and ActionScript 3.
ALL_UPPERCASE
Use this as the variable name when you define a constant, or a value that should never change.
For example, myObject.NUM_TIMES_CLICKED = 2 would be a poor candidate for a constant because it is likely to change. However, myObject.APPLE_FRENCH_SPELLING = 'pomme' would be appropriate here.
firstWordLowercaseAndTheRestAllUppercase
Use this when you are defining anything that is not a constant or a class. You would use this for most things, for example, myObject.numTimesClicked, myObject.myFunction(), myObject.returnString.
AllWordsCapitalized
Use this when you are defining a function that defines a "class," generally any function you would call with the syntax myObject.myClassInstance = new MyClass(). Notice how myClassInstance is in camel-case because it is an instance of the class. However, MyClass is all caps because it is meant to be invoked with new.
You would define the class initially like this: myObject.MyClass = function(){};
WebStorm and Sublime Text are great tools that offer the code intelligence you're looking for.
WebStorm does this out of the box, but my personal preference is Sublime Text with the SublimeCodeIntel plugin.
That being said, it's probably best for you to be using naming conventions:
UpperCamelCase is for classes
ALL_CAPS_SNAKE_CASE is for constants
lowerCamelCase is used for everything else
I have an array of objects that I generate from JSON.parse. I access its properties like this:
AnObject['PhoneList'][i]['PhoneLabel']
When I run the code through the google closure compiler, the name of the properties is not obfuscated and clearly visible. Why are the names of object properties not obfuscated?
Google closure has a difficult time figuring out what it can and can't rename. For example, any data structure that is created or referenced by code outside the Google closure compiled code cannot be renamed or the two sides won't be expecting the same code. Further, referencing properties via constructed strings makes it next to impossible for closure to do it's job well. As such, Closure has a whole bunch of rules and settings to help you control this and direct it for what to do. I'd suggest you read up on those rules/settings at these references:
https://developers.google.com/closure/compiler/docs/api-tutorial3
https://developers.google.com/closure/compiler/docs/compilation_levels
https://groups.google.com/group/closure-stylesheets-discuss/browse_thread/thread/386ba6db27a43887?pli=1
https://developers.google.com/closure/compiler/docs/limitations
And, quoted from this last reference:
String representations of function or parameter names:
The Compiler renames functions and function parameters but does not
change any strings in your code that refer to functions or parameters
by name. You should thus avoid representing function or parameter
names as strings in your code. For example, the Prototype library
function argumentNames() uses Function.toString() to retrieve the
names of a function's parameters. But while argumentNames() might
tempt you to use the names of arguments in your code, Simple mode
compilation breaks this kind of reference.
Quoted strings is the syntax used for properties that should not be renamed ("exported").
you probably want to use
AnObject.PhoneList[i].PhoneLabel
instead.
Google Closure Compiler doesn't touch quoted strings.
myObj.prop = 3;
will result in prop being renamed (and myObj too perhaps)
myObj['prop'] = 3;
will result is 'prop' remaining untouched.