Does this method have a method? - javascript

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.

Related

Where are built-in method in javascript?

please help me get it straight, I see every object in javascript leads to object Object in prototype chain and then to null, in console.log we can see properties and methods of objects but never its implementation, i wonder if this Object is a top-level object where all built-in are stored, is that so?
thank you all for answers!
Javascript is an object-based language. Which means that "everything" inherits from an Object, except Object itself, the top of the prototype chain is null. When you declare an array, you can use .lenght because that is defined in the prototype attribute. There are some exceptions, such as int, floats, etc.
In fact, when you run a console, you can see every method from its parents. Try creating a Constructor for a new object, let's say, for example:
var Person = function(name, yearOfBirth, job) {
this.name = name;
this.yearOfBirth = yearOfBirth;
this.job = job;
}
Add a method to this Person's prototype:
Person.prototype.calculateAge = function() {
console.log(2016 - this.yearOfBirth);
};
And create an instance of this new "class":
var sarah = new Person('Sarah', 1994, 'programmer');
Now go to the console on your browser and type sarah to see it's methods and variables. You'll notice that variables that are exclusive for John will appear on the first drop-down, but you'll also notice that John does not have calculateAge attached directly to it. That's because it's in its prototype, search for something called _proto_ and you'll see this method and also a construct and guess what else? Another _proto_, this time, it's the proto from Person's parent, or, in other words, the Object.
There you can find most of the methods from the Object itself.
Prototypes are what makes inheritance possible in javascript
Perhaps you want to look at ECMA specifications?
http://www.ecma-international.org/publications/standards/Ecma-262.htm
Each browser may have its own implementation of Javascript. Maybe something like this repo will help.
https://github.com/v8/v8

using Set.has in Array.filter - incompatible receiver

Suppose I've a Set as a lookup table.
const myset = new Set(["key1", "key2", "key3", "keepMe"]);
I wanted to filter another array of some other keys (say mykeys) which are in myset.
const mykeys = ["ignoreMe", "keepMe", "ignoreMeToo", "key2"];
Question:
Why do I have to use
const filtered = mykeys.filter(k => myset.has(k))
instead of
const filtered = mykeys.filter(myset.has)
// TypeError: Method Set.prototype.has called on incompatible receiver undefined
i.e., why do I've to create an anonymous lambda function in filter? keys.has has same signature (argument - element, return boolean). A friend told me it's related to this.
Whereas mykeys.map(console.log) works without error (although not being of much use).
I came across this article at MDN and I still don't get why "'myset' is not captured as this". I understand the workaround but not the "why". Can anyone explain it with some details and references in a human friendly way?
Update: Thank you all for the responses. Maybe I wasn't clear about what I'm asking. I do understand the workarounds.
#charlietfl understood. Here's his comment, the thing I was looking for:
Because filter() has no implicit this where as set.has needs to have proper this context. Calling it inside anonymous function and manually adding argument makes the call self contained.
You could use thisArg of Array#filter with the set and the prototype of has as callback.
This pattern does not require a binding of an instance of Set to the prototype, because
If a thisArg parameter is provided to filter, it will be used as the callback's this value. Otherwise, the value undefined will be used as its this value. The this value ultimately observable by callback is determined according to the usual rules for determining the this seen by a function.
const
myset = new Set(["key1", "key2", "key3", "keepMe"]),
mykeys = ["ignoreMe", "keepMe", "ignoreMeToo", "key2"],
filtered = mykeys.filter(Set.prototype.has, myset);
console.log(filtered);
This is a fundamental design decision dating back to the first definition of the JavaScript language.
Consider an object
var myObjet = {
someValue: 0,
someFunction: function() {
return this.someValue;
}
};
Now, when you write
var myValue = myObject.someValue;
You get exactly what you have put in it, as if you had written
var myValue = 0;
Similarly, when you write
var myFunction = myObject.someValue;
You get exactly what you have put in it, as if you had written
var myFunction = (function() {
return this.someValue;
});
...except now, you are not in an object anymore. So this doesn't mean anything. Indeed, if you try
console.log(myFunction());
you will see
undefined
exactly as if you had written
console.log(this.someValue);
outside of any object.
So, what is this? Well, JavaScript decides it as follows:
If you write myObject.myFunction(), then when executing the myFunction() part, this is myObject.
If you just write myFunction(), then this is the current global object, which is generally window (not always, there are many special cases).
A number of functions can inject a this in another function (e.g. call, apply, map, ...)
Now, why does it do this? The answer is that this is necessary for prototypes. Indeed, if you now define
var myDerivedObject = Object.create(myObject);
myDerivedObjet.someValue = 42;
you now have an object based on myObject, but with a different property
someValue
console.log(myObject.someFunction()); // Shows 0
console.log(myDerivedObject.someFunction()); // Shows 42
That's because myObject.someFunction() uses myObject for this, while myDerivedObject.someFunction() uses myDerivedObject for this.
If this had been captured during the definition of someFunction, we would have obtained 0 in both lines, but this would also have made prototypes much less useful.

