instanceof, scopes and objects - javascript

could anyone explain this behaviour to me, please?
'use strict'
var fooFactory = function() {
function foo() {
var name = "foo object";
function getName() {
return name;
}
return {
getName: getName
}
}
function getFoo() {
return new foo;
}
return {
getFoo: getFoo,
foo: foo
}
};
var factory = new fooFactory();
var bar = factory.getFoo();
console.log("is " + bar.getName() + " instance of foo: " + (bar instanceof factory.foo));
// outputs "is foo object instance of foo: false"
i don't understand, why the foo object is no instance of the foo constructor i declare inside the fooFactory.

You're explicitly returning an object from the foo function. That object is not an instance of foo. Hence bar is not an instance of foo. This is how I would rewrite your code:
var foo = fooFactory();
var bar = new foo;
console.log("is " + bar.getName() + " instance of foo: " +
bar instanceof factory.foo);
function fooFactory() {
return function () {
var name = "foo object";
this.getName = function () {
return name;
};
};
}
The reason I would write it like this is as follows:
A factory function should not be called with new. Only constructor functions should be called with new. Furthermore even if you do call fooFactory with new it would make absolutely no difference as you're explicitly returning an object literal anyway. In fact it would be slower.
Instead of returning an object with the constructor function and another function which instantiates the constructor wouldn't it be better to simply return the newly created constructor itself? Since your factory is named fooFactory I would assume that it returns foo and not an object which has a foo property.
If you're going to create a function and use it as a constructor then don't explicitly return an object from it. When you call a function using new JavaScript automatically creates a new instance of the prototype of that function and binds it to this inside the function. As long as you don't explicitly return an object from the constructor function this is returned automatically.
Hope that helps.

To clarify Aadit's answer, the problem is this line:
return {
getName: getName
}
Remove that and change "getName" to be "this.getName" and your function will work as you're expecting.
var fooFactory = function() {
function foo() {
var name = "foo object";
// changed!
this.getName = function() {
return name;
}
// no return
}
function getFoo() {
return new foo;
}
return {
getFoo: getFoo,
foo: foo
}
};
var factory = new fooFactory();
var bar = factory.getFoo();
console.log("is " + bar.getName() + " instance of foo: " + (bar instanceof factory.foo));
// true!

remove return statement in function foo()
return {
getName: getName
}
new operator implicit return child instance of function foo,
but you did explicit return object { getName: getName }
{ getName: getName } is not child of function foo

Related

What different between assigning property on Object and Object.prototype?

What different between assigning property on Object and Object.prototype?
for example
Object.test =function(){};
and
Object.prototype.test =function(){}
The first gives Object a static method that can be invoked directly from the class, without an instance. For example:
Object.test =function(){
console.log('Object test running');
};
Object.test();
Assigning a function to the prototype, on the other hand, allows for instances to run the method:
Object.prototype.test = function() {
console.log('test running on object ', this);
};
// don't use the object constructor, this is just an example:
const obj = new Object();
obj.test();
It might make a bit more sense if you didn't use the built-in Object, which everything inherits from:
function Foo() {}
Foo.checkIfFoo = function(arg) {
return arg instanceof Foo;
};
const f = new Foo();
console.log(Foo.checkIfFoo(f));
Here, foo.checkIfFoo is a helper function on Foo that checks if a passed object is an instance of Foo or not - no instance is required to run checkIfFoo. Functions on the prototype, on the other hand, require an instance to run:
function Foo() {
this.info = 'A Foo instance';
}
Foo.prototype.checkInfo = function() {
console.log(this.info);
};
const f = new Foo();
f.checkInfo();
Note that in ES6+, you can put a function directly on the class with the static keyword:
// roughly equivalent to the snippet with checkIfFoo above
class Foo {
static checkIfFoo(arg) {
return arg instanceof Foo;
}
}
const f = new Foo();
console.log(Foo.checkIfFoo(f));
Whereas a standard method lacks the static keyword:
// roughly equivalent to the snippet with checkInfo above
class Foo {
constructor() {
this.info = 'A Foo instance';
}
checkInfo() {
console.log(this.info);
}
}
const f = new Foo();
f.checkInfo();

Change function behavior without proxy

