google closure compiler not renaming properties - javascript

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.

Related

VS Code JS: Why / when do definitions break?

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.

JavaScript - Functions as objects

The concept of functions being objects in JavaScript would be ok with me if I could understand the following question. I have searched around and looked into the javascript engine to try and find the answer, but no explanation I've found so far sits well in my mind...
An object like the one below is understandably layed out in a hash map type of construct.
var person = {
firstName:"John",
lastName:"Doe",
age:50,
eyeColor:"blue"
};
However, to say this is also an object is where I get stuck:
var name = function () {
alert ('name');
}
In terms of memory, how is this function stored?
Are the statements inside the "hash map" of a function layed out in an execute order? So each property is called upon after the other?
I'm probably missing something or visualising something wrong.
Thanks.
P.S
To clear up question 2,
Say I have an if statement inside my function... will that be stored in a property accessible through one of its properties?
Every object in javascript has properties (key-value pairs identified by strings or symbols) and it has internal slots.
The function object name is stored in the same format as the person object, but their internal slots differ.
person's properties are firstName, lastName, age and eyeColor, each holding the respective primitive value
person's internal slots are (amongst others):
[[prototype]], pointing to Object.prototype
name's properties are name, prototype and length (as typical for Function instances)
name's internal slots are (amongst others):
[[prototype]], pointing to Function.prototype
[[ECMAScriptCode]], pointing to the code of the function
[[Environment]], pointing to the scope the closure was created in
Disclaimer: That's only how it behaves, engines may implement this however they want. Still, it serves well as a mental model, and it's important to understand that objects have a layer below the publicly visible properties.
Functions are objects, in that they can have properties and methods. Unlike objects, they can also be called and will always return a result.
Note that the ECMAScript (i.e. JavaScript) language specification describes how Function objects should behave rather than underlying implementation, so the in-memory representation of the object will depend on implementation.
Regarding 2: Note that the full text of a Function might be stored in the functionBody property, however the body of a Function does not have to be JavaScript. It could be native code, for example, that is not meaningful to return in a string.
If you just want to do regular JavaScript coding, I don't think you really need to worry about how the function is stored by the browser or server or whatever. I do think you are misunderstanding the object-nature of a function. The lines of code inside the function are not individual parts of a hash map. Rather (and this only begins to touch on the concept), a function can have properties with names and values just like a regular object can have such properties. The following code demonstrates this.
var myFunc = function() {
var x = "hello".toUpperCase();
document.write('<p>' + x + '</p>');
};
myFunc.favoriteColor = "red";
myFunc(); // runs the function and shows the text "hello"
document.write("<p>" + myFunc.favoriteColor + "</p>"); // shows the text "red"
The answer to 1. is: It depends on the implementation.
The 2nd question doesn't make any sense.
I think you are looking at the syntax, and assuming that because the way data is declared, and the way functions are declared, that a function can be treated as data in the language.
This is not the case.
There are languages where this IS the case. Lisps and Prolog being the most common examples. see:
https://en.wikipedia.org/wiki/Homoiconicity

What's the difference between str.fun() / str.fun / fun(str) in JavaScript?