Javascript - Prototyping on DOM elements

I'm building custom libraries to handle GUI and creating divs and stuff programatically. I also want to extend these objects with children and methods to do something like this:
Function CustomElement() {
this = document.createElement('div');
///--------
Some custom properties
///--------
}
CustomElement.prototype.customMethod = function(args) {
///--------
Some code here
///--------
};
var elem = new CustomElement();
document.body.appendChild(elem);
elem.customMethod(args);
I've thoroughly searched for an answer but found none. How can I accomplish this?
Note: I'm posting from my cell phone. Please excuse me if the code looks awful. I'll correct it as soon as I have access to a PC.
I appears you are confused between classical languages such that you are probably use to, and prototypical like languages such as Javascript.
Also, in your example, assigning the value of this is an invalid statement.
In Javascript, instead of creating children of a super class, we create objects that inherit the properties of other objects through the prototype chain. Still with me? This means that your customMethod is not technically a method, rather it is a property called customMethod which has the value of a function object.
Every constructor object (which is just a fancy name for your CustomElement function) has a magical property named prototype as you have discovered. Objects don't have this property, but they do have an implicit reference to their constructor's prototype object. This means you can call your customMethod as if it were a property of elem, but it is really a property of the constructors prototype object. So I guess you could say the prototype object is kind of like a parent and the object is kind of like a child (although this is incorrect terminology). This prototype object may also again have an implicit reference to it's constructor prototype, which may reference it's constructor prototype... and so on. That's why its called the prototype chain.
So to answer your question:
I also want to extend these objects with children and methods... How can I accomplish this?
For a suggestion to emulate child like inheritance, see below. However, your library requires a different approach...
A common angle of attack is to create a constructor which creates a new object, with a new Element object as a property of that object. For example:
function CustomElement(doesLikeTrains) {
// keep element in this property
this.nativeElement = document.createElement('div');
// other properties are separate
this.likesTrains = doesLikeTrains;
}
// these are also separate
CustomElement.prototype.doesLikeTrains = function() {
return this.likesTrains;
};
// Lets make objects!
var elem1 = new CustomElement(true);
var elem2 = new CustomElement(false);
// use object property and inherited properties
// we can still use the element ok
document.body.appendChild(elem2.nativeElement);
elem1.doesLikeTrains(); // prints true
elem2.doesLikeTrains(); // prints false :(
The DOM element assigned to the nativeElement property. This means you may add other properties without changing the native element object, but still have access to them. Both elem1 and elem2 inherit the same doesLikeTrains property with the same value, but each have their own likesTrains property, which is initialised in the constructor, and can keep a value specific to the object instance.
The advantage of this is that you could change the doesLikeTrains function to always return true, and because all objects created using your CustomELement constructor inherit the same prototype, all objects would then like trains regardless!
How would one create children like objects?
To emulate a child structure, consider...
function CustomOtherElement(likesTrains, runsOnCoal) {
// create new object and inherit from CustomElement
function EmptyConstructor() {}
EmptyConstructor.prototype = new CustomElement(likesTrains);
// add extra stuff to CustomOtherElements only
EmptyConstructor.runsOnCoal = runsOnCoal;
EmptyConstructor.isTrainSuperFan = function () {
return "Hoot hoot, chugga chugga!";
}
// return the new object
return new EmptyConstructor();
}
// now you can do
var elem3 = CustomOtherElement(true, true);
document.body.appendChild(elem3.nativeElement);
elem3.doesLikeTrains(); // true
elem3.isTrainSuperFan(); // "Hoot hoot, chugga chug!"
The above uses this new CustomOtherElement constructor to make an object that inherits CustomeElement and then add some new properties to this new object. Now you can use both the inherited properties from CustomElement and the new ones created on elem3! Happy Javascripting!
Resource: ECMAScript Language Specifications 5.1 section 4.2.1 (Objects)
Consider the approach sometimes called "parasitical inheritance". In this pattern, you write a constructor function, but return something else after adding methods/properties to it, such as
function CustomElement() {
var elt = document.createElement('div');
///--------
Some custom properties
///--------
elt.customMethod = function(args) {
///--------
Some code here
///--------
};
return elt;
}
var myCustomElement = new CustomElement();
This can be simpler, and more reliable, than trying to subclass HTMLElement, which can be a delicate operation, or wrapping the underlying HTML element, as other answers suggest.
Some might complain that the above approach is fat or slow because the "prototype" methods are being placed on each instance. However, that's something that's not really an issue on modern machines and browsers.
In any case, once we've come this far, we need to ask why we are trying to use constructors and new at all, when we can simply say:
function makeCustomElement() {
var elt = ...;
// set custom properties
// set custom methods
return elt;
}
var myCustomElement = makeCustomElement();
Defining a "subclass" is as simple as:
function makeCustomElementSubclass() {
var elt = makeCustomElement();
// set custom properties and methods
return elt;
}
In none of the cases above are prototypes being used (except methods on the built-in prototype such as HTMLElement). They're not really necessary. As I understand it, this is the direction in which mega-guru Douglas Crockford has gravitated in his style. Many cases where we see people using prototypes, it is a matter of "let me figure out a way to do this using prototypes, because they exist and I sort of think I'm supposed to be using them", or "let me figure out a way to do this using prototypes because they sort of behave like the classes I'm used to from C++/Java/C#", or "let me use prototypes to do this because putting methods once on prototypes is so much more efficient than putting them on each object"--but none of these are compelling reasons.

