Angular 2+ variable hoisting? - javascript

How does Angular resolve all it's variables regardless of where there placed in a component?
For example in Vanilla JS
console.log(a) // undefined
let a = 'Hello;
Angular component
ngOnInit(){
this.example()
}
example(){
console.log(this.a) // Hello
}
a = 'Hello'
I'm aware that this is bad practice and the compiler will complain about that placement of the variable but none the less I am curious how Angular achieves this, or whether it's not an Angular specific behaviour?

This is not an Angular behavior. Actually the piece of code that you provided is inside a class, and the a is not a variable, actually it's a property.
JavaScript (and Typescript) doesn't requires properties to be declared before methods (neither constructor), since it's just a declaration that will be used futurely when this class will be instantiated.
Although tslint may warn you about the placement of it after methods, it's just a coding style concern.
You may translate a class to a traditional function constructor:
class Car {
make = 'default';
drive() {
/* ... */
}
model = 'foo'
}
can be wrote as (and is converted to when using some polyfill on browsers that doesn't support ES6 Class):
var Car = function() {
this.make = 'default';
this.model = 'foo';
}
Car.prototype.drive = function() {
/* ... */
}
Note that in the second case, the properties are defined inside the constructor, so it will always run before the method be called.

Related

Why is 'this' undefined in the debugger but printable in a console.log?

When setting a breakpoint on the console.log statement, why would this be undefined in the debugger but the statement print with no issues? Am I missing something in regards to scope here?
export class OptionsSidebarComponent {
...
public filters: Object = new Object();
...
public generateFilters() {
for (let property in this.terms) {
if (this.terms.hasOwnProperty(property) && this.terms[property] !== null) {
if (!this.filters.hasOwnProperty(this.productGroup.id)){
this.filters[this.productGroup.id] = new Filters();
}
this.terms[property].forEach((term) => {
console.log(this.filters);
});
}
}
}
}
With typescript While debugging, keep in mind that transpilers can rename variables. Using the original name in the console without sourcemaps that include renaming will show you undefined even if the original value isn't. Make sure you use the transpiled name in watches or console commands.
When you're referencing this with your console.log statement inside its own class, you're using it in its relevant scope. Depending on the framework you are using, different terms are used to reference your class... AngularJS used $scope- Angular 2+ uses this to reference the current class (or current scope/context).
When you use this in your debugger you're using it outside of its scope. It no longer references the class you intend it to.
Each one of your components in Angular uses this to reference itself. Here's an article to explain in further detail: https://angular-2-training-book.rangle.io/handout/features/refresher_on_this.html
If we simplify it to basic javascript and look at your class as just a function a good example would be this:
function example(){
var anything = 10;
console.log(anything); //output: 10
}
console.log(anything); //undefined! we're out of scope :)
So looking at it from this perspective, this is nothing magical. It's just provided to us by Angular to make our references to other things inside our components easier.

How to declare a namespace in JavaScript ECS6

I am used to the following syntax which is - I believe - widely used:
var foo = foo || {};
(function() {
foo.bar = function(){
return this;
};
foo.bar.prototype.stuff = null;
foo.bar.prototype.do = function(){...};
})();
It could be done with or without closure.
I use the foo.bar.prototype.stuff syntax so as to not have all the definitions in the constructor itself.
With ECS6 I experimented with this syntax:
class Foo{};
class Bar{
constructor(){
this.stuff = null;
}
get moreStuff(){ return this.stuff++;}
do(){...}
}
Foo.Bar = Bar;
module.exports = { Foo };
I find it very convenient that intellisense works in Visual Studio Code when using this syntax.
Can anyone see any issue with this syntax and if so amend it propose a better one?
I read this post How do I declare a namespace in JavaScript? and found many proposed syntax but most were given before ECS6.
In ES2015+, in the main you don't need these fake namespaces anymore. Instead, use modules. (Perhaps with a module loader, since native support for modules is still only just making its way into browsers.)
But if you want to continue using fake namespaces, perhaps temporarily until native support for modules becomes more widespread, what you have is fine, though there's no real advantage to Foo being declared with class than just making it an object as in your original example:
var Foo = Foo || {};
Foo.Bar = class Bar{
constructor(){
this.stuff = null;
}
get moreStuff(){ return this.stuff++;}
do(){...}
};
But your version is fine other than giving the impression that Foo can be used to construct something useful, and other than the fact that if you do that in two files, it will fail (whereas your first example using var foo = foo || {}; is happy for you to do that in two files and include them both on the same page, perhaps one definign foo.Something and another defining foo.SomethingElse).

JSHint with ECMAScript6: method is not defined

I'm implementing a client-side application using ECMAScript6 and use JSHint for static code analysis. I often use the following pattern in my code:
class MyClass {
constructor() {
//This is how I would like to call myMethod
myMethod();
//This is how I should call myMethod to make JSHint analysis pass
this.myMethod();
}
myMethod(){
//Implementation
}
}
My primary language is Java so I expect that simply calling myMethod() should be ok. However without adding this to method call I'm getting "'myMethod' is not defined" warning from JSHint. My questions are:
Is it correct to make calls without this in such situation? (e.g. in PHP you always need to add $this-> to non-static method call)
If that's correct to make calls without this is there any way (any .jshintrc flag) to turn off this warning in JSHint?
No, this is and never was correct in JavaScript. Methods always need to be called on a receiver explicitly to make this work, and they need to be referred to using property access notation because methods are just functions on properties in javascript. They're not available as functions in the scope of your other methods. It's the same for properties, btw.
JsHint is right here, and there's no reason to turn that warning off. Even if that may possible, executing your program in spite of that would just make it not work.
Is it correct to make calls without this in such situation? (e.g. in
PHP you always need to add $this-> to non-static method call)
No, it is not. You always have to specify the receiver of the method.
If that's correct to make calls without this is there any way (any
.jshintrc flag) to turn off this warning in JSHint?
JSHint returns "'myMethod' is not defined" warning correctly as there is not function called myMethod in the scope of the constructor.
In the code you provided the identifier myMethod isn't defined, but the inherited property myMethod of instances of MyClass is defined.
If you define myMethod as a Function under a closure which isn't available elsewhere then you can access as it in the form you desire
var MyClass = (function () {
function myMethod() {
//Implementation
}
class MyClass {
constructor() {
myMethod();
}
}
return MyClass;
}());
I don't get to write much ES6 so I'm not sure if putting the function myMethod inside MyClass's definition is a SyntaxError
Please note however that this is required to reference your specific instance of MyClass, so you'll probably need to use it somewhere if you want MyMethod to act on the instance.
function myMethod(obj) {...}
// ...
myMethod(this);
If you read the MDN's description of class
JavaScript classes are introduced in ECMAScript 6 and are syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax is not introducing a new object-oriented inheritance model to JavaScript. JS classes provide a much simpler and clearer syntax to create objects and dealing with inheritance.
This is saying using class is just shorthand for the old way of doing it, not a new model, so it may be easier to think of what your current code would look like if written in ES5,
var MyClass = (function () {
function MyClass() {
this.constructor.apply(this, arguments);
}
MyClass.prototype = Object.create(null);
MyClass.prototype.constructor = function () {
myMethod(); // referenceError
this.myMethod(); // works
};
MyClass.prototype.myMethod = function () {
//Implementation
};
return MyClass;
}());

