Pass javascript function as parameter and evaluate its content as class content - javascript

Is it possible to pass a function as parameter to a method and evaluate it's content as if it was part of the class?
function Class()
{
this.Method = function( param )
{
// Call "CallThis"
};
this.CallThis = function()
{
};
}
var c = new Class();
c.Method(
{
evalThisContent: function()
{
this.CallThis();
}
}
);

If I follow your intention:
function Class()
{
this.Method = function( param, name )
{
this[name] = param;
param.call(this);
};
this.CallThis = function()
{
};
}
var c = new Class();
c.Method(function() {
this.CallThis();
}, 'evalThisContent');

It's certainly possible to invoke the function, in this case with
param()
as for "as if it was part of the class", if you mean would it have access to its members through this, no it wouldn't. But you could pass in a reference to this (object of type Class) to the function and it could access its members through this reference.

I've modified the class in the way I think you may have intended, though Zirak seems to have already demonstrated the main idea.
function Class() {
}
Class.prototype.method = function(param) {
if (typeof param === 'object' && param.evalThisContent) {
param.evalThisContent.call(this);
}
};
Class.prototype.callThis = function() {
alert("I'm getting called indirectly!");
};
var c = new Class();
c.method(
{
evalThisContent: function()
{
this.callThis();
}
}
);
If you wish, you could instead add or alter "evalThisContent" dynamically on the prototype, making it available to all objects which may henceforth wish to call it:
Class.prototype.method = function(param) {
if (typeof param === 'object' && param.evalThisContent && !Class.prototype.evalThisContent) {
Class.prototype.evalContent = param.evalThisContent;
}
this.evalContent();
};
This has the advantage of not creating a function into memory each time, nor invoking it in a less than optimal way with call, while call (or apply), as in the first example, has the more commonly useful advantage of allowing each instance of the Class to use its own functions or implementations (or you could use inheritance).

Related

Determine if a JavaScript function is a bound function