I tried googling but couldn't find a precise answer, so allow me to try and ask here. If the question does not seem proper, please let me know and I'll delete it.
In JS you've got three different way of writing certain build in functionalities:
str.length
str.toString()
parseInt(str)
I wonder if there is a reason behind these different ways of writing. As a new user I don't grasp why it couldn't be streamlined as: length(str) / toString(str) / parseInt(str) or with dot formulation.
I however think if I do know the reason behind these differences, it would give me a better understanding of JavaScript.
Length is one of the attributes of string in JavaScript. Hence you use string.length to get the length of the string.
toString is a function for string objects, hence we use stringobj.toString().
parsInt(str) is a global function which takes string as a parameter.
JavaScript is object-oriented, so there are functions or procedures which require first an object to use as this in their bodies. str.length is a property, both syntactically and semantically. It doesn't require any parameters and represents some quality of the object. obj.toString() is a method (a function attached to an object), which doesn't represent any characteristics of the object, but rather operates on its state, computes some new values, or changes the state of the object a lot. parseInt(str) is a "global" function, which represents an operation not attached to any type or object.
Under the hood, these three ways may be well implemented with just calling a function, passing this as the first parameter (like C# does, for example). The semantic difference is the important one.
So why not use just the third syntax, like for example PHP does? First, it doesn't bloat the global environment with lots of functions which only work for one specific case and type, allowing you to specify any new function you want without breaking the old functionality. Second, it ecourages you to use object-oriented concepts, because you can already see working objects and methods in the language, and can try to make something similar.
And why isn't parseInt a method? It can as well be str.toInt() without any issues, it's just the way JavaScript designers wanted it to be, although it seems also a bit logical to me to make it a static method Number.parseInt(str), because the behaviour of the function is relevant more to the Number type than the String type.
JavaScript is based around objects. Objects have properties (e.g. a User object may have name and age properties). These are what define the user and are related to the user. Properties are accessed via dot-notation or brackets notation (to access Eliott’s age, we’ll use either eliott.age or eliott['age'] — these are equivalent).
These properties can be of any type — String, Number, Object, you name it — even functions. Now the proper syntax to call a function in JS is to put round brackets: eliott.sayHello(). This snippet actually fetches Eliott’s sayHello property, and calls it right away.
You can see Eliott as a box of properties, some of which can be functions. They only exist within the box and have no meaning out of the box: what would age be? Whose age? Who’s saying hello?
Now some functions are defined at the global level: parseInt or isNaN for instance. These functions actually belong to the global box, named window (because legacy). You can also call them like that: window.parseInt(a, 10) or window.isNaN(a). Omitting window is allowed for brevity.
var eliott = {
name: 'Eliott',
age: 32,
sayHello: function () { console.log('Hello, I’m Eliott'); }
};
eliott.name; // access the `name` property
eliott.age; // access the `age` property
eliott.sayHello; // access the `sayHello` property
eliott.sayHello(); // access the `sayHello` property and calls the function
sayHello(eliott); // Reference error: `window.sayHello` is undefined!
Note: Some types (String, Number, Boolean, etc.) are not real objects but do have properties. That’s how you can fetch the length of a string ("hello".length) and reword stuff ("hello, Eliott".replace("Eliott", "Henry")).
Behaviour of these expressions is defined in ECMAScript grammar. You could read the specification to understand it thoroughly: ECMAScript2015 specification. However, as pointed out by Bergi, it's probably not the best resource for beginners because it doesn't explain anything, it just states how things are. Moreover I think it might be too difficult for you to be able to grasp concepts described in this specification because of the very formal language used.
Therefore I recommend to start with something way simpler, such as a very basic introduction to JavaScript: JavaScript Basics on MDN. MDN is a great resource.
But to answer your question just briefly:
str.length is accessing a property of the str object.
parseInt(str) is a function call
str.toString() is a call of a function which is a property of the str object. Such functions are usually named methods.
Functions and methods are in fact very similar but one of the differences (except for the obvious syntax difference) is that methods by default have context (this) set to refer to the object which they're part of. In this case inside of toString function this equals to str.
Note: Accessing a property (as in str.length) could in effect call a getter function but it depends on how the object is defined, and is in fact transparent for the user.

Retrieve binary representation of number in ClojureScript

I would like to get the binary form of a number, e.g 6 -> "0110"
I've tried (js/toString ...) but no matter what syntax I use, the repl always returns "[object Window]". What does this mean?
I'm also confused because toString is part of goog.math.Integer, and yet when I try to use js/isOdd, part of the same library, it says it is not defined. I tried manually requiring it via (ns user (:require [goog.math.Integer :as int])), but it made no difference.
I'm also confused as to the difference between (.toString ...) and (js/toString ...).
Any help with the specific problem and/or the nuances of js functions in cljs would be most appreciated. Thanks!
You should use (.toString 6 2). Using (js/toString ...) amounts to toString(...) which you can try evaluating yourself in a typical javascript browser console. You'll see you'll also get an "object Window".
(js/thing) is used for referring to a javascript runtime symbol. In particular, if you've loaded code separate from your compiled clojurescript (e.g. loaded through a different script), you can refer to the loaded symbols using the js/... syntax. js/thing, in this case, will refer to thing in the top level scope of javascript.
For example, say you're using the ROT.js library which exposes its API through the ROT object. You can access its functions in clojurescript (assuming the library has been loaded), using js/ROT. Creating an instance of its Display object found in ROT.Display would then be accomplished using (js/ROT.Display. params).
Loaded Closure compatible code, on the other hand, is accessed depending on how they've been required in the namespace. In general, if you've loaded the goog.math library with (ns test (:require [goog.math :as math]), you can access everything under goog.math using (math/something).
The (.function object params) syntax is used for calling methods of a javacript object and would correspond to object.function(params). Remember that javascript objects are different from values and objects you create through pure clojurescript code. Use (.-property object), if you just want to get the value of that object's property instead. You can also lookup doto, .., and the threading macros ->, ->> for more ways to deal with javascript objects inside clojurescript. Most of the interop facilities provided for java in clojure holds for javascript/clojurescript. I also recommend reading http://www.spacjer.com/blog/2014/09/12/clojurescript-javascript-interop/.
As for the isOdd, that is an instance method of an instance of goog.math.Integer. First create an instance of that (e.g. (def e (new math/Integer ...)) and then you can call .isOdd on that instance. Look through the goog.math.Integer documentations to see which static properties and methods are accessible straight from the Integer scope.
This is a parser error, there are three ways to make this work, creating a var with the number and calling .toString on that, writing the number with an extra a dot or writing the number in parentheses.
If you try 6.toString(2) on a JavaScript console you will get this error:
SyntaxError: Unexpected token ILLEGAL
But this 6..toString(2) works. This is because the JavaScript parser expects a number followed by a dot to be a float literal. When you write 6. the parser expects the next character to be a number not t, when you write 6.. the first dot is parsed as part of the number (creating the number 6.0) and the second dot is parsed as a method call on the created number.
In ClojureScript the compiler knows about this "feature" of JavaScript so you can pass the 6 literal to toString:
cljs.user> (.toString 6 2)
"110"
cljs.user> (.toString 6. 2)
"110"
The ClojureScript compiler generates the correct code in both cases. In the first case it generates (6).toString(2) and in the second case it generates 6.0.toString(2).
(js/toString 6) is calling the toString defined on the window global object. No matter what you pass the result is always the same. You can check that calling by window.toString() in a JavaScript console.
(.toString target args) is calling the toString defined in the target object passing args as parameters of the method.

Why is arr = [] faster than arr = new Array?

I ran this code and got the below result. I curious to know why [] is faster?
console.time('using[]')
for(var i=0; i<200000; i++){var arr = []};
console.timeEnd('using[]')
console.time('using new')
for(var i=0; i<200000; i++){var arr = new Array};
console.timeEnd('using new')
using []: 299ms
using new: 363ms
Thanks to Raynos here is a benchmark of this code and some more possible way to define a variable.
Further expanding on previous answers...
From a general compilers perspective and disregarding VM-specific optimizations:
First, we go through the lexical analysis phase where we tokenize the code.
By way of example, the following tokens may be produced:
[]: ARRAY_INIT
[1]: ARRAY_INIT (NUMBER)
[1, foo]: ARRAY_INIT (NUMBER, IDENTIFIER)
new Array: NEW, IDENTIFIER
new Array(): NEW, IDENTIFIER, CALL
new Array(5): NEW, IDENTIFIER, CALL (NUMBER)
new Array(5,4): NEW, IDENTIFIER, CALL (NUMBER, NUMBER)
new Array(5, foo): NEW, IDENTIFIER, CALL (NUMBER, IDENTIFIER)
Hopefully this should provide you a sufficient visualization so you can understand how much more (or less) processing is required.
Based on the above tokens, we know as a fact ARRAY_INIT will always produce an array. We therefore simply create an array and populate it. As far as ambiguity, the lexical analysis stage has already distinguished ARRAY_INIT from an object property accessor (e.g. obj[foo]) or brackets inside strings/regex literals (e.g. "foo[]bar" or /[]/)
This is miniscule, but we also have more tokens with new Array. Furthermore, it's not entirely clear yet that we simply want to create an array. We see the "new" token, but "new" what? We then see the IDENTIFIER token which signifies we want a new "Array," but JavaScript VM's generally do not distinguish an IDENTIFIER token and tokens for "native global objects." Therefore...
We have to look up the scope chain each time we encounter an IDENTIFIER token. Javascript VMs contain an "Activation object" for each execution context which may contain the "arguments" object, locally defined variables, etc. If we cannot find it in the Activation object, we begin looking up the scope chain until we reach the global scope. If nothing is found, we throw a ReferenceError.
Once we've located the variable declaration, we invoke the constructor. new Array is an implicit function call, and the rule of thumb is that function calls are slower during execution (hence why static C/C++ compilers allow "function inlining" - which JS JIT engines such as SpiderMonkey have to do on-the-fly)
The Array constructor is overloaded. The Array constructor is implemented as native code so it provides some performance enhancements, but it still needs to check for arguments length and act accordingly. Moreover, in the event only one argument is supplied, we need to further check the type of the argument. new Array("foo") produces ["foo"] where as new Array(1) produces [undefined]
So to simplify it all: with array literals, the VM knows we want an array; with new Array, the VM needs to use extra CPU cycles to figure out what new Array actually does.
One possible reason is that new Array requires a name lookup on Array (you can have a variable with that name in scope), whereas [] does not.
Good question.
The first example is called an array literal. It is the prefered way to create arrays among many developers. It could be that the performance difference is caused by checking the arguments of the new Array() call and then creating the object, while the literal creates an array directly.
The relatively small difference in performance supports this point I think. You could do the same test with the Object and object literal {} by the way.
Also, interesting, if the length of the array is known in advance (elements will be added just after creation), the use of an array constructor with a specified length is much faster on recent Google Chrome 70+.
"new Array( %ARR_LENGTH% )" – 100% (faster)!
"[]" – 160-170% (slower)
The test can be found here - https://jsperf.com/small-arr-init-with-known-length-brackets-vs-new-array/2
Note: this result tested on Google Chrome v.70+; in the Firefox v.70 and IE both variants almost equal.
This would make some sense
Objects literals enable us to write code that supports lots of
features yet still make it a relatively straightforward for the
implementers of our code. No need to invoke constructors directly or
maintain the correct order of arguments passed to functions, etc.
http://www.dyn-web.com/tutorials/obj_lit.php

Categories