Javascript 'normal' objects vs module pattern

Currently I'm developing a large scale Javascript app(single page) and I've searched around the web to find some best practices. Most projects use the module pattern so the objects doesn't pollute the global namespace. At this moment I use normal objects:
function LoginModel(){
this.model = new MyModel();
this.getModel = function(){
return this.model;
};
}
This is readable and easy to maintain(my opinion). Is it better to use the module pattern just because of the namespacing or does it has other advantages I'm not aware of(counter memory leaks, ... )? Furthermore, I've already splitted up the files to have a nice MVC pattern and destroy every object when needed(counter memory leaks). So the main question is: do I need, in my case, to use the module pattern or not?
Module pattern:
var LoginModel = (function(){
var model = MyModel;
function getModel(){
return model;
};
return {
getModel: getModel
};
});
The module pattern is better for overall code organization. It lets you have data, logic and functions that are private to that scope.
In your second example getModel() is the only way to get the model from the outside. The variable declared int he module are hidden unless explicitly exposed. This can be a very handy thing.
And there's not really any drawback, other than being a little more complex. You just get more options for organization and encapsulation.
I'd use a plain object until my model gets complex enough to need more structure and some private scoping. And when you hit that point, it's trivial to redefine it as a revealing module without breaking any of the code that uses it.
If you're only going to be using one instance per page, I don't see the need to involve the new keyword. So personally I would create a revealing module like you did in your last example, and expose an object with the "public" properties.
Though I don't see your point with the getModel() function, since MyModel is obviously accessable outside of the scope.
I would have rewritten it slightly:
var LoginModel = (function(model, window, undefined){
function init(){ } // or whatever
function doSomethingWithModel(){
console.log(model);
}
return { init: init };
})(MyModel, window);
If you're uncertain of which modules that will get a model, you can use loose augumentation and change
})(MyModel, window);
to
})(MyModel || {}, window);
If you need several instances of a module, it would look something like this:
var LoginModel = (function(model, window, undefined){
function loginModel(name){ // constructor
this.name = name; // something instance specific
}
loginModel.prototype.getName = function(){
return this.name;
};
return loginModel;
})(MyModel, window);
var lm1 = new LoginModel('foo');
var lm2 = new LoginModel('bar');
console.log(lm1.getName(), lm2.getName()); // 'foo', 'bar'
There's several concepts conflated in your question
With what you call the "normal object", the function becomes a constructor function and requires the new keyword.
The second example uses the Revealing Module Pattern inside of an IIFE. This is the most popular variant of the Module Pattern, but unfortunately deeply flawed. For an explanation of the differences see my answer here, and for its flaws, see here.
Now, your question poses a false dichotomy -- normal objects or module pattern? You don't have to make a choice -- a normal object can use the module pattern simply by putting whatever it wants to keep private inside its closure scope. For example,
function LoginModel(){
var _notifyListeners = function(){
// Do your stuff here
};
this.model = new MyModel();
this.getModel = function(){
_notifyListeners();
return this.model;
};
}
This is an example of a "normal object" using the module pattern. What you have to avoid doing is what the Revealing Module Pattern does -- putting everything into closure scope. You should only put the things you want to keep private inside the closure scope.

