I would like to create a Javascript class that I can use like so:
var f = new myFunction(arg1, arg2);
f.arg1; // -> whatever was passed as arg1 in the constructor
f();
f instanceof myFunction // -> true
typeof f // -> function
I can treat it like a normal object, even adding the native Function object to the prototype chain, but I can't call it like a function:
function myFunction(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
}
myFunction.prototype = Function
var f = new myFunction(arg1, arg2); // ok
f.arg1; // ok
f(); // TypeError: f is not a function, it is object.
f instanceof myFunction // -> true
typeof f // -> object
I can have the constructor return a function, but then it's not an instance of myFunction:
function myFunction(arg1, arg2) {
var anonFunction = function() {
};
anonFunction.arg1 = arg1;
anonFunction.arg2 = arg2;
return anonFunction;
}
var f = new myFunction(arg1, arg2); // ok
f.arg1; // ok
f(); // ok
f instanceof myFunction // -> false
typeof f // -> function
Any suggestions? I should add that I really want to avoid using new Function() since I hate string code blocks.
First and foremost, you should probably be considering some other way of doing this, because it is unlikely to be portable. I'm just going to assume Rhino for my answer.
Second, I'm not aware of any way in Javascript of assigning a function's body after construction. The body is always specified as the object is constructed:
// Normal function definitions
function doSomething() { return 3 };
var doSomethingElse = function() { return 6; };
// Creates an anonymous function with an empty body
var doSomethingWeird = new Function;
Now, there's a non-standard Mozilla extension in the form of a __proto__ property on every object. This allows you the change the inheritance chain of any object. You can apply this to your function object to give it a different prototype after construction:
// Let's define a simple prototype for our special set of functions:
var OddFunction = {
foobar: 3
};
// Now we want a real function with this prototype as it's parent.
// Create a regular function first:
var doSomething = function() {
return: 9;
};
// And then, change it's prototype
doSomething.__proto__ = OddFunction;
// It now has the 'foobar' attribute!
doSomething.foobar; // => 3
// And is still callable too!
doSomething(); // => 9
// And some of the output from your example:
doSomething instanceof OddFunction; // => true
typeof doSomething; // => function
function Foo() { var o = function() {return "FOO"}; o.__proto__ = Foo.prototype; return o; }
(new Foo()) instanceof Foo: true
(new Foo())(): FOO
This isn't possible. If it should be a instance of your function then it has to be a object. Why do you want this?
I dont know why you would want to do something like this. But here's a snippet which comes close,
function MyFunction(arg1, arg2)
{
this.firstProp = arg1;
this.secondProp = arg2;
}
var f = function(arg1, arg2) {
return new MyFunction(arg1, arg2);
}(12,13);
alert("Arg1 " + f.firstProp) // 12;
alert("Arg2 " + f.secondProp) // 13;
alert(f instanceof MyFunction) // true;
Here is what I think a more javascript way of doing what you want, except it doesn't use the instanceof for objects but an inner one.
var f = function(arg1, arg2){
return {
instanceOf:arguments.callee,
arg1:arg1,
arg2:arg2
};
};
var fn = f(1, function(p){ alert(p); });
fn.arg1; // 1
fn.instanceOf === f; //true
typeof f; //function
typeof fn; //object
fn.arg2('hello'); //show alert hello
Related
function foo1(a,b){
console.log(arguments); //["oldValue","oldValue"]
var newArguments = foo2.apply(this,arguments);
for (var i=0;i<arguments.length;i++){
arguments[i] = newArguments[i];
}
console.log(arguments); //["newValue","newValue"]
}
function foo2(){
arguments[0] = "newValue";
arguments[1] = "newValue";
console.log(arguments); //["newValue","newValue"]
return arguments;
}
foo1("oldValue","oldValue");
I'd like to change foo1 arguments values by outer function foo2. I did it by returning array with new arguments in foo2 and replacing foo1 arguments with returned array in foo1. Is there any other - more elegant - way to do so?
https://jsbin.com/jibodu/1/edit?js,console
If you're returning the two new arguments from foo2 just set the arguments to that return value:
arguments = foo2();
full code:
function foo1(a,b){
console.log(arguments); //["oldValue","oldValue"]
arguments = foo2();
var newArguments = foo2.apply(this,arguments);
for (var i=0;i<arguments.length;i++){
arguments[i] = newArguments[i];
}
console.log(arguments); //["newValue","newValue"]
}
Why don't you receive the arguments directly?
function foo1() {
console.log('foo1', arguments); // foo1 { '0': 'oldValue', '1': 'oldValue' }
arguments = foo2.apply(this, arguments);
console.log('foo1', arguments); // foo1 { '0': 'newValue', '1': 'newValue' }
}
function foo2() {
arguments[0] = 'newValue';
arguments[1] = 'newValue';
console.log('foo2', arguments); // foo2 { '0': 'newValue', '1': 'newValue' }
return arguments;
}
foo1('oldValue', 'oldValue');
Update 1
Since you want to change a, b also, I would try calling foo1 "again" like below:
function foo1(a, b) {
console.log('foo1', arguments);
if (a === 'oldValue') // Detect if `arguments` has been changed or not.
// (You can also use a variable to record the change if you prefer.)
// If not, change the arguments and call `foo1` using the new arguments
return foo1.apply(this, foo2.apply(this, arguments));
console.log('foo1 (after changed)', arguments , a, b);
// Do something you want to do originally in `foo1`
}
I suppose that you can make a new function instead of change the arguments inside the foo1, since it seems a little tricky to me?
ok I found resolution. I've just changed first parameter in apply() to "arguments". Now it refers to arguments of caller function and by 'this' I can directly change its values. nonetheless thanks for support!
function foo1(a, b) {
foo2.apply(arguments,arguments);
console.log(arguments); //["newValue","newValue"]
console.log(a); //"newValue"
}
function foo2() {
this[0] = "newValue";
this[1] = "newValue";
};
foo1("oldValue","oldValue");
I'd like to add a method "bar" to a parent class A, after a subclass B are is defined, so that the method is inherited. Is it possible?
I tried the following code
function A() {
this.foo = function () {
console.log('foo')
}
}
function B() {
A.call(this)
}
// (trying to) add a new method to A
A.prototype.bar = function () {
console.log('bar');
}
// It works with instances of A
var a = new A()
a.foo() // ok
a.bar() // ok
// but not with an instance of B
var b = new B()
b.foo() // this works
b.bar() // not this one <------
/*
Exception: b.bar is not a function
#Scratchpad/3:17:1
*/
Any suggestion, please?
If you need just fix your code, you can link methods like this:
function B() {
A.call(this)
for(var i in A.prototype){ this[i] = A.prototype[i]; }
}
But i think it is bad way.
function A() {
this.foo = function () {
console.log('foo');
};
}
function B() {
A.call(this);
}
// (trying to) add a new method to A
A.prototype.bar = function () {
console.log('bar');
};
B.prototype = Object.create(A.prototype);
// It works with instances of A
var a = new A() ;
a.foo() ; // ok
a.bar() ; // ok
// but not with an instance of B
var b = new B() ;
b.foo() ; // this works
b.bar() ;
I case of functional-type of inheritance - you can't add methods, that don't exists in class. Use prototypes
// if you define the prototype as an object
var A = {
foo: function() {
console.log('foo');
}
};
// and define constructors using Object.create
function newA() {
return Object.create(A);
};
function newB() {
return Object.create(newA());
};
// you can add methods to the prototype
A.bar = function () {
console.log('bar');
};
// it works with instances of A
var a = newA()
a.foo();
a.bar();
// and instances of B
var b = newB();
b.foo();
b.bar();
// you can even modify the prototype after the fact
A.baz = function() {
console.log('baz');
};
// and that will work as well
a.baz();
b.baz();
http://jsfiddle.net/5s8ahvLq/
If you don't want the latter behavior of being able to edit the protoype after the fact, use Object.assign or something like underscore or lodash that provides that functionality:
function newA() {
return Object.create(Object.assign({}, A));
}
You're missing:
B.prototype.__proto__ = A.prototype
If you don't like using __proto__ you can use:
B.prototype = Object.create(A.prototype);
This little gem is giving me a bit of a headache. Let's say I create an object that returns a function, like this:
function Bar(prop) {
this.prop = prop;
var that = this;
return function() {
this.prop = that.prop;
}
}
var bar = new Bar();
console.log(bar instanceof Bar);
Bar() returns a function, as you can see. Now, Bar() instanceof Bar returns false, which isn't what I want. How do I check to see if a new Bar() is an instance of Bar? Is this even possible?
Returning any object from a constructor will use that object instead of returning an instance automatically generated by the constructor. It's a bit abstract, so here's an example to show my point:
function Foo() {}
function Bar() {
return new Foo();
}
f = new Foo();
console.log(f instanceof Foo); //true
b = new Bar();
console.log(b instanceof Bar); //false
console.log(b instanceof Foo); //true
Everything in JavaScript is an object, including functions, so the fact that your foo.bar function returns a function means that when you call new foo.bar() you're going to receive the function returned by foo.bar instead of a new foo.bar instance.
While I'm not 100% certain of what you're trying to do exactly, you can check whether a function is being called as an object initializer or as a function simply by using instanceof on the context. This pattern is often used for forcing object initialization:
function Foo(...arguments...) {
if (!(this instanceof Foo)) {
return new Foo(...arguments...);
}
//do stuff
}
This allows Foo to be called as a function and still return a new Foo instance:
a = new Foo(); //a instanceof Foo
b = Foo(); //b instanceof Foo
Not entirely sure why you'd want to do what you are doing but I see what the issue is.
In the scope of 'test', this.bar is the function bar(prop) rather than the function returned as a result of executing this function, if that makes sense. However, new this.bar('hi') will be first executing bar('hi'), which returns an anonymous function that then acts as the constructor.
In other words, you are comparing an instance created from the anonymous function with a different function so instanceof is correctly returning false.
The following logs 'true' but may not be what you are looking for:
function foo() {
this.test = function() {
var cls = this.bar('hi');
console.log(new cls() instanceof cls);
};
this.bar = function bar(prop) {
this.prop = prop;
var that = this;
return function() {
this.prop = that.prop;
}
}
}
var test = new foo();
test.test();
This is the code for _.bind, taken from the Underscore library. I don't understand the business of taking the empty function, changing it's prototype, etc.
var ctor = function(){};
_.bind = function bind(func, context) {
var bound, args;
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};
};
It basically is there so that if you call new bound(), you're able to bind arguments for the new call. E.g.:
var func = function(a, b) {
this.a = a;
this.b = b;
};
// context does not matter, use e.g. `null`
var bound = _.bind(func, null, 1);
new bound(2); // a = 1, b = 2
I tried to explain the code a bit.
var ctor = function(){};
_.bind = function bind(func, context) {
var bound, args;
// use native .bind if available
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
// abort if not called with a function
if (!_.isFunction(func)) throw new TypeError;
// you can also bind arguments, which come after the function and context (so .slice(2))
args = slice.call(arguments, 2);
// return the bound function
return bound = function() {
// if you simply do bound(), then `this` is the global object.
// This means the original function should be called with the
// bound `this` value and arguments. Arguments you pass to the
// bound function are concatenated to the bound arguments.
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
// otherwise, you're calling like `new bound()`, because `this instanceof bound`.
// In that case, `this` should not be passed, but only the arguments. So, you
// create a function of which the prototype is the original function's prototype,
// and create an instance of it (to mimic `new func`).
ctor.prototype = func.prototype;
var self = new ctor; // won't execute anything since ctor's body is empty.
// Just creates an instance
// then, you call the original function with the `this` value of the instance,
// with bound arguments and new arguments concatenated. This way, the constructor
// (func) is executed on the instance.
var result = func.apply(self, args.concat(slice.call(arguments)));
// finally, return the result if it's an object (the specs say `new xxx` should
// return an object), otherwise return the instance (like you would with `new func`)
if (Object(result) === result) return result;
return self;
};
};
I'm playing around with Function.prototype as a learning exercise and was trying to make a generic curry method that could be used like this:
// Any old function
var myFn = function(arg1, arg2) {
console.log(arg1, arg2);
};
// Curry some parameters and return a new function
var myFnCurry = myFn.curry("A");
// Call the curried function, passing in the remaining parameters
myFnCurry("B"); // Outputs: A B
It's fairly straight forward to implement this feature as a function rather than a method using the following approach:
var curry = function(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
fn.apply(this, args.concat(slice.call(arguments)));
};
};
// Example
var myFnCurry = curry(myFn, "A");
myFnCurry("B"); // Outputs: A B
However, I really wanted to be able to utilise the Function prototype, like this:
Function.prototype.curry = function() {
var slice = Array.prototype.slice,
args = slice.call(arguments);
return function() {
// If we call curry like this: myFn.curry()
// how can we get a reference myFn here?
???.apply(this, args.concat(slice.call(arguments)));
};
};
I'm not sure how to get a reference to the myFn function (denoted by the ??? above) that the curry method is being called from.
Is there a way to access the parent function in this circumstance?
Cheers,
Ian
You're calling curry in a context of your function object (myFn.curry), and therefore inside of curry this refers to that function. But your inner function will be called in the context of global object, that's why you need to store the reference to the outer function in a closure.
Function.prototype.curry = function() {
var self = this, args = [].slice.call(arguments)
return function() {
return self.apply(this, args.concat([].slice.call(arguments)));
}
}