How to access a variable using new Person(name, description)? - javascript

While looking at the Cookie Clicker source code I noticed a peculiar system of Game objects, he used new Game.Building("cursor"...). I then decided I would test this with my own code so I did the same thing with a basic user variable.
AI.User = function(username, password) {
try {
this.username = username;
this.password = password;
this.setUsername = function(username) { this.username = username; };
this.setPassword = function(password) { this.password = password; };
this.getUsername = function() { return this.name; };
this.getPassword = function() { return this.password; };
this.GetUserByUsername = function(username) { };
return true;
}
catch(err) {
console.log(err);
return false;
}
};
new AI.User("John Smith", "JSmith42");
The problem is I do not know how to access the variable created.

Object-Oriented Programming in JavaScript
When you use a function with the new operator (i.e. as a constructor), it essentially wraps the function in a little extra code to create a new object, which it sets to this, and then returns that object at the end. **So to save the results of the call, you just assign it to a variable, like var myUser = new AI.User("John Smith", "JSmith42");
Getting into the details, you could think of it sort of like this. The code I'm about to give isn't a perfect match for what actually goes on behind the scenes, but it covers the basics:
function constructObject(constructor) {
var newPrototype = constructor.prototype || Object.prototype,
newThis = Object.create(newPrototype),
constructorResult;
constructor.apply(
newThis,
Array.prototype.slice.call(arguments, 1)
);
if (constructorResult !== undefined) {
return constructorResult;
}
return newThis;
}
When you call "new Constructor(a, b, c)", it's essentially like calling "constructObject(constructor, a, b, c)" as I mention here.
"Object.create" in line 2 creates a brand-new object, whose prototype is equal to whatever we pass in. Note that newPrototype gets picked up from from either constructor.prototype or, if that doesn't exist, Object.prototype. This "newPrototype" object then becomes the prototype of the object that we pass around.
"constructor.apply" then calls the constructor, with our newThis object set to this for that call, and passes in whatever other arguments we might have but leaves the constructor out. We save the return value of the function, even though it's bad practice for constructors to return anything.
Here's a gotcha: if for some reason the constructor returned an object, then we return that instead of the object we made. Otherwise, we return our new object. This is one of the big points where my code isn't a perfect match for what really happens, because the engine has better ways to examine what was or wasn't returned.
It's not good practice to use new without saving the result in a variable. It works, but it looks really strange, and I suspect this is part of why you were confused when you saw it.
Object-Oriented Programming in Cookie Clicker
Cookie Clicker essentially implements its own simple "OO-like" system on top of JavaScript's. There are three kinds of objects: Game.Object, Game.Upgrade, and Game.Achievement. There's no inheritance, prototypal or otherwise, but because it works through a series of callback functions, there's still a kind of polymorphism.
The new operator works just like it does in standard JavaScript. The key is that all three of the basic constructors save a reference to this every time they're called, in one of three lists within the Game object. That's how Cookie Clicker keeps tabs on the objects it creates without saving them in variables: it actually does, just not "in the open". The end result is almost like a kind of table (among other things, as the Game object is huge).
It is probably not a good idea to imitate this style. It reads like no other JavaScript code out there, which is probably a large part of why it confused you so much. Orteil himself seems to be moving away from it: the source code to Idle Game Maker (his follow-up engine) bears a strong resemblance to Cookie Clicker's, but the object system is gone. This is black magic: it's an interesting study in the esoteric details of JavaScript, but not something you should actually practice.
Which, given the themes of Cookie Clicker, is entirely appropriate.

If you're asking why create a variable like that, it's because it's a constructor for that variable. Instead of creating a User object with no name or password and setting it later, you can just call the constructor and fill in the proper parameters with the values you pass in.

This is a simple way to use OO style in javascript.
You can refer to this post if you like to read more.

