the "new" word changes a function to an object? - javascript

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

Related

Cannot Access Getter Method on __proto__

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

How do I call a js prototype method from within the constructor function?

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

Underscore chaining inner workings

I'm, curios how the _.chaining function is implemented and how (or better, why) it works the way it does.
Especially my question is where does the wrapping for each function happen. Let's assume I'm using _.chain(someArray).filter(...); When I step into the function, I can see that the filter function got transformed into something like
function () {
var args = [this._wrapped]; //the data from chain(...)
push.apply(args, arguments); //push to the (?) array
return result.call(this, func.apply(_, args)); //?? where are these coming from?
}
I can see that the function has 3 Closures in it's scope (compare this to the un-chained function that show the definition of the function without all the Closure to it's original function)
The first one is the find function itself, the second "the safe reference to the object itself" and the third on the underscore class itself.
When calling _.chain(), how and where (code-wise) does the transformation (the creating of the scopes etc). I can see that
//http://underscorejs.org/docs/underscore.html#section-139
_.chain = function(obj) {
return _(obj).chain();
};
gets called and this goes to
//http://underscorejs.org/docs/underscore.html#section-145
//...
chain: function() {
this._chain = true;
return this;
},
//...
Then I'm stuck. I can't figure out what happens from there. I assume that the magic happens inside the constructor, but I can't seem to figure out where the additional creation of the Closures comes in. All the functions themselves don't show any sign of being wrapped, the chain call doesn't look like it wraps something. result seems to be there but I don't know where it came from. So, where and how does this happen?
_.chain(obj) returns new instance of _ with attribute _chain = true, that instance of _ has a _wrapped attribute set to current object (great work here). _.mixin(_) in line #1210 add all of underscore methods to underscore (constructor). _.mixin method replace and extend _ methods (still has the parent functions! Accessible via _.prototype). _.mixin change functions of that _ instance (this is the place you see that new function).
New function is:
function () {
var args = [this._wrapped];
push.apply(args, arguments);
return result.call(this, func.apply(_, args));
}
(doesn't matter what method it is, same for all, func is referenced to the original method)
result method function is :
var result = function(obj) {
return this._chain ? _(obj).chain() : obj;
};
so if the object returned by func.apply(_, args) has _chain (_.chain set that attribute) returns _(obj).chain() then you can use it again :)
This is process of chaining but what about prototypes!
In constructor function :
var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj); // This line do the magic
this._wrapped = obj;
};
Consider this :
func = function(a){this.a = a;}
b = func(2);
b.a // TypeError: Cannot read property 'a' of undefined
c = new func(2);
c.a // returns 2, whooa this the magical javascript!
Read this (Underscore docs about OOP) if you want to learn more about underscore mixin function
Am I missing something?

Is it possible to call function.apply without changing the context?

