1. Functions are constructors for new objects
When you call new FuncName
, the function acts as a constructor, and the value of this
inside points to the object being constructed (not the function itself). When you remove new
, this
becomes undefined
, falling back to the global object (unless you're in strict mode).
2. Functions are also objects
Every function is an instance of Function
, so the functions themselves are objects and can have have their own properties. Those properties cannot be accessed with this.propName
inside the function body, only with funcName.propName
. That's because this
inside a function is never the function object itself (unless you forced it to be, with bind
, call
, or apply
).
I hope both topics above help you understand how functions work. As for your final question: Crockford's createObject
is a different way to implement inheritance, doing basically what Object.create
does in ES5-compliant browsers. It allows an object to inherit straight from another object, without requiring you to manually create a new constructor, set its prototype
property (which is an example of a property on a function object), and create an instance with new
. Crockford prefers that, and said he stopped using new
in favor of this approach.
In response to the questions you asked in chat, here is an attempt to explain what functions are and what they do, with examples.
Functions can be just... functions
You call them, they do something:
function alertThis(what) {
alert(what)
}
alertThis("alerting something");
You can also pass them values, and have them return values
function timesTwo(num) {
return num * 2;
}
timesTwo(2); // 4
They can be passed and return anything, including objects...
function createPerson(firstName, lastName) {
return {
firstName : firstName,
lastName : lastName
}
}
var john = createPerson('John', 'Doe');
john.lastName; // "Doe"
...and other functions:
function timesN(n) {
return function(num) {
return n * num;
}
}
var timesThree = timesN(3);
timesThree(5); // 15
Functions are objects
Functions can be passed around and returned like any ordinary object. That's because they are objects. Like any object, they can have properties:
function countCalls() {
countCalls.timesCalled++;
}
countCalls.timesCalled = 0;
countCalls();
countCalls();
countCalls.timesCalled; // 2
One very important default property of functions is prototype
. It's a special property, and we'll see why.
Functions can act as constructors for new objects
Functions can behave like class constructors do in regular OO languages. When called with new
, they create a new object of a certain "class". This new object is called this
inside the function, and is automatically returned:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
var john = new Person('John', 'Doe');
john.firstName; // "John"
john instanceof Person; // true
... unless you deliberately return something else:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
var fakePerson = {
firstName : firstName,
lastName : lastName
};
return fakePerson;
}
var notPerson = new Person('John', 'Doe');
notPerson.firstName; // "John"
notPerson instanceof Person; // false
// Note: the object called 'this' inside the function is created, but
// after the function is called there is no outside reference to it.
Objects created by constructors know who created them, and can see their prototype
property
Back to a real person:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// Add something to the Person prototype
Person.prototype.sayHi = function() {
return "hi, I'm " + this.firstName;
}
var john = new Person('John', 'Doe');
john.sayHi(); // "Hi, I'm John"
john.constructor; // Person
The object john
can sayHi()
because it has access to everything inside its constructor's prototype
property. But it cannot see other properties of Person directly (only through their own constructor
property):
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
Person.timesCalled++;
// There is no 'this.timesCalled', only Person.timesCalled
}
Person.timesCalled = 0;
var john = new Person('John', 'Doe');
john.timesCalled; // undefined - john cannot be called, Person can
john.constructor.timesCalled; // 1