I can do something like this:
var foo = ...// some function assignment
var fooString = foo.toString()
...
// add some alert to foo
...
var fooWithAlert = new Function(forStringWithAlert)
Is there a way to mutate first foo instead of creating new function?
I need it to monkey patch some dependency without recreating whole hierarchy of objects.
I need to patch a constructor function in a library, just add an alert on every call. But without juggling with prototypes
No, you can't modify the function foo refers to. You can only make foo refer to a new function that does what you want. One way to do that is to use your toString approach, but it's best to avoid that if at all possible, because the function you get as a result will not be the same as the original; the scope it has access to will be different.
Usually, you do want a proxy/wrapper, e.g.:
// The original foo
var foo = function(arg) {
return "original foo says '" + arg + "'";
};
console.log(foo("bar"));
// Let's wrap it
(function() {
var originalFoo = foo;
foo = function() {
return originalFoo.apply(this, arguments) + " plus updated foo";
};
})();
console.log(foo("bar"));
This doesn't create a hierarchy of objects or similar, it just wraps foo.
If foo is a constructor function (let's call it Foo), you'll also want to copy Foo.prototype:
// The original Foo
var Foo = function(arg) {
this.value = "original foo";
this.arg = arg;
};
Foo.prototype.getArg = function() {
return this.arg;
};
var f1 = new Foo("bar");
console.log(f1.getArg());
// Let's wrap it
(function() {
var originalFoo = Foo;
Foo = function() {
var rv = originalFoo.apply(this, arguments);
this.arg += " (plus more from augmented foo)";
return rv;
};
Foo.prototype = originalFoo.prototype;
})();
var f2 = new Foo("bar");
console.log(f2.getArg());
And of course, if you need to wrap a function on Foo.prototype, you can do it just like foo in my first example:
// The original Foo
var Foo = function(arg) {
this.value = "original foo";
this.arg = arg;
};
Foo.prototype.getArg = function() {
return this.arg;
};
var f = new Foo("bar");
console.log(f.getArg());
// Let's wrap its getArg
(function() {
var originalGetArg = Foo.prototype.getArg;
Foo.prototype.getArg = function() {
return originalGetArg.apply(this, arguments) + " updated";
};
})();
console.log(f.getArg());
Note how it doesn't matter that we wrapped the prototype function after creating the f object.

Javascript function with methods via prototype [duplicate]

This question already has answers here:
Can a JavaScript object have a prototype chain, but also be a function?
(6 answers)
Closed 9 years ago.
What I would like to have is something like this:
var fnc = new constructor(); // --> function()...
fnc(); // --> Running main function
fnc.method(); // --> Running method
So that one could create new fnc instances, while having the methods in the constructors prototype. However, I don't seem to be able to have result of the constructor as a function, as regardless of the return clause, it seems to become a object, resulting to ..
Uncaught TypeError: Property 'fnc' of object [object Object] is not a function
:(
Edit: Added example code. So what I'm thinking is along these lines.
var constructor = function() { return function() { console.log('Running main function.') }; };
constructor.prototype.method = function() { console.log('Running method.'); }
var fnc = new constructor();
console.log('constructor: ', constructor);
console.log('fnc: ', fnc);
console.log('fnc.method: ', typeof $.method);
console.log('');
fnc();
fnc.method();
In this case, one gets the...
Uncaught TypeError: Object function () { console.log('Running main function.') } has no method 'method'
...error as the function provided by the constructor is different than the constructor itself, on which prototype chain is tacked on. Just can't seem to wrap my head around this. Did one version with jQuery like initialization, which did the trick alright but I later on found out that it ended up doing it through the empty function prototype, meaning every function got the methods.
You can not create callable objects from constructor function instances.
You could have a function that returns a callable function that has methods assigned to it:
function foo() {
function fn() {
..do stuff..
}
fn.method = function () {
..do more stuff..
};
return fn;
}
var bar = foo();
bar(); //does stuff
bar.method(); //does more stuff
You could even call the function as a constructor, but it would actually be doing the same thing as calling the function directly as a function, and not be constructing a new instance of the class:
var baz = new foo();
baz(); //does stuff
baz.method(); //does more stuff
baz instanceof foo; //false
function Constructor(n,s,r) {
this.var1 = n;
this.var2 = s;
this.var3 = r;
}
var fnc = new Constructor("Hi", 3, 6);
fnc.prototype.myMethod = function() {
console.log (this.var1);
}
You can create methods specifically to objects like this
function myObject(name)
{
this.name = name;
}
myObject.prototype =
{
getName: function()
{
console.log("Name is: " + this.name);
return this.name;
}
}
var newObj = myObject("javascript");
var objname = newObj.getName();
console.log("Name is again: " + objname);

JS: Passing a scope as argument, binding it to a function that will be returned

Is it possible to define a function in the scope of a parent function and bind an argument passed through the parent function as its scope before returning it?
Here is an example:
var myObject = {
foo: "bar"
};
var myFunction = (function() {
return function() {
return this.foo;
};
}).call(myObject);
myFunction.call(myObject); // I'd like to bind myObject as this does ...
myFunction(); // ... but I'd like to do it before invoking it, without .call() or .apply()
Or another complex example, that describes what I'm trying to do:
var createMyCopy = function(original, self) {
var copy;
eval("copy=" + original.toString());
console.log(copy()); // returns undefined
};
(function() {
var self = "Hello world",
myFunction = function() {
return self;
};
console.log(myFunction()); // returns "Hello world"
createMyCopy(myFunction);
})();
I'm trying to create a copy of a function, so that I can make changes to it without changing the original one, but I'd like to have the variables that are defined in the original one in the copy as well...
Do you mean like this?
var myObject = {
foo: "bar"
};
var myFunction = (function() {
var self = this;
return function() {
return self.foo;
};
}).call(myObject);
I think you're getting scope and context mixed up in your question.
I think you mean this:
var myFunction = (function(obj) {
return function() {
return obj.foo;
};
})(myObject);
The immediately invoked function expression is passed myObject and returns a new function in which that parameter is bound as the variable obj.
I'm not sure what you mean, but you can do this:
var myObject = {
foo: "bar"
};
function myFunction() {
return this.foo;
}
console.log(myFunction.apply(myObject)); // bar
The first argument of apply is the context (ie. what this refers to). The second argument of apply is an array of arguments (but I've omitted that here as there are no arguments).

Value of this in protoypal object in JavaScript

I'm trying something like this:
(function() {
var Foo, foo;
Foo = function(proto) {
var obj, privateMethod, publicMethod;
privateMethod = function() {
return console.log("private", this);
};
publicMethod = function() {
console.log("public", this);
return privateMethod();
};
obj = Object.create(proto);
obj.bar = publicMethod;
return obj;
};
foo = new Foo({
baz: "dooz"
});
foo.bar();
}).call(this);
Obviously this is the object itself when publicMethod is called, but is set to the global object in the privateMethod. I know it can be solved by changing:
return privateMethod();
to:
return privateMethod.call(this);
I know that this get's lost when a function is nested in a function, but did not expect that case here. Do I encounter this JavaScript bug here or is there something that I simply do not understand yet?
Context (this), in javascript, is set by how a function is called, and is in no way a property of the function itself.
obj.bar = function() { console.log(this) };
obj.bar() // obj
obj['bar']() // obj
// But break the function off the object, and this changes
fn = obj.bar
fn() // window
What this example shows us is that the the dot syntax there sets this. Think of obj.bar() is syntax sugar for obj.bar.call(obj).
So your public method gets the right this, because of how it's called in external code.
foo.bar();
But your private method is invoked with no receiver at all.
return privateMethod();
So no context is assigned, and it defaults to the global object.
So given you are creating these functions in the constructor, you have some flexibility.
You could assign the proper value of this in the constructor to something else, and use that in your private functions. (Likely the best option)
var self = this;
privateMethod = function() {
return console.log("private", self);
};
Or if your JS target engine support Function.prototype.bind (not all do, sadly) you could do:
privateMethod = function() {
return console.log("private", this);
}.bind(this);
Which will return a function that has an assigned context, no matter what.
Or you could bind it manually yourself.
_privateMethod = function() {
return console.log("private", this);
}
Foo = function(proto) {
privateMethod = function() {
_privateMethod.call(this);
}
}
You're calling foo.bar(). This means the function bar() is called on foo, meaning this is foo inside bar().
In your case foo is a Foo object obj, and bar() is publicMethod.
When publicMethod() calls privateMethod(), there's no context, so this becomes the global this (window).

Categories

Resources