using this. in javascript object definition

So I am new to object definition in Javascript, and am trying to write a program that revolves objects as a practice. My problem is that when I am trying to define the object, some of the object properties are dependent on other parts of the object. I am not sure if this is even permitted, because in all my searching I have not been able to find any examples of it.
My question is basically this: can I use previously defined properties of an object to define that object. The most basic example of this would be something like this:
var alfred = {
dogs: 1,
cats:this.dogs+1,
}
Is this permitted? if so is this the right syntax? The reason I need to use a "this." is because I am pushing newly created objects to a array of objects.The code of mine that is not working is below:
obj.push({
canvas:document.getElementById(canvasName),
canvasName:"canvas"+objNum,
image: img,
width:objWidth,
height:objHeight,
centerX:posX,
centerY:posY,
speed:speeds,
hypSquare:Math.sqrt((this.width*this.width)+(this.height*this.height)),
angleInSquare:Math.atan(this.height/this.width),
angle:startAngle,
angleTotal:this.angle+this.angleInSquare,
offX:(this.hypSquare* Math.cos(this.anglesTotal))/2,
offY:(this.hypSquare* Math.sin(this.anglesTotal))/2,
centeredX:this.centerX-this.offX,
centeredY:this.centerY-this.offY,
})
when I call a
console.log(obj[objNum].hypSquare);
(where objNum is just the index of the object in the array) I will get NaN even though if I call
console.log(obj[objNum].width);
I will get the value of objWidth. Is there just a syntactical issue, or is my understanding of objects fundamentally flawed...
Thank you in advance for your time!
Isaac
No, you can't do that. You have to close the object initializer and then add the other property, e.g.:
var alfred = {
dogs: 1
};
alfred.cats = alfred.dogs + 1;
So for your obj.push call, you'll have to use a temporary variable (like alfred above), you can't just use an inline object initializer.
You cannot do that. However, you can use object constructors.
function Person(canvasName, objNum) {
this.canvas = document.getElementById(canvasName);
this.canvasName = "canvas" + objNum;
...
this.centeredY = this.centerY - this.offY;
}
obj.push(new Person("alfred", 3));

Prototype object can be changed from instance

Could someone explain this to me in a sensible way:
function One() {}
One.prototype.obj = { key: 'value' };
One.prototype.str = 'string';
var inst1 = new One(),
inst2 = new One();
// now let’s change some things in our second instance
inst2.obj.key = 'buh!';
inst2.str = 'buh!';
// ok, so what happens to our other instance?
console.log( inst1.str ); // Yields 'string' (unaffected, expected)
console.log( inst1.obj.key ); // Yields 'buh!' (!!)
console.log( One.prototype.obj.key ); // is also 'buh!'
It seems that if a prototype contains an object, the instance you create using the new keyword has that object, but if you change it, you also change the prototype object, thus affecting all instances, like a sibling-inheritance-pattern...
Is this the way it’s suppose to work?
Actually, Javascript doesn't copy anything from the prototype. Everything you define on the prototype exists only once (on the prototype itself) and gets reused because the same prototype instance is passed to all objects.
When you access a property on an object, the object checks to see if it is defined on itself. If it is, it will return the value associated with that property. If it's not, it will delegate the call to its prototype, who will from now on be responsible for what happens. That's why "inheritance" (code reuse) in Javascript is better called delegation.
Things are a bit different for write access. If you set a property on the object, it will "shadow" the value locally. That's the reason why the str property is unaffected, it has actually been defined on the inst2 object. But if you delete inst2.str and do another console.log( inst2.str ) you will notice that it will return the old value.
PS:
If you want a way to prevent that from happening have a look at this tutorial: http://kevlindev.com/tutorials/javascript/inheritance/index.htm
I recommend reading the entire thing, but if you just want the meat see the KevLinDev.extend function in the "Creating a subclass" section.
In short, yes. Javascript does not implicitly copy objects for you, so when you create the object literal at obj, all instances of the One class simply refer to it via reference. Instead, you need to dynamically create the obj object in the constructor:
function One(){
this.obj = {key:'value'};
}
See also: javascript multidimensional object

Categories

Resources