I was learing prototypes in Javascript and got a lot about their usages. But I'm confused about the following that how it didn't work.
function Employee(name)
{
this.name = name;
}
Employee.prototype.code = "SIMPLE";
Employee.prototype.getName = function()
{
return this.name;
}
var a = new Employee("Manish");
var b = new Employee("Vikash");
a.__proto__.code // SIMPLE
a.__proto__.getName() // Undefined
Why we can't access a function on __proto__ while a.__proto__ == Employee.prototype returns true.
The context ( aka this ) is determined in javascript when you call a function. So here:
a.__proto__.getName()
the context is a.__proto __ , and that has not a name property, so it returns undefined. Here:
a.getName()
you call getName with the context being a, and a has a name...
You can access the function on the __proto__ object like you expect - but you're getting this behavior because you lose the binding to this when you call it this way so the function is not returning what you expect. The value of this is determed by the calling context. For the purpose of experimenting, you can try adding the binding back like this:
a.__proto__.getName.bind(a)()
// Manish
// or
a.__proto__.getName.call(b)
// Vikash
Related
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;
// }
I've read the similar questions on SO and can't figure out what I'm doing wrong. I can't call the prototype method from within the constructor method.
I get: Uncaught TypeError: Object # has no method 'afterLoad'
var FiltersByDivision = function () {
$(document).on('afterLoad', this.afterLoad());
};
FiltersByDivision.prototype.afterLoad = function (){
console.log('afterLoad');
}
function OpenOrders() {
Widget.call(this);
FiltersByDivision.call(this);
this.widgetEndpoint = '/xxxxx';
}
OpenOrders.prototype = Object.create(Widget.prototype);
OpenOrders.prototype.constructor = OpenOrders;
There are a number of problems with this code:
You aren't inheriting from FiltersByDivision so thus an OpenOrders object does not have any FiltersByDivision methods. That's the reason why there is no afterLoad method.
$(document).on('afterLoad', this.afterLoad()); will execute this.afterLoad() immediately and pass it's return result as the event handler (which is not what you want). After you fix item 1, perhaps, you want $(document).on('afterLoad', this.afterLoad.bind(this));
There are many possible structures here. If FiltersByDivision is a separate object, then perhaps OpenOrders should just have one of those objects in its instance data like this (though if all it is doing is setting up an event handler, I'm not sure why it is a separate type of object):
var FiltersByDivision = function () {
$(document).on('afterLoad', this.afterLoad.bind(this));
};
FiltersByDivision.prototype.afterLoad = function (){
console.log('afterLoad');
}
function OpenOrders() {
Widget.call(this);
this.filter = new FiltersByDivision();
this.widgetEndpoint = '/xxxxx';
}
OpenOrders.prototype = Object.create(Widget.prototype);
OpenOrders.prototype.constructor = OpenOrders;
As jsfriend already pointed out is that afterLoad is not on ObjectOrders prototype. Doing a OtherConstructor.call does not inherit that constuctors prototype but initializes instance variables.
The value of this is the invoking object so the declaration of the function doesn't define its value but how you invoke it. You could use closures:
var FiltersByDivision = function ()
var me = this;
$(document).on('afterLoad', function(){
me.afterLoad();
});
};
More info on this, prototype and closures can be found here: https://stackoverflow.com/a/16063711/1641941
I'm stuck in some issue, a had a function like this:
var sayHi = function(string){
console.log(string + '' + this.name);
};
then i need to do :
sayHi = giveContext(sayHi,{"name":"moe"});
and then I do :
function giveContext(func,obj){
var fn = func;
fn.prototype.name = obj.name;
var myFn = new fn;
return myFn;
}
and the expected behavior would it be :
sayHi('Hello') // ==> "Hello moe"
the thing is that the "new" keyword in givecontext returns an object instead of a function.
and I'm only getting a
undefined moe
Uncaught TypeError: object is not a function
I'm missing something ?
When you are using new fn it will call the function fn as the constructor of an object, and the result is the object that was created.
Basically this:
var myFn = new fn;
works as:
var myFn = {}; // create an object
fn.call(myFn); // call the constructor with the object as context
(There are more things going on of course, but that is the important stuff for now.)
So, the function giveContext doesn't give a context to a function and return it, instead it will call the function as a constructor of an object and return the object. The code inside the function will be called already (that's why there is a console output at all), and when you are trying to use the return vale from giveContext as a function you will get an error as it's not a function at all.
There is already a built in method bind that sets the context for a function:
sayHi = sayHi.bind({"name":"moe"});
(Note the support information for the method though, it's not supported in iE 8 for example.)
You can also do the same without the bind method by creating a function that calls the function:
function giveContext(f, obj) {
return function(){
return f.apply(obj, arguments);
};
}
Yes, JavaScript is object-oriented, so when you say new fn, it creates a new object. In your setup, your function has a name property, so you should be using "Hello " + sayHi.name to get the results you expect.
You're going to want to read though this to get a good overview: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
I found something strange..
function Man(){
this.Man = "Peter";
}
after I call it. (not use it as a constructor)
Man()
I think a result will be
alert(Man.Man)//-->Peter
but.. I'm wrong , actually the result is :
alert(Man.Man)//-->undefined
alert(Man)//-->Peter
That was really confusing ,how it happened??
I'll explain you what is happening there.
1
function Man(){
this.Man = "Peter";
}
The this in Man() function is window.
2
Man();
You are calling the function. Which sets the global variable Man's value to "Peter".
Note that this.Man = "Peter" is equal to window.Man = "Peter" as this is referring to the window.
3
alert(Man.Man)
The function call Man(); in step 2 has made the Man from a function to a string variable. Now Man is a variable whose value is a string and it doesn't contain the property Man, so it is undefined.
4
alert(Man)
Now, you are actually alerting the global variable which was created in Man() call and it was set the value of "Peter"
I used the chrome console and had some other findings
function Man(){
this.Man = "Peter";
console.log("this", this);
}
Above this refers to Window. If you call the function Man() nothing is returned since the function does not return anything but sets the property Man on the window-object to be Peter. Your line Man.Man should return undefined in chrome. If you use Man().Man you will get undefined as well since this refers to the window object and the function Man() has no property Man. You could write
function Man(){
this.Man = "Peter";
return this.Man;
}
This returns the value Peter. If you want to have a property Man you could use a constructor function write
// set this.Man == window.Man to Peter
function Man() { this.Man = "Peter"; }
// create an constructor for each object Man
Man.prototype = { constructor: this.Man }
// create an object
var man = new Man();
// call his property which was set in the constructor of the prototype
man.Man;
Please ask for more help if anything is unclear.
Update as response to the comment
You can use a constructor without using prototype (see examples at mdn or this question if you use this syntax:
function Box(color) // Constructor
{
this.color = color;
}
var redBox = new Box("red");
var blueBox = new Box("blue");
redBox.color; // returns red
blueBox.color; // returns blue
To understand where this refers to you can take a look at understanding javascript this. In the box-example this refers to the new instance (object) of the "underlying class function". In function Man(){this.Man = "Peter"} the this refers to this.window. You can read more about protype in this book.
Is there any difference when I explicitly return from a function vs. implicitly return?
Here's the code that puzzles me ATM:
function ReturnConstructor(arg){
// Private variable.
var privateVar = "can't touch this, return ctor.";
// This is what is being exposed to the outside as the return object
return {
print: function() {
console.log("ReturnConstructor: arg was: %s", arg);
}
};
}
function NormalConstructor(arg){
// Private variable.
var privateVar = "can't touch this, normal ctor";
// This is what is being exposed to the outside as "public"
this.print = function() {
console.log("NormalConstructor: arg was: %s", arg);
};
}
var ret = new ReturnConstructor("calling return");
var nor = new NormalConstructor("calling normal");
Both objects ('ret' & 'nor') seem the same to me, and I'm wondering if it's only personal preference of whomever wrote whichever article I've read so far, or if there's any hidden traps there.
When you use new, there's an implicit value. When you don't use new, there isn't.
When a function called with new returns an object, then that's the value of the new expression. When it returns something else, that return value is ignored and the object implicitly constructed is the value of the expression.
So, yes, there can be a difference.
Implicit return only happens for single statement arrow functions, except When arrow function is declared with {}, even if it’s a single statement, implicit return does not happen:
link