I couldn't find any clear answer, so what's the difference between Objecttype and extend type in JavaScript?
In AngularJS, when I consoled $state:
console.log($state)
console.log($state.$current.parent)
I got the output as:
As you can see, the $state is interpreted as an Object where the latter is an extend?
I needed the parent name of current state, so I was planning to take it from the self.name object of $state.$current.parent. Is that okay? Or should I keep out of extend?
They both are objects. Chrome's console additionally tells you their type. The first one it's a generic object whereas the second one is still an object, but named instead.
Here's how you can create named objects very easily:
function NamedObject() { this.aProperty = 'something'; }
var namedObject = new NamedObject();
Generic objects are created like this:
var genericObject = { aProperty: 'something' };
In your specific case, uiRouter uses angular.extend internally. If you were to assign a name to this anonymous function here you'd see how extend will be renamed to the function's name.
Related
Given the following code (taken from this answer):
function ConstructorFunction() {
this.someProp1 = "cf1";
this.someProp2 = "cf2";
}
ConstructorFunction.prototype.someMethod = function () { /* whatever */ };
function factoryFunction() {
var obj = {
someProp1: "ff1",
someProp2: "ff2",
someMethod: function () { /* whatever */ }
};
// other code to manipulate obj in some way here
return obj;
}
let objFromConstructor = new ConstructorFunction()
let objFromFactory = factoryFunction()
console.log(objFromConstructor)
console.log(objFromFactory)
I get different looking objects in the Chrome console:
There is text (ConstructorFunction) before the constructor function object - what is this called?
Why is the object from the factory function missing this text?
Does the difference in structure affect anything about how these objects will work?
There is text (ConstructorFunction) before the constructor function
object - what is this called?
ConstructorFunction is the name of your instance object, while with the factory, there is no instance, just an object literal, so no name to report.
Does the difference in structure affect anything about how these
objects will work?
Absolutely. The constructor version has this context pointing to each instance generated, while the factory doesn't and the constructor forms the basis of an inheritance chain that is highly configurable, while the factory doesn't.
Chrome tries to guess what is the object's constructor. In other languages this is called the object's class and you can sort of call it that especially with modern class-based syntax.
When you create an empty object using the object literal syntax, {}, the class of the object is merely Object (yes, there is literally a constructor function in js called Object). When this happens Chrome does not print the class name.
The main difference is that the first object has a constructor and the second does not. Generally this has no effect on how the object behaves except when you use features to ask about the object itself. One difference you have noticed is that the object logged by Chrome is displayed differently by the debugging console.
Other differences include the fact that objFromConstructor is an instanceof ConstructorFunction and also an instanceof Object but objFromFactory is only instanceof Object. You can think of the instanceof operator as telling you if an object is of a particular type so you can say that objFromConstructor is a type of ConstructorFunction but objFromFactory is not. Note that all objects inherit form Object so all objects are also of type Object.
In general, unless you are doing some metaprogramming/introspection/reflection by using things like instanceof you will not notice any difference between the two.
How can I get name of object's class? I mean "Process" in this example
I see two ways to get it. First one is to write a getter in this class like
getClassName(){return "Process"}
But I suppose it will be an error if I try to call this method in object which doesn't belong to this class and hasn't got method like this.
And second one is using object instanceof Process. But maybe there is some way to make it better and more correctly?
You can get it from name on constructor:
console.log(object.constructor.name);
When you do ex = new Example, for instance, in the normal course of things that makes Example.prototype the prototype of the object that was created (ex), and the object inherits a constructor property from that object that refers back to the constructor (Example).
I say "in the normal course of things" because there are various ways those normal relationships can be changed. For instance, code could have overridden the constructor property with an own property on the object (ex.constructor = somethingElse;). To rule out that specific scenario, you could use:
console.log(Object.getPrototypeOf(object).constructor.name);
Live example:
class Example1 {
}
const e1 = new Example1();
console.log(e1.constructor.name); // "Example1"
class Example2 {
constructor() {
this.constructor = "I'm special";
}
}
const e2 = new Example2();
console.log(Object.getPrototypeOf(e2).constructor.name); // "Example2"
The TC39 committee members that specify JavaScript were happy enough to use the instance's constructor property in Promises when building the new promise that then and catch return (see StepĀ 3 here which goes here and reads constructor from the instance) (and in some other places), so you wouldn't be out on your own if you also used it. They don't even go to the prototype of the instance.
But yes, just for completeness, even if you go to the prototype for it, it's still possible for that to lead you astray, since the prototype's constructor property can also be mucked with:
class Example {
}
Example.prototype.constructor = Object; // Why would anyone do this? People are weird.
const e = new Example();
console.log(Object.getPrototypeOf(e).constructor.name); // "Object"
It's also possible to redefine the name on a function:
class Example {
}
// Why would someone do this? People are weird.
Object.defineProperty(Example, "name", {
value: "flibberdeegibbit"
});
const e = new Example();
console.log(Object.getPrototypeOf(e).constructor.name); // "flibberdeegibbit"
So...caveat user.
Note that the function name property is new as of ES2015 (as is class syntax). If you're using class syntax via a transpiler, it may or may not set name correctly.
Generally object instanceof Process is desirable if it's known for sure that object originates from this class/function. There may be situations where this won't be so. The appearance of several Process can be caused by iframes, multiple package versions, etc.
There is name property that already exists in regular functions class constructors. A known pitfall is that it will be mangled in minified code, so it is generally useless in browser JS, and its use can be considered an antipattern. name cannot be reassigned (in some browsers), so a separate property is needed to identify the class.
The proper way is to avoid this problem
But I suppose it will be an error if I try to call this method in object which doesn't belong to this class and hasn't got method like this.
is to use a getter:
class Process {
get className() { return 'Process'; }
...
}
Or a property:
class Process {
...
}
Process.prototype.className = 'Process';
As a result, there may be several Process classes that have Process className identifier. This may be desirable or not. While instanceof associates class instance with one particular class.
Use .constructor.name on the object. Each object's constructor by default refers to his creation function, which has a name property. It returns the name of the function.
class SomeClass {
}
const obj = new SomeClass();
console.log(obj.constructor.name);
Use the name property as follows:
class Process {}
console.log(Process.name);
const process = new Process;
console.log(process.constructor.name);
This is the same way it works for normal prototypal inheritance using functions.
I have a few questions about some code I've come across. You're not required to understand the framework or it's API as my only issue is having a better understanding of some concepts.
I understand that in the line below, the variable polygonCollisionSpite is being assigned the return value of game.add.sprite() which I'm assuming is an object.
var polygonCollisionSprite = game.add.sprite(400,128,'check');
What's confusing to me is what appears to be method chaining? I'd understand a regular method like game.add() but game.add.sprite(), how does that look in the object? this.game.add.sprite = function(){} ?
Then I also came across
scoreText = game.add.text(10, 10, 'Hit Space to Restart Demo');
scoreText.font = 'Arial Black';
scoreText.fontSize = 16;
scoreText.stroke = '#000';
scoreText.strokeThickness = 3;
scoreText.fill = '#fff';
This looks like properties are being added to the object returned and assigned to "scoreText". How are properties able to be added without the usage of the .prototype method?
What might the object being returned to scoreText look like?
Finally, an unrelated but simple question: What's the benefit of assigning a fired function to a variable like:
myvar = test();
Thanks
What's confusing to me is what appears to be method chaining?
There is no chaining there.
Chaining is when a method returns this so foo.bar().baz() has the value of foo as the value of this in both functions.
game.add.sprite(400,128,'check');
This is just accessing properties of an object.
An object can have a property:
someObject.someProperty
The property can have a value
someObject.someProperty = someOtherObject;
That value can be an object, which can have its own properties.
This looks like properties are being added to the object returned and assigned to "scoreText".
The object returned is assigned to scoreText. Properties are then added to that object.
How are properties able to be added without the usage of the .prototype method?
Adding properties to the prototype object makes them available down the inheritance chain when a new object is created from the constructor.
You can add properties to any object.
Most JavaScript that adds properties to something does it to an object directly and doesn't touch the prototype object.
var myPeople = {};
myPeople.john = { name: "John Smith", address: "27 Witherson Ave" };
myPeople.daisy = { name: "Daisy Mannors", address: "19 Cumberbund Rd" };
What might the object being returned to scoreText look like?
There isn't really anything in the code you've provided that could help us infer that. (Other then the properties you explicitly add afterwards).
Finally, an unrelated but simple question: What's the benefit of assigning a fired function to a variable
The same as using a variable for absolutely anything else. You can reuse it, you can change it, you don't need to type out everything needed to recreate it everytime you want to use it.
What I would assume is going on here is game.add.sprite works a little bit like the following:
game.add.sprite = function (options) {
// create instance of Sprite
var inst = new Sprite(options);
// add inst to some entity pool
game.objects.push(inst);
// return for use
return inst;
};
This way, both you and the library/framework has access to this object (inst), and any changes you make, the library/framework is aware of as well.
In this Udacity video on game development, the instructor mentions that Javascript allows us to create an object by giving a handle to its definition. Then, it says that to allow this "an overloaded object definition will update a hash table with a pointer to its class definition".
I quite know what a hash table, a pointer, an overloaded method, and the factory pattern are, but I cannot make sense of this mysterious statement, or of the rest of the explanation.
"Hash table" is just a fancier way of saying "ordinary Javascript object". What the instructor means by "handle to its definition" is just another way of saying "the function that acts as a constructor for the class".
Ultimately, what he means by the statement you mentioned:
each overloaded entity definition will update a hash table with a pointer to its class definition
is the following:
All "subclasses" of Entity will register their constructor function in a single shared hashmap/object using the key which is the type value.
This allows you to get the constructor function (in other words, the function to call new on, which will return an instance of that entity) for any type by accessing gGameEngine.factory[type].
This is nice, because whenever a programmer adds a new type of entity, so long as they remember to add a new entry to that gGameEngine.factory object with the correct key, then that object will contain everything you need to construct any type of supported object.
So the code that iterates over the JSON structure generated by the level editor can create an instance of any type the same way, using something like:
var typeConstructor = gGameEngine.factory(tileSpec.type),
instance;
if (typeConstructor) {
instance = new(typeConstructor)(tileSpec /* or whatever params */);
}
This is similar to the code visible at around the 1 minute mark of the video you linked to.
Make sense now?
I think all he's saying is that you can map references to functions / objects / variables inside another object. He's using one type of property accessor syntax, but I think he's overcomplicating things by using language like 'handle' and 'hash table'.
var someClass = function () {
// stuff
}
var containingObject = {};
containingObject["someClass"] = someClass;
// same thing as
containingObject.someClass = someClass;
Then you can instantiate the class by calling the containingObject property.
var classInstance = new containingObject["someClass"]()
// or
var classInstance = new containingObject.someClass()
Why are arrays in a Backbone.js Model essentially static variables?
class exports.Content extends Backbone.Model
tags: []
then if i make a few models:
contentA = new Content()
contentB = new Content()
and add one string to each models' array:
contentA.tags.push('hello')
contentB.tags.push('world')
they both end up with the same array:
contentB.tags // ['hello','world']
but if it's a string, then there is no problem:
contentA.name = "c1"
contentB.name = "c2"
contentA.name // "c1"
The short answer
When you call extends to define your object, you are passing the new object's configuration in as an object literal. Objects are passed by reference, and the extends function only passes a reference to the tags array in to the new type definition.
As noted by others, you can correct this by assigning tags to a function. This works because a function delays the evaluation of the tags until the object is instantiated. There's nothing native in JavaScript that does this, but it's Backbone itself that recognizes tags as a function or a value.
The long answer
In spite of your code being in CoffeeScript, this comes down to a combination of a few things in JavaScript:
There are no classes in JavaScript
Object literals are evaluated immediately
JavaScript objects are passed around by reference
In JavaScript, there are no classes. Period. CoffeeScript gives you the notion of a class, but in reality, it gets compiled down to JavaScript which has no classes.
You can have types and type definitions (constructor functions) but not classes. Backbone provides a class-like definition, that looks similar to Java's "extend" class-based inheritance. It's still just JavaScript, though, which has no classes.
What we have, instead, is an object literal being passed in to the extends method. It's as if you write this code:
var config = {
tags: []
}
var MyModel = Backbone.Model.extends(config);
In this code, config is an object literal, or a hash, or a key/value pair, or an associative array. Whatever name you call it, it's the same basic idea. You end up with a config object that has a tags attribute. The value of config.tags is an empty array, [], which is itself an object.
Which brings us back to the short answer:
When you call extends to define your object, you are passing the new object's configuration in as an object literal. Objects are passed by reference, and the extends function only passes a reference to the tags array in to the new type definition.
As noted by others, you can correct this by assigning tags to a function. This works because a function delays the evaluation of the tags until the object is instantiated. There's nothing native in JavaScript that does this, but it's Backbone itself that recognizes tags as a function or a value.
"tags" is being declared on the Content.prototype - which is shared across all instances of Content. You probably need to use defaults instead: http://backbonejs.org/#Model-defaults. However, it should be noted that you must use a function (instead of a hash) when defining defaults, otherwise you still run into the same problem when using types which are passed by reference (e.g. Array).
var Content = Backbone.Model.extend({
defaults: function() {
return {
tags: []
};
}
});
benpickles is correct when it comes to Backbone models, and the way to do this in coffeescript in general is to initialize instance properties in the constructor:
class Foo
constructor: ->
#bar = []
As Derick Bailey mentioned, pass by reference is the problem. I solved the problem by cloning the Array (passing-by-value essentially):
var _events = window.active_model.get('events').slice(0);
_events.push({ key: "xxx", value: "yyy" });
window.active_field.set('events', _events);