So I am reading up on JS with Programming JS applications and JS the goodparts. Reading through objects and functions.. which are apparently the same. According to Crockford himself (and practically everybody). But then I ask: if they are the same then why if I have an object:
var myObject = {
value: 0,
increment: function (inc) {
this.value += inc;
}
};
I can add a function like so:
myObject.double = function () {
this.value += this.value;
}
But when I have a constructor (a function..) :
var myConstructor = function() {
this.value = 0;
this.increment = function(inc){
this.value += inc;
};
};
I cannot add a function like this:
myConstructor.double = function(){
this.value += this.value;
};
But only over the prototype like this:
myConstructor.prototype.double = function(){
this.value += this.value;
};
Now how can anybody say that object and function are the same??
Interestingly, the assignment of the "double" method to the constructor does not give an error, only when you create an object afterwards with new and call the double method on this object does it give: "TypeError can not find".
Also, console.log on the constructor gives:
{ [Function] double: [Function] }
Notice the missing comma between "[Function]" and "double" by the way.. But this probably shows that really functions are actually objects because we just added the double property (a function) to this object.
But then the question becomes... why can I call new on myConstructor and not on myObject ?? How does JS distinguish between them? If they are both objects which can consists of properties, values and functions..?
EDIT: ok, so I get they are not the same, sorry for my imprecise wording. But one question remains: how does JS know the difference between an object with a function property and a constructor to which properties have been added?
var object = {
property : "value",
method: function(){
}
};
console.log(object) outputs to:
{ property: 'asdf', method: [Function] }
and
var myConstructor = function() {
this.property = "value";
this.method = function(inc){
};
};
myConstructor.property = "value";
console.log(myConstructor) outputs to:
{ [Function] property: 'value' }
So if an object has an anonymous function JS knows its a constructor? Or does it know that over the prototype maybe?
How does JS know the difference between an object with a function
property and a constructor to which properties have been added?
There are different terminologies:
Functions are objects which are Function instances.
Callable objects are objects with an internal [[Call]] method.
Constructors are objects with an internal [[Construct]] method.
Usually they coincide, so it's usual to call them all functions.
Then it's easy:
If you attempt to call an object and it has a [[Call]] method, that method will be called. Otherwise it's not callable, so error.
If you attempt to instantiate an object and it has a [[Construct]] method, that method will be called. Otherwise it's not a constructor, so error.
Moreover, there is the [[Class]] internal property, which for functions is usually "Function".
Related
What is the difference between creating an object using an inline object constructor and creating an object by immediately invoking a contructor? I have always done the latter as it free's me from having to call something like init() myself and feels like the right thing to do, but I keep seeing the object notation in other people's code and was wondering if there is another difference I am not seeing.
Example:
window.fooModule = {
init: function() {
this.bar = "cee";
doStuff();
},
doStuff: function() {
...
}
}
window.fooModule.init();
Example2:
window.fooModule = new function(){
this.bar = "Cee";
this.doStuff = function() {
...
}
this.doStuff();
}
In first notation variable fooModel is object created without constructor call, in second notation fooModel is object created with call of constructor as anonymous function, so when using new keyword constructor function is called and object is created from its prototype ( in this example no prototype is declared so it is standard object prototype).
Conclusion
Use second notation if Your object has to call some code
when is created, use first if not.
More about second notation
Second notation enables also using local ( private ) variables and functions inside constructor, because constructor give us own scope.
var obj=new function(){
var priv="Local scope variable";
var method=function(){
console.log("Local method");
};
this.doStuff=function(){
//here local methods and variables can be used
};
};
Second notation with constructor and new is more often used with standard constructor function declaration and prototype declaration. This is correct way if We need to create more then one object. Methods and every shared properties should be declared in prototype not in constructor.
var ExampleClass=function(bar){
//constructor
this.bar = bar;
};
ExampleClass.prototype.doStuff=function(){
};
Creating such object:
var a=new ExampleClass("A bar"); //a.bar is "A bar"
var b=new ExampleClass("B bar"); //b.bar is "B bar"
Objects a and b have the same prototype ( it saves memory ) but they can have different properties set in constructor.
OffTop
In javascript is so many possibilities to create objects, I have third example how run code in first notation:
window.fooModule = {
init: function() {
this.bar = "cee";
this.doStuff();
return this;//return this
},
doStuff: function() {
}
}.init();//run init after object notation
I create object and run init in one time.
let the 1st example return obj1 and 2nd example return obj2
obj1 will have [[Prototype]] is an object. This object has constructor property is "function Object()"
obj2 will have [[Prototype]] is an object. This object has constructor property is anonymous function.
The way in 2nd example is usually used to achieve something we call "singleton"
Bonus: This stuff is easy to confused, but if you want to dig deeper, here is a good post for you
https://zeekat.nl/articles/constructors-considered-mildly-confusing.html
There are objects and there are object definitions prototypes. Neither of your examples are object definitions prototypes.
window.fooModule = function(bar){
this.bar = bar;
(this.doStuff = something => {
console.log(this.bar,'is doing', something || 'something');
})();
};
[a,b]= [new fooModule('a'), new fooModule('b')];
If you simply want to create an object, then you can skip the new and this operator.
(window.fooModule = {
bar : 'Cee',
doStuff : something => {
console.log(foo.bar,'is doing', something || 'something');
}}).doStuff();
For function I can make this:
uniqueInteger.counter = 0;
function uniqueInteger() {
return uniqueInteger.counter++; // Increment and return counter property
}
Can I do this also with object method?
Yes, you can, because functions are first class objects:
In JavaScript, functions are first-class objects, because they can have properties and methods just like any other object. What distinguishes them from other objects is that functions can be called. In brief, they are Function objects.
var object = {
x: function () { return this.x.value; }
};
object.x.value = 42;
document.write(object.x());
Objects methods are functions. You can do this for any function:
var a = function () { }
a.bar = "f";
for(property in a) {
console.log(a[property]);
}
// outputs f
However, please note that "own property" has a specific meaning in javascript, to the point that it's highly recommended to check if a property is object's own property when iterating through the properties (e.g. to ignore inherited properties).
o = new Object();
o.prop = 'exists';
o.hasOwnProperty('prop'); // returns true
o.hasOwnProperty('toString'); // returns false
o.hasOwnProperty('hasOwnProperty'); // returns false
I am learning javascript and would love help understanding the snippet of code.
From Object.DefineProperties definition, the first parameter is an object. Is MyObjectConstructor a declaration or an object. With a constructor function I would expect to call new to make it an object.
This is what is confusing me. Or as I read in Javascript functions are objects so do I treat it as an object and the this property is where all staticProps and instanceProps are added to?
var _prototypeProperties = function (child, staticProps, instanceProps) {
if (staticProps){
Object.defineProperties(child, staticProps)
};
if (instanceProps) {
Object.defineProperties(child.prototype, instanceProps);
}
};
function myFunction() {
function MyObjectConstructor(element) {
this.element = element;
this.initialized = false;
}
_prototypeProperties(MyObjectConstructor, {...}, {...});
}
Yes, (constructor) functions are objects as well in javascript, and you can add properties directly to them.
The _prototypeProperties function in your example snippet does put the staticProperties on the constructor, so that they could be accessed as MyObjectConstructor.myStaticProperty. It also does put instanceProps (better: "class properties", "prototype properties") on the MyObjectConstructor.prototype object, from where they are inherited by instances: (new MyObjectConstructor).myPrototypeProperty. Lastly, your MyObjectConstructor does put "real" (own) properties on the instances, specifically (new MyObjectConstructor).element and .initialised.
In JavaScript, once defined, the resulting functions act identically:
function Hat() { }
var Hat = function() { }
Conventionally the first is used to create objects (usually with new) and the second is used as a regular method.
The new operator, when preceding a function gets kinda weird. Using the new operator will:
create a new Object "it"
set the function being called as "it"s prototype
binds "it" to this within the function
overrides the return value of the function with "it". This overrides both explicit returns and implicit returns of undefined.
For example:
// first define Hat function
function Hat() { this.color = 'red' }
// calling with `new` implicitly returns a new object bound to the function
new Hat()
// > Hat { color: "red" }
// invoking without `new` implicitly returns `unefined`,
// but `this` points to Hat's parent object.
// If running in the browser, Hat's parent object would be `window`
// so now Window.color is set to "red"
Hat()
//> undefined
Window.color
//> "red"
Be careful with new, because the new object will be returned instead of any explicit returns.
var color = function() { return "blue" }
color()
//> "blue"
new color()
//> color {}
JavaScript is prototypal by nature. The new operator reflects neither prototypical nor classical inheritance. I avoid it when possible, although many popular libraries use it.
I recommend reading through Crockford's explanation of JavaScript's prototypal inheritance: http://javascript.crockford.com/prototypal.html
Its terse, but if you understand his 10 lines of demo code you'll be good.
Play with bind, call and apply, and different scoping contexts too. After understanding scoping and the prototypal nature, the rest is just syntax.
first : the function is the first type object in the javascript . it means you can deliver the function as value . for example :
function test(){
return function(){
console.log('function');
}
}
test()();
you return the function as return an object , function can be assigned and the function another kind of value !
var test = function(i) {
// body...
return i;
}
test('123');
a character string 'test' refer to a Anonymous function , you can understand that you transmit a function to a character string .
second : if you use new to create a instance via function , this function will be called construction function , normally it used to init the params , and the instance will take the construction function own property or method and prototype's property or method from the construction function .
third : the instance's property of "__proto__" is refer to the construction function's prototype object . this is why the instance can use the prototype's property or method from the construction function .
forth : if you create the instance by new , the this will refer to the instance object ! so that instance can use the property and method .
from your code :
var _prototypeProperties = function (child, staticProps, instanceProps) {
if (staticProps){
Object.defineProperties(child, staticProps)
};
// the properties from the own construction function , like this :
// this.element = element;
// this.initialized = false;
if (instanceProps) {
Object.defineProperties(child.prototype, instanceProps);
}
};
// the properties from the construction function's prototype object . like this :
// MyObjectConstructor.prototype.name = 'somebody';
// MyObjectConstructor.prototype.getName = function(){
// return this.name;
// }
What is the difference between this two codes and which one should I use?
function Test() {}
Test.method = function() {};
With Prototype:
function Test() {}
Test.prototype.method = function() {};
1st case : static method.
function Test() {}
Test.method = function () { alert(1); };
var t = new Test;
Test.method(); // alerts "1"
t.method(); // TypeError: Object #<Test> has no method 'method'
2nd case : instance method.
function Test() {}
Test.prototype.method = function () { alert(1); };
var t1 = new Test;
var t2 = new Test;
t1.method(); // alerts "1"
t2.method(); // alerts "1"
Test.method(); // TypeError: Object function Test() {} has no method 'method'
The first example merely assigns a function to a new property of Test called method. There is nothing special or magic about it (by which I mean, the language does not do anything interesting with it). You might call this a static method, because it's shared across all instances, but it's really just a normal property. (Functions are objects and objects have properties.)
In the second case, a new method is added to Test's prototype, which makes it available to all instances of Test. This is special behavior. Every object in JavaScript has an internal link to another object, which is called its prototype. This link is established using the prototype of the constructor that created the object, so any instance created by Test will have the new property in its prototype chain.
For example:
function Test() {}
Test.method = function() {};
var a = new Test();
console.log(a.method); // => undefined
But:
function Test() {}
Test.prototype.method = function() {};
var a = new Test();
console.log(a.method); // => function
The prototype method is shared between all instances of Test.
The difference goes back to how the prototype chaining works. If you create instances of Test then they will be able to access the methods that are defined on the prototype.
The first code, simply adds a "static" method on the constructor; You won't be able to access that method doing something like this:
var testInst = new Test();
testInst.method() // Error Undefined is not a function
The only way to invoke that method is via the constructor reference i.e.
Test.method();
As i mentioned, the above is feasible if you add the method to the prototype of the constructor.
If you define a method in the prototype, any instances will be able to use that method. If you define the method as simply a part of the original object, it allows you to simply use that in a manner that one could reasonably refer to as a static method.
For example:
Array.isArray( [] ) //true
[].isArray() //throws a TypeError
The second example throws a TypeError because isArray() is not in the Array.prototype (remember, instances only access methods defined in that instance, or in that instance's prototype or __proto__ chain).
In short:
* A method defined in the original object can be accessed by that object, but not instances of that object.
* A method defined in the original object's prototype can be accessed by any instance of the original object.
Will NOT Work (for an instance)
function Test() {}
Test.method = function() {};
Will Work (for an instance)
function Test() {}
Test.prototype.method = function() {};
Why?
Assuming that you create an instance of Test:
t = new Test()
On calling a method:
t.method()
JavaScript will first look within Test, for example the 3 properties and methods will be recognized below:
function Test() {} {
this.a = "hello";
this.b = "world";
this.c = function() { alert( this.a + this.b) }
}
and then the second, the look up will be done on prototype:
Test.prototype.method = function() { console.log('prototype defined method') }
In JavaScript the below does not register to the instance t but instead Test:
Test.method = function() { console.log('something unsual') };
therefore
Test.method() // works
t.method() // no works
When trying to test prototype functionality, I got this odd result:
Here is my first test:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype.name = "Fred";
alert(a.name);
</script>
And, here's the second one:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype = {
name : "Fred",
}
alert(a.name);
</script>
I can't understand why the first will return a alert with "Fred" and the second is "undefined" though these mean the same thing?
Could you help me with it?
Thank you.
When you define a function in JavaScript, the interpreter makes a special prototype property available on the function, which points to an object, in case you use that function as a constructor. The [[Prototype]] internal property points to this object when you create a new object using the constructor.
When you replace the prototype property with a new one, you are replacing that reference, and if you do it after you instantiate an object, you will find the prototype object appears to be stale (that object's [[Prototype]] is pointing to the original object that prototype pointed to).
Solutions
Only assign new properties directly on the prototype property.
var constructor = function() { };
constructor.prototype.someMethod = function() { };
Use an extend type function to extend the existing prototype property with your new object (in this example, I used Underscore's extend() function).
var constructor = function() { };
_.extend(constructor.prototype, { someMethod: function() { } });
Make sure after the constructor, assigning the prototype property is the very next step in your program (generally not recommended).
var constructor = function() { };
constructor.prototype = { someMethod: function() { } };
Your ordering is messed up. You need assign the object to the prototype before using the new operator:
function Hello() {
}
Hello.prototype = {
name : "Fred",
}
var a = new Hello();
alert(a.name);
Demo.
The two code snippets are not actually equal.
In the first script you only override Hello.prototype.name, while in the second script you override the whole content of Hello.prototype.