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.
Related
I'm learning Javascript in code academy. And I found this code:
// Our person constructor
function Person (name, age) {
this.name = name;
this.age = age;
}
// We can make a function which takes persons as arguments
// This one computes the difference in ages between two people
var ageDifference = function(person1, person2) {
return person1.age - person2.age;
}
var alice = new Person("Alice", 30);
var billy = new Person("Billy", 25);
// get the difference in age between alice and billy using our function
var diff = ageDifference(alice,billy);
And it works and returns the difference. However I was wondering why inputting Person.alice and Person.billy into ageDifference returns an error. Isn't the age stored as Person.billy.age and Person.alice.age?
Short answer, no. Person is the prototype (the analogue-but-not-same as class) for Alice and Billy. It defines the methods and fields a new object of this class can use, and is not a container for all Person objects as you imply.
The prototype, Person is by itself an object with its own fields and methods. Person.alice alludes to there being a "class field" called "alice", all Person objects will share - and of course has nothing to do with the new object you defined which happens to be stored in the variable "alice".
Bottom line, Person.alice/.billy are both undefined, and undefined.age is throwing an error.
You can think of the function
function Person (name, age) {
this.name = name;
this.age = age;
}
when used with new, as a Mold. It does not contain the new object, just builds it.
Person is just schema how to create object it is not like in normal programing languages .. Some people say the Javascript is real OOP language , because every type is object , and every function is object ... there are no classes (schemas how to create some object) , shcema for creating some object is object not class... And if you want to simulate some oop concpet you must play with prototype .. its bit wierd but prototypes are like extensions of some object , like you say .. this object will point on this location and take all code where i poiting too
function Person(age,name){
this.name = name;
this.age = age;
this.speak = function(){...}
}
function Person(age,name){
var p = {}
p.name = name;
p.age = age;
p.speak = function(){...}
return p;
}
The only difference I see is that using the first one you must call with new to let the language know its constructing a new object, is it essentially just constructing an object where 'this' refers to the new object being created??
i.e same as doing this.
{
age: 12,
name: "mark",
speak: function(){...}
}
where as the second returns an object so you can just write
Person(12,"mark")
instead of
new Person(12,"mark")
So I guess my question is, is there anything wrong with using the second version and are the differences I stated correct and are they the only differences between the two?
The first one:
function Person(age,name){
this.name = name;
this.age = age;
this.speak = function(){...}
}
Is a named constructor function.
Will work properly with instanceof Person
Is easier to do mixins or classic Javascript inheritance with
Could use the prototype for methods which may consume less memory or be faster to construct an object if there are lots of methods
Could also be designed to work without requiring new.
Is more akin to how the new ES6 class and extends syntax works which is likely how a lot of Javascript will be written in the future.
The second one:
function Person(age,name){
var p = {}
p.name = name;
p.age = age;
p.speak = function(){...}
return p;
}
Is a factory function. It creates a generic object, assigns properties to it and then returns the object.
It could be inherited from, but not in a classic way only by another factory function that knows how this object works. Some types of inheritance of mixins are not as doable with this structure.
Will not work with instanceof.
Does not and cannot use the prototype for methods.
Could be called with new and would still work (the system-created new object would just be discarded).
Can create any kind of object. It can even branch based on the arguments passed or environment and create a different kind of object based on some logic. Technically you can do this with the first style too, but it's inefficient because the interpreter creates a specific type of object and then you would return something else causing the original object that was created to then be garbage collected. So, if you're going to create multiple different kinds of objects, the second method would be more efficient at that.
Outside of these differences, the two will mostly function the same and there is nothing technically "wrong" with either method.
There are advocates for both styles of programming in Javascript and some would say there are situations where one is more appropriate than another and vice versa. I'd suggest you build a couple subclasses for this object to flush out some more of the programming differences because the subclasses will also work differently.
If you want to search for other articles on the topic, this is basically a "constructor function vs. a factory function in Javascript" which will sometimes stray into the argument for/against using the .prototype, but also tends to cover your topic too.
Here's are some articles on that specific topic (which cover a gamut of opinions):
JavaScript Constructor Functions Vs Factory Functions
Javascript object creation patterns
In defense of JavaScript’s constructors
Constructor function vs Factory functions
Factory constructor pattern
Some Useful JavaScript Object Creation Patterns
Constructors Are Bad For JavaScript
Constructors vs factories
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.
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.
I want to create a simple class in Javascript with only one public function as follows:
function A(myTitle) {
var title = "";
this.getTitle = function() {
return title;
};
title = myTitle;
};
var anInstance = new A("first");
console.log("anInstance.getTitle(): '"+anInstance.getTitle()+"'");
// expecting to return "first"
This does work as expected.
Now I want to add this class as a prototype to a new class, that includes a new title variable, so that the getTitle() method returns the value of the variable instead:
var myA = new Object();
myA.title ="second";
myA.prototype = anInstance;
console.log("myA.getTitle(): '"+myA.getTitle()+"'");
// expecting to return "second"
But instead of the expected "second", it results in the following error:
TypeError: 'undefined' is not a function (evaluating 'myA.getTitle()')
What is the problem with this function access?
Update:
The key point for my question is the following: In my application I will create several thousand instances of type "A" and several more of other comparable types. Thus memory efficiency and performance do matter. So I thought it would be great to create the according methods (several more will follow, getTitle is only one example) only once and the "data objects" reference these methods. Is this possible?
If all you want is instance variables (and that's all I see you using), what's wrong with idiomatic JavaScript:
function A(title) {
this.title = title;
};
A.prototype.getTitle = function() {
return this.title;
};
var anInstance = new A("first");
var myA = new A("second");
You can implement both Self-like prototypal OO and Smalltalk-like class-based OO on top of JavaScript, but this only makes sense in case of inheritance hierarchies, where the flat model of JS (which favors composition over inheritance - it's easy to add new methods to the prototype or apply() arbitrary constructor functions, but you'll have to jump through some hoops to make inheritance work properly) is not sufficient.
As to why your code can't work: your getTitle() method returns a lexical instead of an instance variable, which takes no part in property resolution via the prototype chain and thus can't be overwritten your way; also, .prototype is a property of constructor functions which is used to initialize the internal [[Prototype]] property of newly created instances - setting .prototype on general objects has no effect whatsoever on property resolution.
Firstly JavaScript is not a class based language.
This works just as well and am unsure what you are trying to achieve with your solution:
http://jsfiddle.net/jRtD2/