Is there a way to determine if a JavaScript function is a bound function?
Example:
var obj = {
x:1
};
function printX() {
document.write(this.x);
}
function takesACallback(cb) {
// how can one determine if this is a bounded function
// not just a function?
if (typeof cb === 'function') {
cb();
}
}
takesACallback(printX.bind(obj)); // 1
takesACallback(printX); // undefined
Perhaps this is an important point. I am not asking why the second call prints undefined.
Both bound functions and arrow functions do not have a prototype property:
typeof (function() {}).prototype // 'object' as usual
typeof (function() {}).bind(null).prototype // 'undefined'!
typeof (() => {}).prototype // 'undefined'!
This is not 100% safe since you could still manually assign this property (although that'd be weird).
As such, a simple way to check for bindability would be the following:
// ES5
function isBindable(func) {
return func.hasOwnProperty('prototype');
}
// ES6
const isBindable = func => func.hasOwnProperty('prototype');
Usage:
isBindable(function () {}); // true
isBindable(() => {}); // false
isBindable(
(function () {}).bind(null)
); // false
This way you can make sure that the function that has been passed can deal with a dynamic this.
Here is an example usage for which the above fails:
const arrowFunc = () => {};
arrowFunc.prototype = 42;
isBindable(arrowFunc); // true :(
Interestingly, while bound functions do not have a prototype property they can still be used as constructors (with new):
var Animal = function(name) {
this.name = name;
};
Animal.prototype.getName = function() {
return this.name;
};
var squirrel = new Animal('squirrel');
console.log(squirrel.getName()); // prints "squirrel"
var MutatedAnimal = Animal.bind({}); // Radiation :)
console.log(MutatedAnimal.hasOwnProperty('prototype')); // prints "false"
var mutatedSquirrel = new MutatedAnimal('squirrel with two heads');
console.log(mutatedSquirrel.getName()); // prints "squirrel with two heads"
In that case, the original function prototype (Animal) is used instead.
See JS Bin, code and link courtesy of Dmitri Pavlutin.
This of course won't work with arrow functions since they can't be used as constructors.
Unfortunately, I don't know if there is a way to distinguish a bound function (usable as constructor) from an arrow function (not usable as constructor) without trying them out with new and checking if it throws (new (() => {}) throws a "is not a constructor" error).
In environments that support ES6, you can check whether the name of the function starts with "bound " (the word "bound" followed by a space).
From the spec:
19.2.3.2 Function.prototype.bind ( thisArg , ...args)
[...]
15. Perform SetFunctionName(F, targetName, "bound").
Of course that could result in false positives if the name of the function was manually changed.
One could override the existing prototype bind, tagging functions that have been bound.
A simple solution. This will likely kill certain optimizations in V8 (and possibly other runtimes) because of hidden classes, though.
(function (bind) {
Object.defineProperties(Function.prototype, {
'bind': {
value: function (context) {
var newf = bind.apply(this, arguments);
newf.context = context;
return newf;
}
},
'isBound': {
value: function () {
return this.hasOwnProperty('context');
}
}
});
}(Function.prototype.bind));
In motion:
(function (bind) {
Object.defineProperties(Function.prototype, {
'bind': {
value: function (context) {
var newf = bind.apply(this, arguments);
newf.context = context;
return newf;
}
},
'isBound': {
value: function () {
return this.hasOwnProperty('context');
}
}
});
}(Function.prototype.bind));
var a = function () {
console.log(this);
};
var b = {
b: true
};
var c = a.bind(b);
console.log(a.isBound())
console.log(c.isBound())
console.log(c.context === b);
a();
c();
You would need to write your own bind function on the prototype. That function would build an index of what has been bound.
You could then have another function to perform a lookup against the object where that index is stored.
Based on previous answers, I create a function to determine:
function isBoundFunction(func) {
if(typeof func.prototype === 'object') return false
try {
new func()
}
catch(e) {
return false
}
return true
}
This function determine three type of functions: 1. original function, whose prototype is object, 2. arrow function, which can not be used as constructor, 3. bound function.
There is a module that can help you solve this problem : bind2.
Here's a use case :
const bind2 = require('bind2');
function testFunc() {
return this.hello;
}
const context = { hello: 'world' };
const boundFunc = bind2(testFunc, context);
console.log(boundFunc.bound); // true
Full disclosure : I wrote this module.

Crockford's Prototypical Inheritance - Usage

I've been building a small JS framework for use at my job, and I'd like to employ Douglas Crockford's prototypical inheritance patterns. I think I get the general idea of how the prototype object works, but what isn't clear is the way in which I would use this pattern beyond the simplest example.
I'll flesh it out to the point that I understand it.
(function () {
'use strict';
var Vehicles = {};
Vehicles.Vehicle = function () {
this.go = function () {
//go forwards
};
this.stop = function () {
//stop
};
};
Vehicles.Airplane = Object.create(Vehicles.Vehicle());
}());
So now my Vehicles.Airplane object can go() and stop(), but I want more. I want to add takeOff() and land() methods to this object. I could just use ugly dot notation afterwards:
Vehicles.Airplane.takeOff = function () {
//take off stuff
}
But that seems wrong, especially if I were to add many methods or properties. The question asked at here seems to be very similar to mine, but the answer doesn't quite ring true for me. The answer suggests that I should build an object literal before using Object.create, and that I should pass that object literal into the create method. In the example code given, however, it looks like their new object inherits nothing at all now.
What I'm hoping for is some syntax similar to:
Vehicles.Airplane = Object.create(Vehicles.Vehicle({
this.takeOff = function () {
//takeOff stuff
};
this.land = function () {
//land stuff
};
}));
I know this syntax will break terribly with Object.create right now, because of course I'm passing Vehicle.Vehicle a function rather than an object literal. That's beside the point. I'm wondering in what way I should build new properties into an object that inherits from another without having to list them out one at a time with dot notation after the fact.
EDIT:
Bergi, after some anguished thought on the topic, I think I really want to go with what you described as the "Classical Pattern". Here is my first stab at it (now with actual code snippets rather than mocked up hypotheticals - You even get to see my crappy method stubs):
CS.Button = function (o) {
o = o || {};
function init(self) {
self.domNode = dce('a');
self.text = o.text || '';
self.displayType = 'inline-block';
self.disabled = o.disabled || false;
self.domNode.appendChild(ctn(self.text));
if (o.handler) {
self.addListener('click', function () {
o.handler(self);
});
}
}
this.setText = function (newText) {
if (this.domNode.firstChild) {
this.domNode.removeChild(this.domNode.firstChild);
}
this.domNode.appendChild(ctn(newText));
};
init(this);
};
CS.Button.prototype = Object.create(CS.Displayable.prototype, {
constructor: {value: CS.Button, configurable: true}
});
CS.Displayable = function (o) { // o = CS Object
o = o || {};
var f = Object.create(new CS.Element(o));
function init(self) {
if (!self.domAnchor) {
self.domAnchor = self.domNode;
}
if (self.renderTo) {
self.renderTo.appendChild(self.domAnchor);
}
}
//Public Methods
this.addClass = function (newClass) {
if (typeof newClass === 'string') {
this.domNode.className += ' ' + newClass;
}
};
this.addListener = function (event, func, capture) {
if (this.domNode.addEventListener) {
this.domNode.addEventListener(event, func, capture);
} else if (this.domNode.attachEvent) {
this.domNode.attachEvent('on' + event, func);
}
};
this.blur = function () {
this.domNode.blur();
};
this.disable = function () {
this.disabled = true;
};
this.enable = function () {
this.disabled = false;
};
this.focus = function () {
this.domNode.focus();
};
this.getHeight = function () {
return this.domNode.offsetHeight;
};
this.getWidth = function () {
return this.domNode.offsetWidth;
};
this.hide = function () {
this.domNode.style.display = 'none';
};
this.isDisabled = function () {
return this.disabled;
};
this.removeClass = function (classToRemove) {
var classArray = this.domNode.className.split(' ');
classArray.splice(classArray.indexOf(classToRemove), 1);
this.domNode.className = classArray.join(' ');
};
this.removeListener = function () {
//Remove DOM element listener
};
this.show = function () {
this.domNode.style.display = this.displayType;
};
init(this);
};
CS.Displayable.prototype = Object.create(CS.Element.prototype, {
constructor: {value: CS.Displayable, configurable: true}
});
I should be quite clear and say that it's not quite working yet, but mostly I'd like your opinion on whether I'm even on the right track. You mentioned "instance-specific properties and methods" in a comment in your example. Does that mean that my this.setText method and others are wrongly placed, and won't be available to descendant items on the prototype chain?
Also, when used, it seems that the order of declaration now matters (I can't access CS.Displayable.prototype, because (I think) CS.Button is listed first, and CS.Displayable is undefined at the time that I'm trying to reference it). Is that something I'll just have to man up and deal with (put things in order of ancestry in the code rather than my OCD alphabetical order) or is there something I'm overlooking there as well?
Vehicles.Airplane = Object.create(Vehicles.Vehicle());
That line is wrong. You seem to want to use new Vehicles.Vehicle - never call a constructor without new!
Still, I'm not sure which pattern you want to use. Two are coming to my mind:
Classical Pattern
You are using constructor functions just as in standard JS. Inheritance is done by inheriting the prototype objects from each other, and applying the parent constructor on child instances. Your code should then look like this:
Vehicles.Vehicle = function () {
// instance-specific properties and methods,
// initialising
}
Vehicles.Vehicle.prototype.go = function () {
//go forwards
};
Vehicles.Vehicle.prototype.stop = function () {
//stop
};
Vehicles.Airplane = function() {
// Vehicles.Vehicle.apply(this, arguments);
// not needed here as "Vehicle" is empty
// maybe airplane-spefic instance initialisation
}
Vehicles.Airplane.prototype = Object.create(Vehicles.Vehicle.prototype, {
constructor: {value:Vehicles.Airplane, configurable:true}
}); // inheriting from Vehicle prototype, and overwriting constructor property
Vehicles.Airplane.prototype.takeOff = function () {
//take off stuff
};
// usage:
var airplane = new Vehicles.Airplace(params);
Pure Prototypical Pattern
You are using plain objects instead of constructor functions - no initialisation. To create instances, and to set up inheritance, only Object.create is used. It is like having only the prototype objects, and empty constructors. instancof does not work here. The code would look like this:
Vehicles.Vehicle = {
go: function () {
//go forwards
},
stop: function () {
//stop
}
}; // just an object literal
Vehicles.Airplane = Object.create(Vehicles.Vehicle); // a new object inheriting the go & stop methods
Vehicles.Airplane.takeOff = function () {
//take off stuff
};
// usage:
var airplane = Object.create(Vehicles.Airplane);
airplane.prop = params; // maybe also an "init" function, but that seems weird to me
You got Object.create wrong. The first argument should be an object (maybe that's why people suggested you pass a literal).
In your first example, you're actually passing undefined:
Vehicles.Airplane = Object.create(Vehicles.Vehicle()); // the function call will
// return undefined
The following would work, but it's not very Crockford-ish:
Vehicles.Airplane = Object.create(new Vehicles.Vehicle());
The way I believe Crockford would do it (or, at least, wouldn't complain of):
var Vehicles = {};
Vehicles.Vehicle = {
go : function() {
// go stuff
},
stop : function() {
// go stuff
}
};
Vehicles.Airplane = Object.create(Vehicles.Vehicle, {
takeOff : {
value : function() {
// take-off stuff
}
},
land : {
value: function() {
// land stuff
}
}
});
Note that Vehicles.Vehicle is just a literal, which will be used as the prototype for other objects. When we call Object.create, we pass Vehicles.Vehicle as the prototype, and takeOff and land will be own properties of Vehicles.Airplane. You may then call Object.create again, passing Vehicles.Airplane as the prototype, if you want to create e.g. a Boeing.
The own properties passed as the second parameter are packed in an object that contains a representation of their property descriptors. The outer keys are the names of your properties/methods, and each one points to another object containing the actual implementation as the value. You may also include other keys like enumerable; if you don't they'll take the default values. You can read more about descriptors on the MDN page about Object.defineProperty.

Is it right to think of a Javascript Function Expression that uses the 'new' keyword as 'static'

I'm just trying to understand Javascript a little deeper.
I created a 'class' gameData that I only want ONE of, doesn't need a constructor, or instantiated.
So I created it like so...
var gameData = new function () {
//May need this later
this.init = function () {
};
this.storageAvailable = function () {
if (typeof (Storage) !== "undefined") {
return true;
}
else {
return false;
}
};
}
Realizing that the 'new' keyword doesn't allow it to be instantiated and makes it available LIKE a static class would be in C#.
Am I thinking of this correctly? As static?
No, it is not static because it still has a constructor property pointing to your "anonymous" function. In your example, you could use
var gameData2 = new (gameData.constructor)();
to reinstantiate a second object, so the "class" (instance actually) is not really "static". You are basically leaking the constructor, and possibly the data that is bound to it. Also, a useless prototype object (gameData.constructor.prototype) does get created and is inserted in the prototype chain of gameData, which is not what you want.
Instead, you might use
a single, simple object literal (as in Daff's answer). That means you don't have a constructor, no closure-scoped private variables (you have used none anyway) and no (custom) prototype.
the (revealing) module pattern (as in jAndy's answer). There you'd have an IIFE to create closure-scoped variables, and can return any kind of object.
an actual constructor ("class") that can be instantiated later (when needed), and yields the same singleton object always.
This is what the singleton pattern would look like:
function GameData() {
if (this.constructor.singleton)
return this.constructor.singleton;
else
this.constructor.singleton = this;
// init:
// * private vars
// * public properties
// ...
}
GameData.prototype.storageAvailable = function () {
if (typeof (Storage) !== "undefined") {
return true;
}
else {
return false;
}
};
var gameData = new GameData();
var gameData2 = new GameData();
gameData === gameData2 === GameData.singleton; // true
Yet, the prototype is quite useless because you have only one instance of GameData. It would only get interesting with inheritance.
There is no Class in ECMAscript, there is only Object.
When new is used to invoke a function, we call it a constructor function. This function somewhat auto returns a new object once it finished. Any data that is stored within that object using this (which references that newly created object) is returned as property of that object. Beside that, new sets a property called constructor to exactly this function.
In your case, you don't even really require the usage of new, you could easily re-write your code as follows:
var gameData = (function () {
var public = { },
private = { }; // any private data can get stored here
//May need this later
public.init = function () {
};
public.storageAvailable = function () {
if (typeof (Storage) !== "undefined") {
return true;
}
else {
return false;
}
};
return public;
}());
This is called the factory pattern, singleton pattern, module pattern, and there might be some other names.
I think what you are looking for is just a simple JavaScript object:
var gameData = {
//May need this later
init : function () {
},
storageAvailable : function () {
if (typeof (Storage) !== "undefined") {
return true;
}
else {
return false;
}
}
}
If you want to use private variables create a revealing module pattern style wrapper. This is basically what jAndy suggested:
var gameData = (function() {
var private = 'private variable';
return {
//May need this later
init : function () {
},
storageAvailable : function () {
if (typeof (Storage) !== "undefined") {
return true;
} else {
return false;
}
}
}
})();

Is it possible to append functions to a JS class that have access to the class's private variables?

I have an existing class I need to convert so I can append functions like my_class.prototype.my_funcs.afucntion = function(){ alert(private_var);} after the main object definition. What's the best/easiest method for converting an existing class to use this method? Currently I have a JavaScript object constructed like this:
var my_class = function (){
var private_var = '';
var private_int = 0
var private_var2 = '';
[...]
var private_func1 = function(id) {
return document.getElementById(id);
};
var private_func2 = function(id) {
alert(id);
};
return{
public_func1: function(){
},
my_funcs: {
do_this: function{
},
do_that: function(){
}
}
}
}();
Unfortunately, currently, I need to dynamically add functions and methods to this object with PHP based on user selected settings, there could be no functions added or 50. This is making adding features very complicated because to add a my_class.my_funcs.afunction(); function, I have to add a PHP call inside the JS file so it can access the private variables, and it just makes everything so messy.
I want to be able to use the prototype method so I can clean out all of the PHP calls inside the main JS file.
Try declaring your "Class" like this:
var MyClass = function () {
// Private variables and functions
var privateVar = '',
privateNum = 0,
privateVar2 = '',
privateFn = function (arg) {
return arg + privateNum;
};
// Public variables and functions
this.publicVar = '';
this.publicNum = 0;
this.publicVar2 = '';
this.publicFn = function () {
return 'foo';
};
this.publicObject = {
'property': 'value',
'fn': function () {
return 'bar';
}
};
};
You can augment this object by adding properties to its prototype (but they won't be accessible unless you create an instance of this class)
MyClass.prototype.aFunction = function (arg1, arg2) {
return arg1 + arg2 + this.publicNum;
// Has access to public members of the current instance
};
Helpful?
Edit: Make sure you create an instance of MyClass or nothing will work properly.
// Correct
var instance = new MyClass();
instance.publicFn(); //-> 'foo'
// Incorrect
MyClass.publicFn(); //-> TypeError
Okay, so the way you're constructing a class is different than what I usually do, but I was able to get the below working:
var my_class = function() {
var fn = function() {
this.do_this = function() { alert("do this"); }
this.do_that = function() { alert("do that"); }
}
return {
public_func1: function() { alert("public func1"); },
fn: fn,
my_funcs: new fn()
}
}
var instance = new my_class();
instance.fn.prototype.do_something_else = function() {
alert("doing something else");
}
instance.my_funcs.do_something_else();
As to what's happening [Edited]:
I changed your my_funcs object to a private method 'fn'
I passed a reference to it to a similar name 'fn' in the return object instance so that you can prototype it.
I made my_funcs an instance of the private member fn so that it will be able to execute all of the fn methods
Hope it helps, - Kevin
Maybe I'm missing what it is you're trying to do, but can't you just assign the prototype to the instance once you create it? So, first create your prototype object:
proto = function(){
var proto_func = function() {
return 'new proto func';
};
return {proto_func: proto_func};
}();
Then use it:
instance = new my_class();
instance.prototype = proto;
alert(instance.prototype.proto_func());

Encapsulation in javascript

I need to create simple reusable javascript object publishing several methods and parameterized constructor. After reading through several "OOP in JavaScript" guides I'm sitting here with an empty head. How on the Earth can I do this?
Here my last non-working code:
SomeClass = function(id) {
this._id = id;
}
(function() {
function intFun() {
return this._id;
}
SomeClass.prototype.extFun = function() {
return incFun();
}
})();
This is my usual approach:
MyClass = function(x, y, z) {
// This is the constructor. When you use it with "new MyClass(),"
// then "this" refers to the new object being constructed. So you can
// assign member variables to it.
this.x = x;
...
};
MyClass.prototype = {
doSomething: function() {
// Here we can use the member variable that
// we created in the constructor.
return this.x;
},
somethingElse: function(a) {
}
};
var myObj = new MyClass(1,2,3);
alert(myObj.doSomething()); // this will return the object's "x" member
alert(myObj.x); // this will do the same, by accessing the member directly
Normally the "this" keyword, when used in one of the object's methods, will refer to the object itself. When you use it in the constructor, it will refer to the new object that's being created. So in the above example, both alert statements will display "1".
An exception to this rule is when you pass one of your member functions somewhere else, and then call it. For example,
myDiv.onclick = myObj.doSomething;
In this case, JavaScript ignores the fact that "doSomething" belongs to "myObj". As a result, the "this" inside doSomething will point to another object, so the method won't work as expected. To get around this, you need to specify the object to which "this" should refer. You can do so with JavaScript's "call" function:
myDiv.onclick = function() {
myObj.doSomething.call(myObj);
}
It's weird, but you'll get used to it eventually. The bottom line is that, when passing around methods, you also need to pass around the object that they should be called on.
I usually don't worry too much about hiding the internals, although I do prefix them with underscores to mark them as not intended to be used outside the "class". Normally what I will do is:
var MyClass = function() {};
MyClass.prototype = {
_someVar : null,
_otherVar : null,
initialize: function( optionHash ) {
_someVar = optionsHash["varValue"];
_otherVar = optionsHash["otherValue"];
},
method: function( arg ) {
return _someVar + arg;
},
};
And use it as so...
var myClass = new MyClass( { varValue: -1, otherValue: 10 } );
var foo = myClass.method(6);
All vars are private:
SomeClass = function (id) {
var THIS = this; // unambiguous reference
THIS._id = id;
var intFun = function () { // private
return THIS._id;
}
this.extFun = function () { // public
return intFun();
}
}
Use THIS within private methods since this won't equal what you might expect.
From http://learn.jquery.com/code-organization/concepts/#the-module-pattern:
// The module pattern
var feature = (function() {
// private variables and functions
var privateThing = "secret";
var publicThing = "not secret";
var changePrivateThing = function() {
privateThing = "super secret";
};
var sayPrivateThing = function() {
console.log( privateThing );
changePrivateThing();
};
// public API
return {
publicThing: publicThing,
sayPrivateThing: sayPrivateThing
};
})();
feature.publicThing; // "not secret"
// logs "secret" and changes the value of privateThing
feature.sayPrivateThing();
So using returning an object that aliases its "methods" could be another way to do it.
I've read from http://www.amazon.com/Programming-Oracle-Press-Poornachandra-Sarang-ebook/dp/B0079GI6CW that it is always good practice to use getters and setters rather that accessing the variable directly from outside the object, so that would eliminate the need of returning variables by reference.
BTW you could just use this.variable to reference/declare a public variable and var variable to declare a private variable.
I know this is a late answer, but I hope it helps anyone who reads it in the future.

Categories

Resources