I'm not all that well versed in JavaScript and I've got a scope problem that I can't find a reference on:
class a
{
var CommonNameVar;
}
class b extends a
{
var CommonNameVar;
function Something(){
CommonNameVar = "somevalue";
}
}
How do I specifically reference CommonNameVar in b and not a (i.e. reference a specific scope of variables)?
It turns out that I'm also not familiar with unityscript and I've made a rather cardinal mistake of assuming that just because this has a .js on the file, that this is javascript (sound like an old sketch from Bob Newhart).
I'll post a new question formatted correctly for the context and declare this one dead.
You can't hide CommonNameVar from the scope it is declared in. But, to make it available to b, you need to create it as this.CommonNameVar so it becomes an instance property and will inherit, otherwise, it's just a local variable and won't inherit.
The this keyword ensures that you'll always get the value of the property that is associated with the instance.
And, your syntax needs a bit of work as classes declare properties within them, not just "loose" elements.
So, with the code below, when an instance of a is made, this will reference one instance and CommonNameVar will be something and when an instance of b is made, b.CommonNameVar will also be something (because of inheritance), until/unless b.Something() is executed, in which case b.CommonNameVar will then be somevalue, while a.CommonNameVar will remain something.
class a {
this.CommonNameVar = "something";
}
class b extends a {
this.Something = function() {
this.CommonNameVar = "somevalue";
}
}
this can get considerably more tricky depending on your code structure and you can read about that here.
Related
Is there way to tell if a instance variable was instantiated inside of the class/object or is referenced from outside?
class A {
b1 = new B();
constructor(public b2:B) {}
}
I.e. I want to find the object properties / variables that are "owned" by the object (i.e. instantiated by itself, here b1) vs. the ones that are referenced (here b2).
Your code compiles to this in JS (I added the class def for B):
class B {
}
class A {
constructor(b2) {
this.b2 = b2;
this.b1 = new B();
}
}
Which is what you have to work with unless you use a reflection library, or add annotations. So there is no API that I know of to simply output parameter names for the constructor.
If you still want to proceed and don't want to invest heavily, a cheap version of this may just be using some clever-enough regex on the output from A.toString() to detect parameter names and correlate them with member names on an instance of A.
No, there is no way to do that.
Notice that the distinction is even more blurry than you might think: a constructor argument value might have been created solely for that instance, to be owned by it (new A(new B())), or an object that was created within the constructor of A might later become shared after it has been accessed from outside (new C(a.b1)). If you want to decide whether an object is "owned" by your A instances or not, you need to describe that contract in the documentation of your class (i.e. for its constructor, and the methods/accessors that might return a field).
If we need smth owned it means it should be encapsulated and not available for public use. My proposition for you is to explicitly say that b1 is a private field. But in terms of which property was initialized in the constructor itself and which was at the field definition level is unknown.
My initial page load instantiates PageInit as follows.
<script>
"use strict";
let PageInit = null;
document.addEventListener("DOMContentLoaded", () => {
PageInit = new IPageInit();
});
</script>
I had to let PageInit=null in order to put that reference into the global name space to make it visible. I suspect that is wrong, because I can't imagine that every class that is instantiated has to be done so in global. (??) So, guidance on the right way to do this is appreciated also.
PageInit(), once it is created has a constructor that calls a class method, which in turns creates an instance of another class:
class IPageInit {
constructor() {
this.InitialiseComponents();
}
//Class Method
InitialiseComponents() {
this.PageContent = new IPageContent();
}
}
Coming from a C# background, I do not create an instance of a class with the class's exact name, as you see above. The class name is "IPageContent", and the instantiated name is just "PageContent". (Again, guidance on the right naming conventions is appreciated.)
PageContent(), when it is instantiated has a constructor that itself creates a property called "TrafficData".
class IPageContent {
constructor() {
this.TrafficData = "Paragraph 13.5";
}
}
Later, in "loose javascript" code on the page, a function tries to make a reference to TrafficData. I've tried two ways:
// page javascript
function LoadTrafficData {
let x = PageContent.TrafficData; // PageContent (itself) is undefined
let x = PageInit.TrafficData; // PageInit is valid object, but TrafficData is undefined
}
As you see, neither way works. I do not know enough about scope and visibility in instantiated JavaScript classes to figure out what is wrong and what to do about it. I am using plain vanilla JS - no frameworks, APIs, or Libraries.
How do I get LoadTrafficData() (a loose function, not a class method) to get a reference to TrafficData?
You are correct that global variables are generally a bad practice. Modern js uses imports to import classes into other classes. For example, you might have a PageService singleton class that creates an instance of your PageContent class and holds it in a class property. Other classes could import your PageService singleton to use its properties.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
Your naming conventions are a bit unusual for JS as well:
Class names are normally capitalized, like PageContent, and instances are lowercase, like pageContent.
Class methods and functions should start with lowercase letters.
In typescript, you would prefix interfaces with an I, like IPageInterface, but you wouldn't normally prefix class names in regular javascript.
To debug your stuff, it's common to do console.log(myVariable) to inspect things. You can also insert a debugger; statement in your code to launch chrome's debugger at that line. To access your global var, you would do: PageInit.PageContent.TrafficData.
Stylistically, I prefer this structure:
var Filter = function( category, value ){
this.category = category;
this.value = value;
// product is a JSON object
Filter.prototype.checkProduct = function( product ){
// run some checks
return is_match;
}
};
To this structure:
var Filter = function( category, value ){
this.category = category;
this.value = value;
};// var Filter = function(){...}
Filter.prototype.checkProduct = function( product ){
// run some checks
return is_match;
}
Functionally, are there any drawbacks to structuring my code this way? Will adding a prototypical method to a prototype object inside the constructor function's body (i.e. before the constructor function's expression statement closes) cause unexpected scoping issues?
I've used the first structure before with success, but I want to make sure I'm not setting myself for a debugging headache, or causing a fellow developer grief and aggravation due to bad coding practices.
Functionally, are there any drawbacks to structuring my code this way?
Will adding a prototypical method to a prototype object inside the
constructor function's body (i.e. before the constructor function's
expression statement closes) cause unexpected scoping issues?
Yes, there are drawbacks and unexpected scoping issues.
Assigning the prototype over and over to a locally defined function, both repeats that assignment and creates a new function object each time. The earlier assignments will be garbage collected since they are no longer referenced, but it's unnecessary work in both runtime execution of the constructor and in terms of garbage collection compared to the second code block.
There are unexpected scoping issues in some circumstances. See the Counter example at the end of my answer for an explicit example. If you refer to a local variable of the constructor from the prototype method, then your first example creates a potentially nasty bug in your code.
There are some other (more minor) differences. Your first scheme prohibits the use of the prototype outside the constructor as in:
Filter.prototype.checkProduct.apply(someFilterLikeObject, ...)
And, of course, if someone used:
Object.create(Filter.prototype)
without running the Filter constructor, that would also create a different result which is probably not as likely since it's reasonable to expect that something that uses the Filter prototype should run the Filter constructor in order to achieve expected results.
From a run-time performance point of view (performance of calling methods on the object), you would be better off with this:
var Filter = function( category, value ){
this.category = category;
this.value = value;
// product is a JSON object
this.checkProduct = function( product ){
// run some checks
return is_match;
}
};
There are some Javascript "experts" who claim that the memory savings of using the prototype is no longer needed (I watched a video lecture about that a few days ago) so it's time to start using the better performance of methods directly on the object rather than the prototype. I don't know if I'm ready to advocate that myself yet, but it was an interesting point to think about.
The biggest disadvantage of your first method I can think of is that it's really, really easy to make a nasty programming mistake. If you happen to think you can take advantage of the fact that the prototype method can now see local variables of the constructor, you will quickly shoot yourself in the foot as soon as you have more than one instance of your object. Imagine this circumstance:
var Counter = function(initialValue){
var value = initialValue;
// product is a JSON object
Counter.prototype.get = function() {
return value++;
}
};
var c1 = new Counter(0);
var c2 = new Counter(10);
console.log(c1.get()); // outputs 10, should output 0
Demonstration of the problem: http://jsfiddle.net/jfriend00/c7natr3d/
This is because, while it looks like the get method forms a closure and has access to the instance variables that are local variables of the constructor, it doesn't work that way in practice. Because all instances share the same prototype object, each new instance of the Counter object creates a new instance of the get function (which has access to the constructor local variables of the just created instance) and assigns it to the prototype, so now all instances have a get method that accesses the local variables of the constructor of the last instance created. It's a programming disaster as this is likely never what was intended and could easily be a head scratcher to figure out what went wrong and why.
While the other answers have focused on the things that are wrong with assigning to the prototype from inside the constructor, I'll focus on your first statement:
Stylistically, I prefer this structure
Probably you like the clean encapsulation that this notation offers - everything that belongs to the class is properly "scoped" to it by the {} block. (of course, the fallacy is that it is scoped to each run of the constructor function).
I suggest you take at the (revealing) module patterns that JavaScript offers. You get a much more explicit structure, standalone constructor declaration, class-scoped private variables, and everything properly encapsulated in a block:
var Filter = (function() {
function Filter(category, value) { // the constructor
this.category = category;
this.value = value;
}
// product is a JSON object
Filter.prototype.checkProduct = function(product) {
// run some checks
return is_match;
};
return Filter;
}());
The first example code kind of misses the purpose of the prototype. You will be recreating checkProduct method for each instance. While it will be defined only on the prototype, and will not consume memory for each instance, it will still take time.
If you wish to encapsulate the class you can check for the method's existence before stating the checkProduct method:
if(!Filter.prototype.checkProduct) {
Filter.prototype.checkProduct = function( product ){
// run some checks
return is_match;
}
}
There is one more thing you should consider. That anonymous function's closure now has access to all variables inside the constructor, so it might be tempting to access them, but that will lead you down a rabbit hole, as that function will only be privy to a single instance's closure. In your example it will be the last instance, and in my example it will be the first.
Biggest disadvantage of your code is closing possibility to override your methods.
If I write:
Filter.prototype.checkProduct = function( product ){
// run some checks
return different_result;
}
var a = new Filter(p1,p2);
a.checkProduct(product);
The result will be different than expected as original function will be called, not my.
In first example Filter prototype is not filled with functions until Filter is invoked at least once. What if somebody tries to inherit Filter prototypically? Using either nodejs'
function ExtendedFilter() {};
util.inherit(ExtendedFilter, Filter);
or Object.create:
function ExtendedFilter() {};
ExtendedFilter.prototype = Object.create(Filter.prototype);
always ends up with empty prototype in prototype chain if forgot or didn't know to invoke Filter first.
Just FYI, you cannot do this safely either:
function Constr(){
const privateVar = 'this var is private';
this.__proto__.getPrivateVar = function(){
return privateVar;
};
}
the reason is because Constr.prototype === this.__proto__, so you will have the same misbehavior.
Stylistically, I prefer this structure:
var Filter = function( category, value ){
this.category = category;
this.value = value;
// product is a JSON object
Filter.prototype.checkProduct = function( product ){
// run some checks
return is_match;
}
};
To this structure:
var Filter = function( category, value ){
this.category = category;
this.value = value;
};// var Filter = function(){...}
Filter.prototype.checkProduct = function( product ){
// run some checks
return is_match;
}
Functionally, are there any drawbacks to structuring my code this way? Will adding a prototypical method to a prototype object inside the constructor function's body (i.e. before the constructor function's expression statement closes) cause unexpected scoping issues?
I've used the first structure before with success, but I want to make sure I'm not setting myself for a debugging headache, or causing a fellow developer grief and aggravation due to bad coding practices.
Functionally, are there any drawbacks to structuring my code this way?
Will adding a prototypical method to a prototype object inside the
constructor function's body (i.e. before the constructor function's
expression statement closes) cause unexpected scoping issues?
Yes, there are drawbacks and unexpected scoping issues.
Assigning the prototype over and over to a locally defined function, both repeats that assignment and creates a new function object each time. The earlier assignments will be garbage collected since they are no longer referenced, but it's unnecessary work in both runtime execution of the constructor and in terms of garbage collection compared to the second code block.
There are unexpected scoping issues in some circumstances. See the Counter example at the end of my answer for an explicit example. If you refer to a local variable of the constructor from the prototype method, then your first example creates a potentially nasty bug in your code.
There are some other (more minor) differences. Your first scheme prohibits the use of the prototype outside the constructor as in:
Filter.prototype.checkProduct.apply(someFilterLikeObject, ...)
And, of course, if someone used:
Object.create(Filter.prototype)
without running the Filter constructor, that would also create a different result which is probably not as likely since it's reasonable to expect that something that uses the Filter prototype should run the Filter constructor in order to achieve expected results.
From a run-time performance point of view (performance of calling methods on the object), you would be better off with this:
var Filter = function( category, value ){
this.category = category;
this.value = value;
// product is a JSON object
this.checkProduct = function( product ){
// run some checks
return is_match;
}
};
There are some Javascript "experts" who claim that the memory savings of using the prototype is no longer needed (I watched a video lecture about that a few days ago) so it's time to start using the better performance of methods directly on the object rather than the prototype. I don't know if I'm ready to advocate that myself yet, but it was an interesting point to think about.
The biggest disadvantage of your first method I can think of is that it's really, really easy to make a nasty programming mistake. If you happen to think you can take advantage of the fact that the prototype method can now see local variables of the constructor, you will quickly shoot yourself in the foot as soon as you have more than one instance of your object. Imagine this circumstance:
var Counter = function(initialValue){
var value = initialValue;
// product is a JSON object
Counter.prototype.get = function() {
return value++;
}
};
var c1 = new Counter(0);
var c2 = new Counter(10);
console.log(c1.get()); // outputs 10, should output 0
Demonstration of the problem: http://jsfiddle.net/jfriend00/c7natr3d/
This is because, while it looks like the get method forms a closure and has access to the instance variables that are local variables of the constructor, it doesn't work that way in practice. Because all instances share the same prototype object, each new instance of the Counter object creates a new instance of the get function (which has access to the constructor local variables of the just created instance) and assigns it to the prototype, so now all instances have a get method that accesses the local variables of the constructor of the last instance created. It's a programming disaster as this is likely never what was intended and could easily be a head scratcher to figure out what went wrong and why.
While the other answers have focused on the things that are wrong with assigning to the prototype from inside the constructor, I'll focus on your first statement:
Stylistically, I prefer this structure
Probably you like the clean encapsulation that this notation offers - everything that belongs to the class is properly "scoped" to it by the {} block. (of course, the fallacy is that it is scoped to each run of the constructor function).
I suggest you take at the (revealing) module patterns that JavaScript offers. You get a much more explicit structure, standalone constructor declaration, class-scoped private variables, and everything properly encapsulated in a block:
var Filter = (function() {
function Filter(category, value) { // the constructor
this.category = category;
this.value = value;
}
// product is a JSON object
Filter.prototype.checkProduct = function(product) {
// run some checks
return is_match;
};
return Filter;
}());
The first example code kind of misses the purpose of the prototype. You will be recreating checkProduct method for each instance. While it will be defined only on the prototype, and will not consume memory for each instance, it will still take time.
If you wish to encapsulate the class you can check for the method's existence before stating the checkProduct method:
if(!Filter.prototype.checkProduct) {
Filter.prototype.checkProduct = function( product ){
// run some checks
return is_match;
}
}
There is one more thing you should consider. That anonymous function's closure now has access to all variables inside the constructor, so it might be tempting to access them, but that will lead you down a rabbit hole, as that function will only be privy to a single instance's closure. In your example it will be the last instance, and in my example it will be the first.
Biggest disadvantage of your code is closing possibility to override your methods.
If I write:
Filter.prototype.checkProduct = function( product ){
// run some checks
return different_result;
}
var a = new Filter(p1,p2);
a.checkProduct(product);
The result will be different than expected as original function will be called, not my.
In first example Filter prototype is not filled with functions until Filter is invoked at least once. What if somebody tries to inherit Filter prototypically? Using either nodejs'
function ExtendedFilter() {};
util.inherit(ExtendedFilter, Filter);
or Object.create:
function ExtendedFilter() {};
ExtendedFilter.prototype = Object.create(Filter.prototype);
always ends up with empty prototype in prototype chain if forgot or didn't know to invoke Filter first.
Just FYI, you cannot do this safely either:
function Constr(){
const privateVar = 'this var is private';
this.__proto__.getPrivateVar = function(){
return privateVar;
};
}
the reason is because Constr.prototype === this.__proto__, so you will have the same misbehavior.
This is going to be a relatively long question, but one I would really like to understand. Final question formulated at the bottom of the question.
I have read the answers to this question:
ES6 class variable alternatives
The question on why this is not accepted syntax in ES6:
class MyClass {
const MY_CONST = 'string';
constructor(){
this.MY_CONST;
}
}
1) The first answer mentions:
Remember, a class definition defines prototype methods - defining
variables on the prototype is generally not something you do.
I don't get this; static variables in a class based language would appear to serve the same purpose as properties defined on the prototype in JS.
Obviously not an instance variable like a person's name, but it could be a default MAX_SPEED for a vehicle, or a counter that is shared by all instances. If the instance doesn't override the prototype's MAX_SPEED, it returns to the default. Isn't that the exact purpose of a static variable?
2) The following post (ES6 spec proposal) formulates:
There is (intentionally) no direct declarative way to define either
prototype data properties (other than methods) class properties, or
instance property.
Class properties and prototype data properties need be created outside
the declaration.
I don't see the actual difference in declaring / initialising an instance/class variable with default value within the class itself (outside the constructor)? What does it matter if it's on the prototype? If it concerns an instance variable with a default value that will be likely for all instances (yet overridable), I don't see what is the problem. So what is this intention about exactly?
3) The second answer on the question ES6 class variable alternatives confuses me (though not from a technical pov).
From within a class method that variable can be accessed as
this.constructor.foo (or MyClass.foo).
These class properties would not usually be accessible from to the
class instance. i.e. MyClass.foo gives 'bar' but new MyClass().foo is
undefined
This indicates that it is clearly possible to declare a class variable on the class (or underlying function) as implemented in this example: http://www.es6fiddle.net/iehn0hxp/
class Car{
constructor(){
//Set instance variable
this.instance_var = 220;
//Set class variable
this.constructor.class_var = 240;
}
}
var Mercedes = new Car();
var Audi = new Car();
//Instance property
console.log(Mercedes.instance_var); //220
//Class property
console.log(Car.class_var); //240
//Set instance property
Mercedes.instance_var = 120; //Well I don't know really :-)
console.log(Mercedes.instance_var); //120
//Class property
Car.class_var = 140;
console.log(Car.class_var); //140
//Can be accessed from the constructor property on the instance
console.log(Mercedes.constructor.class_var); //140
console.log(Audi.constructor.class_var); //140
So in the end it is possible to declare a static property from within the class; so I don't see what is the difference declaring it within the constructor, versus just defining it on the class, vs defining it from outside? In the end it just seems to be a trivial technical modification to put it in the constructor vs as an actual class definition (the result will be the same).
Is it really just a design choice to only make methods available?
Ultimate question:
Because I don't understand how being a prototype-language changes the
philosophy of having properties on the prototype against
static variables on a class. It looks the same to me.
I hope that my question is clear, shout if not.
I don't get this; static variables in a class based language would appear to serve the same purpose as properties defined on the prototype in JS.
No, static variables are more like properties defined on the constructor. Variables on the prototype would be closer to instance variables, but they’re not nearly as useful because they’re shared between instances. (So if you modify a mutable property on the prototype, it will be reflected in all other instances of that type.)
This also answers your other questions, I think, but to recap:
variables on the prototype are not like static variables in that they appear to belong to every instance rather than just the class
variables on the prototype are not like instance variables in that each instance of the class doesn’t have its own instance of the variable
therefore, variables on the prototype are not that useful and they should be assigned to in the constructor (instance variables) or assigned to the constructor (class variables)
they’re also properties, not variables
And a non-ES6-sugared example:
function Something() {
this.instanceProperty = 5;
}
Something.staticProperty = 32;
Something.prototype.prototypeProperty = 977;
var s = new Something();
console.log(s.instanceProperty); // 5
console.log(s.prototypeProperty); // 977? If you want a class property,
// this is not what you want
console.log(s.staticProperty); // undefined; it’s not on the instance
console.log(Something.staticProperty); // 32; rather, it’s on the class
console.log(Something.prototypeProperty); // undefined; this one isn’t