46

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:

  1. Can you call new for a function, as for an object?
  2. The use of "this" is made possible, because we use that function as an object?
reformed
  • 4,505
  • 11
  • 62
  • 88
Paul
  • 6,108
  • 14
  • 72
  • 128

7 Answers7

125

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:

Community
  • 1
  • 1
Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
  • 6
    you left out the most import part: the new object referenced by a constructor's `this` inherits properties from the constructor's prototype. – RobG May 11 '11 at 03:29
  • 2
    @RobG -- well that I *did*! I have updated the answer to include some examples of this -- thanks for helping make it better! – Sean Vieira May 11 '11 at 03:40
  • 1
    Fantastic answer. Truly great. Covered what to do, and then taught me how to understand it. Each question I had reading it was answered in the following section after. Thanks!! – redfox05 Mar 04 '16 at 20:50
20

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.

Adam Bergmark
  • 7,316
  • 3
  • 20
  • 23
7

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();
Tom Chandler
  • 642
  • 3
  • 9
4

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"

Saurabh
  • 1,545
  • 1
  • 9
  • 9
1

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.

Thomas Shields
  • 8,874
  • 5
  • 42
  • 77
  • 2
    The function isn't used as an object. A new object is created when using `new` and the function is called in the scope of that function – Adam Bergmark May 11 '11 at 02:13
  • @Adam righto. I skimmed the exact phraseology of his question. lesson learned. ;-) – Thomas Shields May 11 '11 at 02:15
  • @Adam : another way to create an object is to use object literal syntax just as Thomas did . Using "new" is just one of the ways to create object. – user670800 May 11 '11 at 02:22
  • 1
    @Adam - your comment "A new object is created when using new and the function is called in the scope of that function" - is very misleading. When called with `new`, the function's `this` keyword is set to a brand new **object** whose internal [[prototype]] property is a reference to the funciton's public prototype. It is that **object** that is returned (unless some other object is explicity returned). Calling a function with `new` **always** returns an object. It has nothing whatever to do with scope, the scope of the function remains exactly as if it had been called without `new`. – RobG May 11 '11 at 03:20
  • @Thomas - firstly, there are no classes in javascript, though you can emulate classic class-based inheritance. Secondly, if the constructor returns an object other than `this`, it doesn't inherit from the constructor's prototype (so pretty pointless using `new`). – RobG May 11 '11 at 03:26
  • @RobG `this` is scoped dynamically, but yeah, perhaps it's confusing. For unknown reason's I'm always referring to the dynamic context as scope. Spec calls it `thisArg`. – Adam Bergmark May 11 '11 at 03:28
1

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 )

user670800
  • 1,107
  • 1
  • 11
  • 16
0
  1. In fact, every data types like array, functions are Objects.
  2. When we take function as a class declaration, this works.
xblymmx
  • 39
  • 2
  • 3