In some Javascript code (node.js specifically), I need to call a function with an unknown set of arguments without changing the context. For example:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(this, args);
}
The problem in the above is that when I call apply, I'm change the context by passing this as the first argument. I'd like to pass args to the function being called without changing the context of the function being called. I essentially want to do this:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(<otherFn's original context>, args);
}
Edit: Adding more detail regarding my specific question. I am creating a Client class that contains a socket (socket.io) object among other info pertaining to a connection. I am exposing the socket's event listeners via the client object itself.
class Client
constructor: (socket) ->
#socket = socket
#avatar = socket.handshake.avatar
#listeners = {}
addListener: (name, handler) ->
#listeners[name] ||= {}
#listeners[name][handler.clientListenerId] = wrapper = =>
# append client object as the first argument before passing to handler
args = Array.prototype.slice.call(arguments)
args.unshift(this)
handler.apply(this, args) # <---- HANDLER'S CONTEXT IS CHANGING HERE :(
#socket.addListener(name, wrapper)
removeListener: (name, handler) ->
try
obj = #listeners[name]
#socket.removeListener(obj[handler.clientListenerId])
delete obj[handler.clientListenerId]
Note that clientListenerId is a custom unique identifier property that is essentially the same as the answer found here.
If I understand you correctly:
changes context
| n | y |
accepts array n | func() | func.call() |
of arguments y | ???????? | func.apply() |
PHP has a function for this, call_user_func_array. Unfortunately, JavaScript is lacking in this regard. It looks like you simulate this behavior using eval().
Function.prototype.invoke = function(args) {
var i, code = 'this(';
for (i=0; i<args.length; i++) {
if (i) { code += ',' }
code += 'args[' + i + ']';
}
eval(code + ');');
}
Yes, I know. Nobody likes eval(). It's slow and dangerous. However, in this situation you probably don't have to worry about cross-site scripting, at least, as all variables are contained within the function. Really, it's too bad that JavaScript doesn't have a native function for this, but I suppose that it's for situations like this that we have eval.
Proof that it works:
function showArgs() {
for (x in arguments) {console.log(arguments[x]);}
}
showArgs.invoke(['foo',/bar/g]);
showArgs.invoke([window,[1,2,3]]);
Firefox console output:
--
[12:31:05.778] "foo"
[12:31:05.778] [object RegExp]
[12:31:05.778] [object Window]
[12:31:05.778] [object Array]
Simply put, just assign the this to what you want it to be, which is otherFn:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(otherFn, args);
}
'this' is a reference to your function's context. That's really the point.
If you mean to call it in the context of a different object like this:
otherObj.otherFn(args)
then simply substitute that object in for the context:
otherObj.otherFn.apply(otherObj, args);
That should be it.
If you bind the function to an object and you use everywhere the bound function, you can call apply with null, but still get the correct context
var Person = function(name){
this.name = name;
}
Person.prototype.printName = function(){
console.log("Name: " + this.name);
}
var bob = new Person("Bob");
bob.printName.apply(null); //window.name
bob.printName.bind(bob).apply(null); //"Bob"
One way that you can work around the change of context that can happen in JavaScript when functions are called, is to use methods that are part of the object's constructor if you need them to be able to operate in a context where this is not going to mean the parent object, by effectively creating a local private variable to store the original this identifier.
I concede that - like most discussions of scope in JavaScript - this is not entirely clear, so here is an example of how I have done this:
function CounterType()
{
var counter=1;
var self=this; // 'self' will now be visible to all
var incrementCount = function()
{
// it doesn't matter that 'this' has changed because 'self' now points to CounterType()
self.counter++;
};
}
function SecondaryType()
{
var myCounter = new CounterType();
console.log("First Counter : "+myCounter.counter); // 0
myCounter.incrementCount.apply(this);
console.log("Second Counter: "+myCounter.counter); // 1
}
These days you can use rest parameters:
function fn(...args) {
otherFn(...args);
}
The only downside is, if you want to use some specific params in fn, you have to extract it from args:
function fn(...args) {
let importantParam = args[2]; //third param
// ...
otherFn(...args);
}
Here's an example to try (ES next version to keep it short):
// a one-line "sum any number of arguments" function
const sum = (...args) => args.reduce((sum, value) => sum + value);
// a "proxy" function to test:
var pass = (...args) => sum(...args);
console.log(pass(1, 2, 15));
I'm not going to accept this as an answer, as I'm still hoping for something more suitable. But here's the approach I'm using right now based upon the feedback on this question so far.
For any class that will be calling Client.prototype.addListener or Client.prototype.removeListener, I did added the following code to their constructor:
class ExampleClass
constructor: ->
# ...
for name, fn of this
this[name] = fn.bind(this) if typeof(fn) == 'function'
message: (recipient, body) ->
# ...
broadcast: (body) ->
# ...
In the above example, message and broadcast will always be bound to the new ExampleClass prototype object when it's instantiated, allowing the addListener code in my original question to work.
I'm sure some of you are wondering why I didn't just do something like the following:
example = new ExampleClass
client.addListener('message', example.bind(example))
# ...
client.removeListener('message', example.bind(example))
The problem is that every time .bind( ) is called, it's a new object. So that means that the following is true:
example.bind(example) != example.bind(example)
As such, the removeListener would never work successfully, thus my binding the method once when the object is instantiated.
Since you seem to want to be using the bind function as it is defined in Javascript 1.8.5, and be able to retrieve the original this object you pass the bind function, I recommend redefining the Function.prototype.bind function:
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
/** here's the additional code **/
fBound.getContext = function() {
return oThis;
};
/**/
return fBound;
};
Now you can retrieve the original context that you called the bind function with:
function A() {
return this.foo+' '+this.bar;
}
var HelloWorld = A.bind({
foo: 'hello',
bar: 'world',
});
HelloWorld(); // returns "hello world";
HelloWorld.getContext(); // returns {foo:"hello", bar:"world"};
I was just reminded of this question after a long time. Looking back now, I think what I was really trying to accomplish here was something similar to how the React library works with its automatic binding.
Essentially, each function is a wrapped bound function being called:
function SomeClass() {
};
SomeClass.prototype.whoami = function () {
return this;
};
SomeClass.createInstance = function () {
var obj = new SomeClass();
for (var fn in obj) {
if (typeof obj[fn] == 'function') {
var original = obj[fn];
obj[fn] = function () {
return original.apply(obj, arguments);
};
}
}
return obj;
};
var instance = SomeClass.createInstance();
instance.whoami() == instance; // true
instance.whoami.apply(null) == instance; // true
Just push properties directly to the function's object and call it with it's own "context".
function otherFn() {
console.log(this.foo+' '+this.bar); // prints: "hello world" when called from rootFn()
}
otherFn.foo = 'hello';
otherFn.bar = 'world';
function rootFn() {
// by the way, unless you are removing or adding elements to 'arguments',
// just pass the arguments object directly instead of casting it to Array
otherFn.apply(otherFn, arguments);
}