Annotate Singleton objects in JavaScript for the Google Closure Compiler, or "dangerous use of the global this object" warning

I'm working with the Google Closure Compiler in ADVANCED_OPTIMIZATIONS compilation level and have started to annotate my constructors because I get all kinds of warnings:
WARNING - dangerous use of the global this object
For my 'constructor' type functions I'll annotate them like this:
/**
* Foo is my constructor
* #constructor
*/
Foo = function() {
this.member = {};
}
/**
* does something
* #this {Foo}
*/
Foo.prototype.doSomething = function() {
...
}
That seems to work fine, however what if I have a 'singleton' object that isn't constructed with var myFoo = new Foo();
I couldn't find in the documentation how to annotate this type of object because its type is just object right?
Bar = {
member: null,
init: function() {
this.member = {};
}
};
The preferred way of creating singletons in Closure is like this:
/** #constructor */
var Bar = function() { };
goog.addSingletonGetter(Bar);
Bar.prototype.member = null;
Bar.prototype.init = function() {
this.member = {};
};
This allows for lazy instantiation of the singleton. Use it like this:
var bar1 = Bar.getInstance();
var bar2 = Bar.getInstance();
bar1.init();
console.log(bar2.member);
Keep in mind that this doesn't prevent people from using the constructor to create instances of Bar.
This is exactly the type of potential bug that "dangerous use of this" warns you against. In your example, the Closure Compiler may try to "flatten" your code to:
Bar$member = null;
Bar$init = function() { this.member = {}; };
NOTE: The Closure Compiler currently will not flatten a namespace that is declared as a global object (i.e. without the "var" keyword in front), so your code may still work now. However, there is no telling that it won't do that in a future version and your code will suddenly break without warning.
Of course, then "Bar$member" and "Bar$init" will be renamed to "a" and "b" respectively. This is called "namespace flattening" or "collapsing of properties".
You can immediately see that your code no longer works correctly. Before compilation, if you write:
Bar.init();
this will refer to Bar. However, after compilation it becomes:
Bar$init();
this will no longer refer to Bar. Instead it refers to the global object.
This is way the compiler is trying to warn you that using "this" in such a way is "dangerous", because "this" may be changed to refer to the "global" object. That's the true meaning of the warning.
In short, DO NOT DO THIS. This type of coding style creates bugs that are very difficult to track down.
Modify your code this way:
var Bar = { // Closure Compiler treats globals and properties on global differently
member: null,
init: function() { Bar.member = {}; }
};
or use a closure:
var Bar = (function() {
var member = null;
return {
init: function() { member = {}; }
};
})();
When using the Closure Compiler in Advanced Mode, do not try to get rid of warnings by annotating them away. Warnings are there for a reason -- they try to warn you about something.

Categories

Resources