You need to capture the result of the new expression in a variable:
var user = new AI.User("John Smith", "JSmith42");
console.log(user.getUsername();); // outputs "John Smith"
Note that you can also use a function's .prototype property to create your getters and setters once, rather than having to re-create them every time someone creates a new object. Here's an example of that from an article I wrote:
function Person(first, last)
{
this.first = first;
this.last = last;
}
var john = new Person("John", "Doe");
var mary = new Person("Mary", "Deer");
Person.prototype.full = function() {return this.first + " " + this.last;};
alert(john.full()); // "John Doe"
There are a lot of things happening here.
We create a function, which will set properties on its this object when called.
We create two separate instances of that function by putting the new keyword before our function calls. This ensures that john and mary refer to completely separate objects, each with their own first and last properties.
We create a new function and assign it to the full property on our Person function's prototype property. The prototype property exists on all functions, and allows you to define fall-back properties that should exist on every object created from that function.
We call the full() function on john. JavaScript sees that the john object doesn't actually have a full function on it, so it looks for a Person.prototype.full() function and calls that instead. Within that call, however, this still refers to the john object.

Related

Encapsulation / Data Hiding in Javascript?

I would like to understand the concept of Encapsulation in JavaScript, and how to make my properties and methods public or private.
I'm playing around with this example:
var person = function(newName, newAge) {
// Private variables / properties
var name = newName;
var age = newAge;
// Public methods
this.getName = function() {
return name;
}
// Private methods
var getAge = function() {
return age;
}
// Public method, has acces to private methods
this.giveAge = function() {
return getAge();
}
}
var jack = new person("Jack", 30);
console.log(jack.name); // undefined
console.log(jack.getName); // Jack
console.log(jack.getAge()); // TypeError: jack.getAge is not a function
console.log(jack.getAge); // undefined
console.log(jack.giveAge()); // 30
So, variables var name and var age are private. To access them I use public methods by using .this reference. So anything that is var inside my function is private, and anything that's .this inside my object is visible outside.
I guess that's cause person is visible, so it exposes all of its properties.
Am I on the right track? Is this the right way to hide or expose your properties / methods?
And one more question, why does console.log(jack.getAge()); throws an error? And when referencing functions I "stored" in variables, should I put () at the end of that function, it works both ways, so I don't know what do use?
Thanks!
I guess that's cause person is visible, so it exposes all of its properties.
Correct.
Am I on the right track? Is this the right way to hide or expose your properties / methods?
If you want to do it, then yes, this is a fairly standard way to do it. There's at least one other way as of ES2015, but with (probably) more overhead.
And one more question, why does console.log(jack.getAge()); throws an error?
Because the jack object doesn't have a getAge property, so jack.getAge yields undefined, which isn't a function. There's a getAge variable inside the context that the giveAge closure has access to (along with age and name), but jack doesn't have a getAge property.
And when referencing functions I "stored" in variables, should I put () at the end of that function, it works both ways, so I don't know what do use?
No, it doesn't work both ways. jack.getName gets a reference to the function. jack.getName() calls the function and gets its return value.
I should note that there's no point to the getAge function. It's only accessible to closures defined within the person function, just like age and name are. So anything that would use getAge would just use age instead and avoid the function call.
Just for completeness, I'll note that many people don't worry about truly private properties in JavaScript, opting instead for "private by convention" — e.g., they use a naming convention (such names starting with _) to mean "don't touch these, they're private." That doesn't do anything to prevent people using them, of course, it just indicates that they shouldn't. Folks advocating this usually point out that in many languages with "true" private properties/fields (Java, C#), those properties/fields are accessible with only a small amount of effort via reflection. And so, the argument goes, just using a naming convention is "as private."
I'm not agreeing (nor particularly disagreeing) with that, it does require rather more work in Java or C# to access private properties than public ones. I'm just noting that the "private by convention" approach is quite common, and frequently "good enough."
I guess that's cause person is visible, so it exposes all of its properties.
not exactly. First of all, person is a regular function. it can perfectrly be called without the new-keyword, but the results will blow up your whole application.
To understand why, you should first understand what the new-keyword does behind the scenes. This would be an js-implementation:
function fakeNew(constructor, ...args){
if(typeof constructor !== "function"){
throw new TypeError(constructor + " is not a constructor");
}
//create a new Instance of the constructors prototype-property
var instance = Object.create(constructor.prototype);
//invoke the constructor with the scope set to the instance and the provided arguments
var result = constructor.apply(instance, args);
//check wether the returned value is an Object (and functions are considered as Objects)
if(result === Object(result)){
//then return the result-value in favor to the instance
return result;
}
//otherwise return the instance
return instance;
}
On the other hand, any function can also be a constructor; no special needs, it's all up to you.
So back to jack
var jack = person("Jack", 30); //would result in the following desaster:
console.log(jack); //undefined, since person doesn't return anthing
console.log(jack.getName());
//will throw, since jack is still undefined, and therefore doesn't have any properties
//BUT:
console.log(window.getName()) //will return "Jack" now
console.log(window.getAge); //undefined, but this is fine
//global scope has not been polluted with this one, cause getAge was a local variable inside the function-call
console.log(window.giveAge()) //can still call the enclosed (private) function getAge()
then
var jill = person("Jill", 28);
//will overwrite the global functions and expose new values now
console.log(window.getName(), window.giveAge()) //"Jill", 28
//and Jack is kind of gone, well the variable is left but the variable contained undefined, so...
next thing is scoping. let's assume you made this correct
//first let's add a function that executes on the scope
//inside the constructor
this.getNameAndAge = function(){
return this.getName() + ": " + getAge();
}
.
var andy = new person("Andy", 45);
var joe = new person("Joe", 32);
//let's make Andy a little younger
andy.getNameAndAge = joe.getNameAndAge;
console.log(andy.getNameAndAge(), andy.getName() + ": " + andy.giveAge());
//will result in "Andy: 32", "Andy": 45
waaaaat?
well you've overridden the public method getNameAndAge.
the name is accessed by invoking the (also public) method getName() on the current Object.
but giveAge() still the enclosed variable from the scope where this specific "instance of the getNameAndAge-function" was declared, and therefore it's from Joe's function call.
To understand the impacts of this, let's make the scoping even more weird
funciton Animal(species, _name){
//species is likewise a local variable and can be enclosed, modified, or whatever
//we don't need to write it to some different variable
//but we want to expose the name of this animal, since it should be possible to change it later
//without the need to create a getter and a setter just to change the property of _name
this.name = _name;
this.whoAreYou = function(){
//so we concat the enclosed value from species with the name-argument on this object
//in the hope that everything will be alright.
return species + " " + this.name;
}
}
var jack = new Animal("dog", "Jack");
var jill = new Animal("cat", "Jill");
var joe = new Animal("fish", "Joe");
console.log(jack.whoAreYou()); //"dog Jack"
console.log(jill.whoAreYou()); //"cat Jill"
console.log(joe.whoAreYou()); //"fish Joe"
//as far so good; till now ...
//since these properties are still writable someone will start and move them around
//maybe like a callback
function someFunction(someArg, callback){
console.log(someArg, callback());
}
someFunction("Who are you?", jack.whoAreYou);
//or sth. like this:
//you may not believe that someone would ever do that, but it will happen!
jack.whoAreYou = jill.whoAreYou;
console.log(jack.whoAreYou());
//and now the poor dog has an Identity-crisis.
//the first one will result in:
"Who are you?", "dog undefined"
//the latter will log "cat Jack"
or even more fummy if sth. like this happens:
var fn = joe.whoAreYou;
console.log(fn.call(jack), fn.call(jill), fn.call(joe), fn.call(Animal));
//cause now they are all fishes, even the Animal-constuctor
I don't want to say that this is bad, or that you should avoid it but there is the way that it works, and that should be considered.
cause this way provides us with prototypal inheritance, and a great way to write mixins, without writing wrapper-methods all the time.
You can look at that as "i need to secure my private state", or "I work in whatever enviorment you provide to me"
And one more question, why does console.log(jack.getAge()); throws an error?
because jack.getAge is undefined and undefined is no function
var getAge = function() {
return age;
}
another comment to this line
in JS function- and variable-declarations are hoisted and therefore available from the beginning of the function. Expressions are not.
var person = function(){
//...
foo();
bar();
baz();
function foo(){ console.log("this will work"); }
var bar = function(){ console.log("this will fail"); }
//because to this point, bar was delared and assigned with undefined,
//and we remember? undefined can't be invoked
return whatever;
function baz(){ console.log("event this would work"); }
//unless some preprocessor decided (falsely), that this function can be removed
//since it is after the return-statement, and is therefore unreachable
}

Accessing variables in a constructor function using a prototype methode

Why can't i access the variable HTML in the constructor function using the prototype method .nextSlide?
function test(root){
var HTML = getAllHTML();
function getAllHTML(){
var boss, expoHTML;
var boss = document.querySelector(root);
expoHTML = {
slides: boss.querySelectorAll(".slide"),
prev: boss.querySelector(".control.prev"),
next: boss.querySelector(".control.next"),
current: boss.querySelector(".slide-current"),
total: boss.querySelector(".slide-total")
}
return expoHTML;
}
}
EXPOjs.prototype.nextSlide = function(){
alert(HTML.current)
}
var newTEST = new test(".ieps");
newTEST.nextSlide();
It's a "scope" problem; every variable in Javascript has a scope, which means: "who can see this variable"?
In your case, HTML is defined in the function test(). This means that it will be visible:
Within the function test()
Within any functions defined within test()
That's it. Outside test(), HTML will be empty.
Now, I can see that you are using test() as a constructor function. With this, you enter the wonderful world of object creation and Javacript. Take a deep breath :D
When you do this:
function Person( age ){
this.age = age;
}
And then you do:
var pavlo = new Person( 23 );
Basically "new" has the effect of:
Creating an empty object
Running your function so that this points to the newly created object
Assign the newly created object to pavlo
This trickery means that you can do
var pavlo = new Person( 23);
console.log( pavlo.age );
And then there are prototype functions.
If you define a function like this:
Person.prototype.setAge = function( newAge){
this.age = newAge();
}
Any function (or any variable for that matter) defined in Person's prototype object will also be accessible to any object created using that constructor. Plus, the this variable will be the object making that call.
So, if you have:
function Person( age ){
this.age = age;
}
Person.prototype.setAge = function( newAge){
//`this` at this point is the object "calling" <-- This will throw an error if left uncommented.
this.age = newAge();
}
var pavlo = new Person( 23 );
console.log( pavlo.age );
// pavlo is making the call. So, within `setAge()`, `this` will be `pavlo`
pavlo.setAge( 26 );
So, for your solution:
function test(root){
this.HTML = getAllHTML();
// etc.
}
And then your alert should be:
test.prototype.nextSlide = function(){
alert(this.HTML.current);
}
Note that in Javascript you should have constructor functions starting with a capital letter (see: Test rather than test).
If you don't want HTML to be accessible from the outside, convention says that you normally put an underscore in front of the variable's name (call it _HTML ).
There are other ways of doing it, if you absolutely have to keep that variable hidden away from the developers. However, it's not exactly straightforward and -- most developers would say -- definitely not worth the effort.
A couple of good reads (but, I must say that I read them when I was starting with JS, and they confused the hell out of me at the time :D )
http://javascript.crockford.com/private.html (you know crockford, right? :D )
http://phrogz.net/JS/classes/OOPinJS.html (read it only when you have really understood the previous article)
UPDATE: This is another fantastic article on this matter: https://blog.jcoglan.com/2012/01/19/the-cost-of-privacy
Enjoy!
You're trying to access the property inside Test, but test is not part of Expojs. Then you're trying to extend the prototype of Expojs which is a bad idea because it's never a good idea to create new members for code which you don't control.
If you want nextSlide to be part of Test then you have to use Test.prototype.nextSlide(), which would create a new prototype member for the test object called nextSlide(). Then the public instance members would be accessible, such as this.getallHTML = function(){//usual stuff};
You need to use this keyword for the variables you want to access on a basic level.
After that there is the issue of abstraction which you have to consider if you want to protect the code from being used wrongly by others.
I've just been doing lots of tutorials on object orientation in JavaScript and as you can see I've learnt loads on this so far (still learning so I may not have everything right here), but I recommend doing some more study.

Difference between two JS examples?

I've written a JS object that obfuscates email addresses, however I've discovered two slightly different ways of doing so (each with 1 private method and 1 public method):
Object 1:
var email = new function()
{
function encrypt(code, key)
{
<eliminated for brevity>
};
this.mailto = function(address, name)
{
link = encrypt(<code>, <key>);
document.write(''+ name +'');
}
};
Object 2:
var email = function()
{
function encrypt(code, key)
{
<eliminated for brevity>
};
return {
mailto: function(address, name)
{
link = encrypt(<code>, <key>);
document.write(''+ name +'');
}
};
}();
Both of these syntaxes work and can be called with:
email.mailto('example', 'Example');
I'm particularly interested in memory usage or extensibility.
It looks to me as if Object 1 would create a new instance every time it's called?
What are the differences?
It looks to me as if Object 1 would create a new instance every time it's called?
No. You're doing this with the new keyword already (and once only), email is a static object.
What are the differences?
The first email object does inherit from an extra prototype object that is not apparent in the code. Yet, it does e.g. store the initialisation function, making it non-anonymous. You could create another instance of your module by
var email2 = new (email.constructor)();
This is completely superfluous and probably unintentional.
I'm particularly interested in memory usage
The first option does have an additional prototype object and needs to hold the constructor function in memory, while the second one can garbage-collect the IEFE after it was used. Use the second pattern only, avoid the first one.

What are the differences between these three patterns of "class" definitions in JavaScript?

Are there any important/subtle/significant differences under the hood when choosing to use one of these four patterns over the others? And, are there any differences between the them when "instantiated" via Object.create() vs the new operator?
1) The pattern that CoffeeScript uses when translating "class" definitions:
Animal = (function() {
function Animal(name) {
this.name = name;
}
Animal.prototype.move = function(meters) {
return alert(this.name + (" moved " + meters + "m."));
};
return Animal;
})();
and
2) The pattern that Knockout seems to promote:
var DifferentAnimal = function(name){
var self = this;
self.name = name;
self.move = function(meters){
return alert(this.name + (" moved " + meters + "m."));
};
}
and
3) a similar, simple pattern I've often seen:
var DifferentAnimalWithClosure = function(name){
var name = name;
var move = function(meters){
};
return {name:name, move:move};
}
and
4) The pattern that Backbone promotes:
var OneMoreAnimal= ClassThatAlreadyExists.extend({
name:'',
move:function(){}
});
Update 1: Changed pattern #2 and added pattern #3 in response to Elias' response // minor formatting
Just to be clear: JS doesn't know of classes, just objects and custom, self-defined constructor functions, but that's besides the point.
To answer your question in short: yes, there are some small and even some fairly large differences between the various ways of creating a new object you're posting here.
CoffeeScript:
This is actually the most clear-cut and traditional way to create your own constructor, but it has been "optimized" in the sense that it's been ready set-up to use (optional) closure variables.
Basically, what this code does, is use an IIFE, to wrap both the constructor definition and the proptotype method assignments in their own, private scope, that returns a reference to the new constructor. It's just clean, simple JS, no different from what you might write yourself.
Knockout:
Now this threw me a little, because to me, at least, the snippet you provide looks either like part of a module pattern, or a power constructor. But since you're not using strict mode, omitting the new would still make for dangerous situations, and since the entire function goes trough the trouble of creating a new instance of DifferentAnimal, only to then construct a second object literal, assigning all properties of DifferentAnimal to that secondary object, I'd say you're missing something. Because, truth be told, omitting the last return {}; statement here, would probably make no difference at all. Plus: as you can see, you're declaring a method (move) in what is, in essence, a constructor. This means that every instance will be assigned its own function object move, rather then getting it from the prototype.
In short: have another close look at where you got this snippet from, and double-check if this is the full version, because if it is, I can only see arguments against this.
Using a variable, defined inside the constructor is simply: a closure, suppose your properties have a distinct initial state, determined by some arguments, passed to that constructor:
function MyConstructor(param)
{
var paramInit = param/2;//or something
this.p = paramInit;//this property can change later on, so:
this.reInit = function()
{//this method HAS to be inside constructor, every instance needs its own method
this.p = paramInit;//var paramInit can't, it's local to this scope
};
}
var foo = new MyConstructor(10);
console.log(foo.p);//5
foo.p = 'hi';
console.log(foo.p);//hi
foo.reInit();
console.log(foo.p);//5
console.log(foo.paramInit);//undefined, not available outside object: it's a pseudo-private property
That's all there is too it, really. When you see ppl using var that = this; or something, that's often to create a reference to the main object that is available anywhere, without having to deal with the headaches of this (what does this reference? What should the method do when applied to an object other than the one it was originally intended for? etcetera...)
Backbone:
Here, we're dealing with another case: extending objects (IE: using methods, properties of either an existing "class" (constructor) or a particular instance) is not the same as simply creating an object.
As you well know, JS objects can be assigned new properties at any given time. Those properties can be removed, too. Sometimes, prototype properties can be redefined on the instance itself (masking the prototypal behaviour) etc... So it all depends on what you want the resulting object (the newly created object, that extends the given instance) to look like: do you want it to take all properties from the instance, or do you want both objects to use the same prototype somewhere down the line?
Both of these things can be achieved by using simple JS, too, but they just take a bit more effort to write yourself. However, if you write, for example:
function Animal(name)
{
this.name = name;
}
Animal.prototype.eat= function()
{
console.log(this.name + ' is eating');
};
That could be deemed the equivalent of writing:
var Animal = Object.extend({name:'',eat:function()
{
console.log(this.name + ' is eating');
}});
A lot shorter, but lacking the constructor.
new vs Object.create
Well, that's an easy one: Object.create just is a lot more powerful that new: you can define prototype methods, properties (including weather or not they are enumerable, writeable etc...) right at the time you need to create an object, instead of having to write a constructor and a prototype, or create an object literal and mess around with all those Object.defineProperty lines.
The downsides: Some people still aren't using ECMA5 compliant browsers (IE8 is still not quite dead). In my experience: it does become quite hard to debug sizeable scripts after a while: though I tend to use power-constructors more than I do regular constructors, I still have them defined at the very top of my script, with distinct, clear and quite descriptive names, whereas object-literals are things I just create "on-the-fly". Using Object.create, I noticed I tend to create objects that are really a little too complex to qualify as actual object literals, as though they are object literals:
//fictional example, old:
var createSomething = (function()
{
var internalMethod = function()
{//method for new object
console.log(this.myProperty || '');
};
return function(basedOn)
{
var prop, returnVal= {};
returnVal.myProperty = new Date();
returnVal.getCreated = internalMethod;//<--shared by all instances, thx to closure
if (!basedOn || !(basedOn instanceof Object))
{//no argument, or argument is not an object:
return returnVal;
}
for (prop in basedOn)
{//extend instance, passed as argument
if (basedOn.hasOwnProperty(prop) && prop !== '_extends')
{
returnVal[prop] = basedOn[prop];
}
}
returnVal._extends = basedOn;//<-- ref as sort-of-prototype
return returnVal;
};
}());
Now this is pretty verbose, but I've got my basic constructor ready, and I can use it to extend an existing instance, too. It might seem less verbose to simply write:
var createSomething = Object.create(someObject, {getCreated:function()
{
console.log(this.myProperty);
},
myProperty:new Date()});
But IMO, this makes it harder on you do keep track of what object is created where (mainly because Object.create is an expression, and will not be hoisted.Ah well, that's far from a conclusive argument of course: both have their pro's and con's: I prefer using module patters, closures and power constructors, if you don't that's just fine.
Hope this cleared up a thing or 2 for you.
The first example puts the move function in the prototype which will be shared between all Animal instances.
The second example creates a new move function for every the animal instance.
The third example generates a Animal class with the move function in the prototype similar to the first example but with allot less code.
(In your example the name is also shared between all instances, which you probably don't want)
Putting the function in the prototype makes instantiating Animals faster, and because of the way JIT engines work even the execution of the function is faster.

javascript : function and object...?

Can you call a function as an object? For example:
function Tip(txt){
this.content = txt;
this.shown = false;
}
And:
var tip = new Tip(elem.attr('title'));
My questions:
Can you call new for a function, as for an object?
The use of "this" is made possible, because we use that function as an object?
You are looking for the constructor concept.
All functions in JavaScript are objects and can be used to create objects:
function make_person(firstname, lastname, age) {
person = {};
person.firstname = firstname;
person.lastname = lastname;
person.age = age;
return person;
}
make_person("Joe", "Smith", 23);
// {firstname: "Joe", lastname: "Smith", age: 23}
However, in order to create new objects of a particular type (that is to say, that inherit a prototype, have a constructor, etc), a function can reference this and if it is called with the new operator then it will return an object with all of the attributes that are defined on this in the function - this in such cases references the new object we are creating.
function make_person_object(firstname, lastname, age) {
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
// Note, we did not include a return statement
}
The key difference to note between make_person and make_person_object is that calling new make_person() (as opposed to simply make_person()) will not do anything different ... both will produce the same object. Calling make_person_object() without the new operator however, will define your this attributes on the current this object (generally window if you are operating in the browser.)
Thus:
var Joe = make_person_object("Joe", "Smith", 23);
console.log(Joe); // undefined
console.log(window.firstname) // "Joe" (oops)
var John = new make_person_object("John", "Smith", 45);
console.log(John); // {firstname: "John", lastname: "Smith", age: 45}
Also, as #RobG points out, this way of doing things creates a reference to the prototype property of make_person_object on each "Person" we create. This enables us to add methods and attributes to persons after the fact:
// Assuming all that came before
make_person_object.prototype.full_name = "N/A";
make_person_object.prototype.greet = function(){
console.log("Hello! I'm", this.full_name, "Call me", this.firstname);
};
John.full_name // "N/A"
John.full_name = "John Smith";
make_person_object.full_name // Still "N/A"
John.greet(); // "Hello! I'm John Smith Call me John"
Convention has it that constructor functions like make_person_object are capitalized, singularized and "nouned" (for lack of a better term) -- thus we would have a Person constructor, rather than a make_person_object which might be mistaken for an ordinary function.
See also:
The new operator
bobince's great introduction to subclassing in JavaScript (both with and without prototype inheritance.)
Every function has a reference to this. if you call Tip(), this will refer to the global object. If you call new Tip(), a new object with a reference to Tip.prototype is created and this will refer to that new object.
You can't use new on objects, for instance new {} throws TypeError: object is not a function. If you are refering to new Object() then that works since Object is a function.
Yes. In JavaScript, technically everything is an object. When you use new, it creates an instance of the Tip object and then calls the Tip function as if it were a constructor.
If you want to add functions to the Tip object, you should add them to Tip's prototype like so:
Tip.prototype.getContent = function() {
return this.content;
};
If you have that, and then you do:
var tip = new Tip("this is my content.");
alert(tip.getContent());
It'll show a message saying "this is my content."
You can only use new, however, if the object has a functional implementation. So this won't work:
var Tip = { content: txt, show: false };
var tipObj = new Tip();
I have struggled to understand these concepts(functions as objects, prototype objects, __proto__ property, constructor property) for almost 8 years(2008-2016). First I started David Flanagan "JavaScript Definitive Guide 5/6th ed" for 4-5 years after multiple readings of Chapters 6,8,9; it did not make any sense to me but after struggling on Internet I some what able to manage functions(typical C++ function with properties) as objects; because object can also have methods. And luckily in 7th year 2015, I started Wrox Nicholas C. Zakas "Professional JavaScript for Web Developers 3rd ed" Chapter 6,7; and it was really very helpful to understand above four concepts. Traditionally in C/C++/C# functions are thought of as to modify an object; or in other words they are made for the "doing something" where as Objects are made for maintaining state of global running context with methods to change its own object state. So if functions can be first class objects then why objects can not be like functions ?
The main key question here should be WHY ? Why not single conceptual entity
like "associative-function" or "chained-arguments" ? And here is my understanding:
Browser exe is a single threaded application and this exe controls calling JS interpreter with predefined scope chain(some what similar to a string of commands with arguments); now at runtime the JS engine(not interpreter) loads the code in hoisting fashion(since there is no main method so uplifting the well defined keyworded codes and its call). In this hoisted code if functions are not treated as objects then they have to be maintained on separate call context(out of scope chain) which is easily possible in c/c++/c#(bcoz of multi thread and unlimited memory) but not in JS. Hence "to-do smth on chained object" makes a java script function as first class object. In fact JS objects also do the same thing; the only difference is "calling an object" is not there in objects where as "calling a function" is chained context which make sense. Functions can also be thought of as "bunch of variables with assembly language instructions with address link(chain)". The linking part is another side of story as top->bottom linking(prototype object) vs bottom->top linking(__proto__ property) vs object blue print->object instances(constructor property). Few months back I found the following image as helpful for understanding linking.
http://judis.me/wordpress/wp-content/uploads/2015/08/JavaScriptDiagram.png "JS Object model"
for #1 : There is an object called Function (capital F)
var f = new Function("x", "y", "return x*y;");
for #2 : the "this" is different depending on innvocation pattern (as termed by Douglas Crockford). Crockford said there are 4 patterns ( method pattern , function pattern , constructor pattern , and "apply" pattern )
The function is acting as a constructor on a class. Alternatively, you could do:
function Tip(txt) {
return {
content: txt,
shown: false
}
}
and get a new instance with: var myTip = new Tip("my epic tip");
This is similar to, say, c#:
public class Tip {
string text = "";
public Tip(string txt) {
text = txt;
}
}
So, sort of. 1) You're calling new since the function is essentially acting as a class, and 2) this is referring to the current instance of the class.
In fact, every data types like array, functions are Objects.
When we take function as a class declaration, this works.

Categories

Resources