How does jQuery have the $ object constructor and the methods associated with the $?

How is it that jQuery can do $("#foo").addClass("bar") and $.ajax()?
I'm creating a micro javascript framework and want to create a new instance of an object, such as $("#hello"). With this object there are associated methods, such as addClass, css, etc, just like with jQuery. So I could do something like
$("#foo").addClass("remove").css("color", "red");
I have been successful in creating this. However, when I want to call a method from this object, such as $.ajax, the constructor function is overwritten, and I can call $.ajax, but not $("#foo").
Basically, how can jQuery do both?
$ = function(arg) { console.log("$ function called with " + arg); }
$.ajax = function(arg) {console.log("$.ajax called with " + arg);}
$('foo');
$.ajax('bar');
http://jsfiddle.net/ac7nx/
I don't think there's any magic here. $ is just a name for the global function. Just keep in mind that in javascript, functions are first class objects that can have their own properties, including sub-functions, which is what $.ajax is.
Since you mentioned the constructor function, I should note that there are no OO objects being used here, just regular functions (no new keyword), so constructor functions don't play into this. If you are using the new keyword, that is probably where you are getting confused. If you want $('#foo') to return a new object, then inside the $ function's code you should create a new object using new and return that, which is what jQuery does, but the $ function itself is not a constructor and should not be called with new. Or in the case of something like $('#someID'), inside that function jQuery is getting an element object from the DOM and then returning that object, but still $ is just a regular function whose return value is an object, not a constructor function.
OK, the $ function is not only a function but an object, like all functions. So it can have methods. That's all that ajax is, a method of the $ function. So we can start off by doing this:
$ = function(obj) {
// some code
};
$.ajax = function (arg1, arg2) {
// some ajax-y code
};
So far so good. Now, what on earth do we put in the $ function? Well it has to return an object and that object has to have some nice methods defined on it. So we'll need a constructor function (to give us new objects) and a prototype (to provide the nifty methods for those objects).
$ = function(obj) {
var myConstructor = function (obj) {
this.wrappedObj = obj;
};
myConstructor.prototype = {
niftyMethod: function () {
// do something with this.wrappedObj
return this; // so we can chain method calls
},
anotherNiftyMethod: function (options) {
// do something with this.wrappedObj and options
return this;
}
};
return new myConstructor(obj);
};
So there we have it. We can do this:
var mySnazzObject = $("whatever");
mySnazzObject.niftyMethod().anotherNiftyMethod(true);
And we can do this:
$.ajax("overthere.html", data);
Obviously jQuery does a heck of a lot more than that, and it does it in some really impressive ways, but that's the general idea.
UPDATE: AS #Raynos was kind enough to observe without supplying a constructive answer, my original code would create the prototype ad infinitum. So we make use of an anonymous autoexecuting function to declare the constructor and prototype separately:
(function () {
var myConstructor = function (obj) {
this.wrappedObj = obj;
};
myConstructor.prototype = {
niftyMethod: function () {
// do something with this.wrappedObj
return this; // so we can chain method calls
},
anotherNiftyMethod: function (options) {
// do something with this.wrappedObj and options
return this;
}
};
var $ = function(obj) {
return new myConstructor(obj);
};
$.ajax = function (arg1, arg2) {
// some ajax-y code
};
window.$ = $;
}());
Two different things:
$.ajax is a prototyped function of jQuery called ajax.
While $('foo') is a call of the jQuery function and depending on the type of foo it reacts in different ways. At http://api.jquery.com/jQuery you can see that jQuery (almost the same as $) can react on three different types: selectors, html or callbacks.
You can imitate the magic jQuery behaviour as following:
//define
var _$ = {};
var $ = function(selector) {
_$.html = function(args) {
alert("Doing the method 'html' with arguments " + args
+ " for selector " + selector);
return _$; //needed for pipeline
};
return _$;
};
$.ajax = function(args){alert("Doing the method 'ajax' "); }
//and try
$("selector1").html("args1").html("args2");
$.ajax("args2");

Categories

Resources