We've seen an example in Constructors.
function Person(name, age) {In Person, it uses a function literal to create a function and assigns it to the toString property of this. Every time you use the constructor function to create an instance, you also create a new function.
this.name = name;
this.age = age;
this.toString = function() {
return '[' + this.name + ', ' + this.age + ']';
};
}
js> function Person(name, age) {
> this.name = name;
> this.age = age;
> this.toString = function() {
> return '[' + this.name + ', ' + this.age + ']';
> };
> }
js> var p1 = new Person('Justin', 35);
js> var p2 = new Person('Momor', 32);
js> p1.toString == p2.toString;
false
js>
> this.name = name;
> this.age = age;
> this.toString = function() {
> return '[' + this.name + ', ' + this.age + ']';
> };
> }
js> var p1 = new Person('Justin', 35);
js> var p2 = new Person('Momor', 32);
js> p1.toString == p2.toString;
false
js>
The toString function actually doesn't close any resource. For efficiency, you may code as follows:
function toString() {Although it solves the problem of repeatedly creating functions but the name 'toString' has one foot in the global scope. In fact, if you know every function has a prototype property, you can do as follows:
return '[' + this.name + ', ' + this.age + ']';
}
function Person(name, age) {
this.name = name;
this.age = age;
this.toString = toString;
}
js> function Person(name, age) {
> this.name = name;
> this.age = age;
> }
js> Person.prototype.toString = function() {
> return '[' + this.name + ', ' + this.age + ']';
> };
function () {
return "[" + this.name + ", " + this.age + "]";
}
js> var p1 = new Person('Justin', 35);
js> var p2 = new Person('Momor', 32);
js> p1
[Justin, 35]
js> p2
[Momor, 32]
js>
> this.name = name;
> this.age = age;
> }
js> Person.prototype.toString = function() {
> return '[' + this.name + ', ' + this.age + ']';
> };
function () {
return "[" + this.name + ", " + this.age + "]";
}
js> var p1 = new Person('Justin', 35);
js> var p2 = new Person('Momor', 32);
js> p1
[Justin, 35]
js> p2
[Momor, 32]
js>
When you use new and a constructor function to create an instance, JavaScript first creates a plain object and the prototype property of the constructor function is set as the prototype object of the plain object. After that, this refers to the plain object and the constructor function is called.
When JavaScript looks up a property, it first searches properties on the instance. In the above example, p1 has properties name and age so the corresponding values of them are retrieved. If the instance itself doesn't have the properties, JavaScript searches the prototype object of the instance. The prototype object is assigned when calling a constructor function. In the above example, p1 itself has no toString so JavaScript searches the prototype object of p1 and it's the same object as Person.prototype. The toString property is found on the Person.prototype so the function referred by toString is executed.
It should be noted that the prototype object is searched only if there's no property on the instance itself. If you add a property to an instance, only the instance owns the property. You don't add the property to the prototype object of the instance. For example:
js> function Some() {}
js> Some.prototype.data = 10;
10
js> var s = new Some();
js> s.data;
10
js> s.data = 20;
20
js> s.data;
20
js> Some.prototype.data;
10
js>
js> Some.prototype.data = 10;
10
js> var s = new Some();
js> s.data;
10
js> s.data = 20;
20
js> s.data;
20
js> Some.prototype.data;
10
js>
In the above example, you add a data property to s but the value of Some.prototype.data is not affected.
You can add properties to the prototype property of a constructor function at any time. New properties can be found through the prototype mechanism even if properties are added to the prototype property after an instance is created. For example:
js> function Some() {}
js> var s = new Some();
js> print(s.data);
undefined
js> Some.prototype.data = 10;
10
js> print(s.data);
10
js>
js> var s = new Some();
js> print(s.data);
undefined
js> Some.prototype.data = 10;
10
js> print(s.data);
10
js>
It's mentioned in Constructors. If you use new to create an instance, it owns a constructor property which refers to the constructor function. In fact, every time a Function instance is created, a plain object is created and set to the prototype property of the Function instance. The plain object, of course, also has a constructor property. That's why you can find the constructor property for every object because it comes from the prototype object of an instance. For example:
js> function Some() {}
js> Some.prototype.constructor;
function Some() {
}
js>
js> Some.prototype.constructor;
function Some() {
}
js>
By default, the prototype property of a Function instance refers to an instance of Object. The object referred by prototype also has a constructor property. According to the prototype mechanism, if a property is not found on prototype, it will search the prototype object of prototype. For the above example, that is Object.prototype. That's because prototype refers to an instance of Object and the prototype object of prototype is Object.prototype. If the property is still not found, you will get undefined. This is the mechanism of JavaScript prototype chains.
For example:
js> Object.prototype.xyz = 10;
10
js> function Some() {}
js> var s = new Some();
js> s.xyz;
10
js> s.__proto__ == Some.prototype;
true
js> s.__proto__.__proto__ == Object.prototype;
true
js>
10
js> function Some() {}
js> var s = new Some();
js> s.xyz;
10
js> s.__proto__ == Some.prototype;
true
js> s.__proto__.__proto__ == Object.prototype;
true
js>
In the above example, __proto__ is a non-standard property in Rhino. You can use it to get the prototype object of an instance. By default, it's the prototype property of a constructor function. Although the Some instance and Some.prototype both have no xyz, it will look up the prototype chain. The xyz property is finally found on Object.prototype. It is not recommended to add properties to Object.prototype because this will affect all instances in JavaScript. The above example is just for a demonstration.
You can also use the isPrototypeOf function to check whether an object is the prototype object of another object. For example:
js> var arr = [];
js> Array.prototype.isPrototypeOf(arr);
true
js> Function.prototype.isPrototypeOf(Array);
true
js> Object.prototype.isPrototypeOf(Array.prototype);
true
js>
js> Array.prototype.isPrototypeOf(arr);
true
js> Function.prototype.isPrototypeOf(Array);
true
js> Object.prototype.isPrototypeOf(Array.prototype);
true
js>
When for in iterates properties of an object, it will iterate all iterable properties along the prototype chain. If you delete a property of an object, it will delete the first property encountered on the prototype chain.