Override JavaScript (window) Function - javascript

I'd like to override a function which is being made by a javascript plugin. I know how to override regular window functions, but this is different. I'm not sure how to name it, but the structure of that function is like:
window.something.function
I have no idea how to override that. I have tried the following:
var originalFunction = window.something.function;
window.something.function = function(parameter) {
alert('called');
return originalFunction(parameter);
}
But it's not working.
Does someone know a solution?
Edit:
As I have been told my question is unclear, I have edited it again using the actual names of the plug-in.
The plugin is meant to be used as:
var myColor = new jscolor(target, options)
When this is being used, there is a function "inside" the object "jscolor" which is being called when setting the value of target element. I want to override that function to add an extra functionality without changing the original js file.
Code:
if (!window.jscolor) { window.jscolor = (function () {
var jsc = {
.....
jscolor : function (targetElement, options) {
....
//Function I want to change:
this.exportColor = function (flags) {
if (!(flags & jsc.leaveValue) && this.valueElement) {
var value = this.toString();
if (this.uppercase) { value = value.toUpperCase(); }
if (this.hash) { value = '#' + value; }
if (jsc.isElementType(this.valueElement, 'input')) {
this.valueElement.value = value;
} else {
this.valueElement.innerHTML = value;
}
}
}
}
};
My attempts so far:
var origJsColor = jscolor.exportColor;
jscolor.exportColor = function(flags) {
console.log('called');
return origJsColor(flags);
}
and the window attempt above.

The jscolor code you've shown creates an object with its own copy of exportColor (one is created for each object). So to replace it, you have to replace it on each instance as the instance is created.
You can do that as a one-off in much the way you showed, just working with the instance rather than the plugin function, and using Function#call to call it with the right this:
// Get the instance
var c = new jscolor(target, options)
// Update it
var origExportColor = c.exportColor;
c.exportColor = function(flags) {
console.log('called');
return origExportColor.call(c, flags); // Note the changes on this line
};
Or instead of
return origExportColor.call(c, flags);
you might use
return origExportColor.apply(c, arguments);
...if there's any chance of the function being called with anything other than exactly one argument. (arguments is a magic pseudo-array containing the arguments used to call the function.)
If you want to do that for all instance you might create, you can put a facade in front of jscolor to do that to each instance:
var realJscolor = jscolor;
jscolor = function() {
// Call the real function, passing along all the arguments we
// get automatically (`arguments` is a magic pseudo-array)
var retVal = realJscolor.apply(this, arguments);
// If it returned a non-`null` object, we want to use that instead
// of `this`; if not, we keep using `this`
if (!retVal || typeof retVal !== "object") {
retVal = this;
}
// Slip in our version of exportColor
var origExportColor = retVal.exportColor;
retVal.exportColor = function(flags) {
console.log('called');
// (Maybe use `apply` here instead)
return origExportColor.call(retVal, flags);
};
// Return the result, in case the real function overrode `this`
return retVal;
};
jscolor.prototype = realJscolor.prototype;
Then just use jscolor normally:
var c = new jscolor(target, options);
The reason for the retVal thing is that although normally a new expression's result is a refernece to the new object created by new, a constructor function can return a non-null object reference and, if it does, the new expression's result is that object reference instead. That's why we check the return value of realJscolor.
Of course, that means that all uses of jscolor on the page that use the global will now use your updated function instead. If you don't want that, just use your own name and don't override jscolor:
var myColor = function() {
var retVal = jscolor.apply(this, arguments);
// ...and so on...
return retVal;
};
myColor.prototype = jscolor.prototype;
Usage:
var c = new myColor(target, options);

Function
function a() {alert(this)} // will print `window` obejct
is defined in the window scope. That is, it is a method of the window. Your more difficult situation comes from the fact that this is different from window if you define function as a method in another object.
var a = {method: function() {alert(this)}}
you call a.method() but see that the same window again. You need to bind your function to the parent object to make it compete method.

Related

Properly get "this" in jQuery plugin member

I have a JavaScript module that I would like to create a jQuery plugin interface to.
The module itself is like this:
var Foo = (function () {
"use strict";
var self = {};
self.add = function (selector, otherParam)
{
// Does things unto selector.
// Precisely what it does doesn't matter.
};
return self;
}());
and is used, with success, like this:
Foo.add(a);
Now, I would like to create a plugin that interfaces to this module,
so I can use it somewhat like this:
$.fn.foo = Foo;
$.fn.foo.add = function (param) {
var selector = this;
Foo.add(selector, param);
}
$(elem).foo.add(a);
The problem I'm facing is that I can't get "this" working in .add().
The best way I managed to do it was to not have Foo be self-initializing,
and use a syntax like:
$.fn.foo = Foo;
$(elem).foo().add(a);
It works, but I find it less aesthatically pleasing and less "clean".
Is there a way to do this? Am I on the wrong approach altogether?
Thankful for any input, and I apologize in advance if this has already been answered or is unfit in any other way.
I did search for answers, but I'm not well-versed in plugin authoring nor an expert on jQuery itself.
TL;DR: I have a module like Foo above, and would like to access it's members like a jQuery plugin.
Here is a simplified version of the pattern I normally use (error checking and extra features removed).
It uses a single class function and a plugin bridge extension method to allow attachment to multiple elements. Methods are called by using a string option value:
var Foo = (function () {
"use strict";
// Constructor
function Foo($element, options){
this.$element = $element;
this.options = options
this.fooVal = 0;
}
// Create method (called from bridge)
Foo.prototype.onCreate = function(){
this.fooVal = ~~this.$element.text()
};
// Add the specified val to the elements current value
Foo.prototype.add = function (val) {
this.fooVal += val;
// Update the element text with the new value
this.$element.text(this.fooVal);
};
return Foo;
})();
// Create a bridge to each element that needs a Foo
$.fn.foo = function (options, args) {
this.each(function () {
var $element = $(this);
// Try to get existing foo instance
var foo = $element.data("Foo");
// If the argument is a string, assume we call that function by name
if (typeof options == "string") {
foo[options](args);
}
else if (!foo) {
// No instance. Create a new Foo and store the instance on the element
foo = new Foo($element, options);
$element.data("Foo", foo);
// Record the connected element on the Foo instance
foo.$element = $element;
// Call the initial create method
foo.onCreate();
}
});
}
// testing
console.clear();
$('#test').foo();
$('#button2').click(function () {
$('#test').foo("add", 2);
});
$('#button10').click(function () {
$('#test').foo("add", 10);
});
For your example Foo takes the initial value from the element text and subsequent "add" calls modify that value.
JSFiddle: http://jsfiddle.net/TrueBlueAussie/o2u7egfy/3/
Notes:
~~ is just a fast short-cut for parseInt()
You could supply an initial value via the options parameter (ignored in first example). See following:
e.g.
// Create method (called from bridge)
Foo.prototype.onCreate = function(){
this.fooVal = this.options.value || ~~this.$element.text()
// Set initial value
this.$element.text(this.fooVal);
};
and start with
$('#test').foo({value: 999});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/o2u7egfy/4/

Javascript: object return itself a.k.a. chaining

I am trying to build my own little jquery-like library but I'm having a really rough time with creating this chaining pattern. Basically I have one class with a bunch of methods that make it easier to manipulate the document. Here's an example
function MF(selector){
var DO; // Stands for DocumentObject
this.select = function(selector){
return document.getElementById(selector);
}
if(typeof selector === 'string'){
DO = this.select(selector);
}else if(selector instanceof HTMLElement){
DO = selector;
}
this.children = function children(selector){
return DO.getElementsByClassName(selector);
}
return {
MF: ???
}
}(null);
I might be wrong in my reflections but what I've come to figure out is that in order to have additional methods for a document object ( html element ) I either need to extend the HTMLElement prototype or pass the element along with my class. I've chosen the second option. I just can't figure out what to return in my class so that I can have chaining going on. What I simply aim at, for the sake of this example, is to be able to write the following line of code:
MF('someDiv').children('someClass');
In a desperate attempt I tried returning a new instance of MF which should not have instances by default and led myself to an infinite loop. I really cannot figure what I'm supposed to return there. Any help is greatly appreciated!
It looks like you also tried to use the module pattern, and haven't taken advantage of prototypes..
When you want to chain something, you either need to return itself (this) within the chainable methods, or return a new instance of your Object. In the example below I achieve chaining by using new instances (well the children looked like it needed to be a list so I did an Array of them).
var MF = (function () { // module pattern start
function MF(selector) {
if (!(this instanceof MF)) return new MF(selector); // always construct
this.node = null; // expose your DO
if (typeof selector === 'string') {
this.node = document.getElementById(selector);
} else if (selector instanceof HTMLElement) {
this.node = selector;
} else {
throw new TypeError('Illegal invocation');
}
}
MF.prototype = {}; // set up any inheritance
MF.prototype.select = function (selector) {
return new MF(document.getElementById(selector)); // returns new instance
};
MF.prototype.children = function (selector) {
var MFs = [],
nodes = this.node.getElementsByClassName(selector),
i;
for (i = 0; i < nodes.length; ++i) {
MFs[i] = new MF(nodes[i]);
}
return MFs; // array of items of new instances
};
return MF; // pass refence out
}()); // module pattern end
Then, for example, you can chain like..
MF(document.body).children('answer')[0].children('post-text')[0].node;
return this; will allow access to methods of the Constructor. Do it at the very bottom of the Constructor and the very bottom inside every method that belongs to it, if the method doesn't need to return another value.
function MF(selector){
var doc = document;
this.select = function(selector){
return doc.getElementById(selector);
}
// there are problems with some of your code
this.someMethod = function(){
/* do stuff - If you want to access an Element then
var thisIsNowGlobal = this.select('someId');
thisIsNowGlobal.innerHTML = 'someText';
Note, the keyword this is global not var
If you wrote this.select('someId').innerHTML the property would not exist
When a property of an Object is assigned to a variable or argument
the this value changes to the global context.
*/
return this;
}
return this;
}
You can do this pretty easily. Bear in mind that when you return this then if this has methods defined on it, then you can call them sequentially.
var MyUtilThing = function(){};
MyUtilThing.prototype.doStuff = function doStuff (){ // give it a name, helps in debugging
// do your thing
console.log('doing stuff');
return this; // this is your instance of MyUtilThing
}
var thing = new MyUtilThing();
thing.doStuff().doStuff().doStuff(); // etc
One way around having to explicitly create instances is do this in your constructor.
var MyUtilThing = function(selector){
var F = function(){};
F.prototype = MyUtilThing.prototype;
var toReturn = new F();
toReturn.initialize(selector);
return toReturn;
};
MyUtilThing.prototype.initialize = function initialize(selector){
this.selector = selector;
};
MyUtilThing.prototype.doStuff = function doStuff (){ // give it a name, helps in debugging
// do your thing
console.log('doing stuff to', this.selector);
return this; // this is your instance created in the constructor (the blank function with the same prototype as MyUtilThing)
}
var thing = MyUtilThing('div'); // no use of new here!
thing.doStuff().doStuff().doStuff(); // etc
But, getting into some slightly heavy territory there. Best bet is just to try and understand exactly how this is used in JS, and you'll get a long way.
Traditionally the way jQuery enables chaining is by creating a wrapper object for every type of return value. For example in your case it pays to create your own wrapper for HTMLElement:
function HTMLElementWrapper(element) {
if (element instanceof HTMLElementWrapper) return element;
this.element = element;
}
Now that you have an HTMLElementWrapper you can refactor your MF function as follows:
function MF(selector) {
return new HTMLElementWrapper(typeof selector === "string" ?
document.getElementById(selector) : selector);
}
The MF function now returns an HTMLElementWrapper object which has two methods select and children:
HTMLElementWrapper.prototype.select = function (selector) {
return new HTMLElementWrapper(this.element.getElementById(selector));
};
HTMLElementWrapper.prototype.children = function (selector) {
return new NodeListWrapper(this.element.getElementsByClassName(selector));
};
Ofcourse for the children function to work you'll need to create a NodeListWrapper constructor:
function NodeListWrapper(list) {
if (list instanceof NodeListWrapper) return list;
this.list = list;
}
Now you can chain methods as follows:
MF("someDiv").select("something").children("someClass");
To chain methods after .children("someClass") you need to add those methods to NodeListWrapper.prototype.

Object Oriented JavaScript programming

I have been trying to learn OOP with JavaScript before I start attempting to learn backbone.js.
I want to be able to data bind but I can't seem to get it to work.
I've just made a simple protoype of a budget website that you can put in a budget and input how much you've spent, and it will show if you've gone over.
function BudgetItem(spent, budget){
this.setSpent = function(spent){
this.spent = spent;
}
this.setBudget = function(budget){
this.budget = budget;
}
this.getSpent = function(){
return this.spent;
}
this.getBudget = function(){
return this.budget;
}
}
function BudgetType(type){
this.getType = function(){
return type;
}
}
BudgetType.prototype = new BudgetItem();
$(document).ready(function(){
var food = new BudgetType('food');
$('.budget').html(food.getBudget());
$('.editbudget').change(function(){
food.setBudget($('.editbudget').data())
});
})
That's my code thus far. I'm not sure if I'm doing it right. Am I supposed to extend things? Also, can someone explain how to dynamically data bind without a library?
First I'll give you some theory. A Javascript function is a dynamic object, just like Object is, and a new instance can be created using the new keyword much like you are doing in your listener. When this happens, the function itself will run as a constructor while the this keyword will be bound to the newly created object. What you're doing above then is in fact adding new properties on the fly as you're passing in their values for the first time... which is fine, but not very clear to another reader.
Now for the tricky part. Every function has a link to a "hidden" Prototype object. This is an anonymous (not accessible by name) object created by the JavaScript runtime and passed as a reference to the user object through the prototype property. This Prototype object also has a reference to the function through its constructor property. To test what I'm saying for yourself, try the following:
BudgetItem.prototype.constructor === BudgetItem // true
Putting it all together, you can now think of functions as constructors to (hidden) classes that are created for you behind the scenes, accessible through the function's prototype property. So, you could add the fields to the Prototype object directly as so:
function BudgetItem(spent) {
this.spent = spent
}
BudgetItem.prototype.setSpent = function(spent) { this.spent = spent };
BudgetItem.prototype.getSpent = function() { return this.spent };
Another problem is inheritance and passing parameters to the constructor. Again, your version is valid but you lose the ability to pass the spent and budget values when initializing a BudgetType. What I would do is forget prototypes and go:
function BudgetType(type, spent) {
var instance = new BudgetItem(spent);
instance.type = type;
return instance;
}
This is close to what Scott Sauyet suggested above but more powerful. Now you can pass both parameters (and more) and have a more complicated inheritance tree.
Finally, what you can do is create private (or pseudo-private, more accurately) properties by providing a getter to an otherwise automatic variable (one passed as an argument or initialised inside the function). This is a special feature of the language and it works like so:
function BudgetType(type, spent) {
var instance = new BudgetItem(spent);
instance.getType = function() {
return type;
}
return instance;
}
Now you can access the 'type' passed in the constructor by obj.getType() but cannot override the initial value. Even if you define obj.type = 'New Value' the getType() will return the initial parameter passed because it has a reference to another context which was created when the object was initialised and never got released due to the closure.
Hope that helps...
if you want all instances of objects to reference the same members/values you can use a closure:
// create a constrctor for you object wrapped in a closure
myCon = (function() {
// define shared members up here
var mySharedObj = new function () {
this.member = "a";
}();
// return the actual constructor
return function () {
this.mySharedObj = mySharedObj;
}
}());
// create two instances of the object
var a = new myCon();
var b = new myCon();
// Altering the shared object from one
a.mySharedObj.member = "b";
// Alters it for all
console.log(b.mySharedObj.member);
If you want to build objects from other objects(sort of like other languages' class whatever extends baseClass), but do not want them to share values via reference(instead a clone of values), you can use something like the following:
Object.prototype.extendsUpon = (function (_prop, _args) {
return function (base) {
for (var key in base) {
if (_prop.call(base, key)) {
this[key] = base[key];
}
}
function con(child){
this.constructor = child;
}
con.prototype = base.prototype;
this.prototype = new con(this);
this.__base__ = base.prototype;
var args = _args.call(arguments);
args.shift();
base.constructor.apply(this, args);
}
}(Object.prototype.hasOwnProperty, Array.prototype.slice));
Then to build objects ontop of objects:
// Base Object Constructor
function Fruit(name) {
this.fruitname = name;
}
Fruit.prototype.yum = function() {
return "I had an " + this.fruitname;
}
// Object constructor that derives from the Base Object
function Favorite() {
// Derive this object from a specified base object:
// #arg0 -> Object Constructor to use as base
// #arg1+ -> arguments passed to the BaseObject's constructor
this.extendsUpon(Fruit, "apple");
// From here proceed as usual
// To access members from the base object that have been over-written,
// use "this.__base__.MEMBER.apply(this, arguments)"
}
Favorite.prototype.yum = function() {
return this.__base__.yum.apply(this) + " and it was my favorite";
}
var mmm = new Favorite();
// Outputs: "I had an apple and it was my favorite"
mmm.yum();

Javascript Sandbox Pattern example implementation

On Page 101 of Stoyan Stefanov's great book "JavaScript Patterns" he explains the sandbox pattern.
I liked his book much but I really missed some real life examples here and then to better understand what he talks about.
Like the sandbox pattern!
I'm looking for a real life working implementation, like a copy&paste starting point, just a simple example that will work to fully understand it.
Is there any?
I've simplified Stoyan's example in an attempt to make it easier to understand what's going on. I've also commented it more thoroughly.
/*First define the modules of the sandbox. These will be defined
as properties on the constructor function because this is a
convenient place to keep them.*/
Sandbox.modules = {};
Sandbox.modules.returnNumbers = function(MYAPP) {
MYAPP.return100 = function() {return 100;};
};
Sandbox.modules.returnLetters = function(MYAPP) {
MYAPP.returnABC = function() {return "ABC";};
};
function Sandbox() {
/* Because Sandbox is a constructor, an new object is automatically
created. Because we're in the constructor, we refer to this new object
as 'this'.
A constructor would typically be used as part of an assignment, e.g.
myObject = new Sandbox().
However, it's also legitimate javascript to use a constructor without
the assignment by just writing new Sandbox() with no assignment. The
constructor does return an object, it's just that it doesn't get
assigned to anything so is discarded.
We're going to add functionality (methods) to the 'this' object, but
rather than returning it, we will pass it to the callback function, so
the methods can be used immediately.
*/
var args = Array.prototype.slice.call(arguments); //Put the arguments
//of the call to the Sandbox constructor in an array called args.
var callback = args.pop(); //The last argument is the callback
var requiredmodules = args; //The remaining arguments are the require
// modules
//For each of the modules in 'requiredmodules', add the module's
//methods to 'this'
for (i=0; i< requiredmodules.length; i++) {
Sandbox.modules[requiredmodules[i]](this);
}
//'this' now has methods returnNumbers and returnLetters
//Call the callback. In the example below, 'this' will be called
//MYAPP, which within the callback will have all the methods from
//the required modules.
callback(this);
}
//Finally here is an example of usage
new Sandbox('returnNumbers', 'returnLetters', function (MYAPP) {
console.log(MYAPP.return100());
console.log(MYAPP.returnABC());
});
Stoyan Stefanov mentions in the same chapter that YUI version 3 implements the Sandbox pattern. The YUI add method (API) registers modules and the use method (API) loads the specified ones in the sandbox instance. There are links to the source js file in the API documentation.
Virtually all YUI code examples use this pattern to work with the YUI library. Defining a module is rarely needed - YUI has many core ones and there is a page for custom modules added by the community.
So I tried and came up with this solution:
function Sandbox() {
// turning arguments into an array
var args = Array.prototype.slice.call(arguments),
// the last argument is the callback
callback = args.pop(),
// modules can be passed as an array or as individual parameters
modules = (args[0] && "string" === typeof args[0]) ? args : args[0],
i;
// make sure the function is called
// as a constructor
if (!(this instanceof Sandbox)) {
return new Sandbox(modules, callback);
}
// add properties to 'this' as needed:
this.a = 1;
this.b = 2;
// now add modules to the core 'this' object
// no modules or "*" both mean "use all modules"
if (!modules || '*' === modules) {
modules = [];
for (i in Sandbox.modules) {
if (Sandbox.modules.hasOwnProperty(i)) {
modules.push(i);
}
}
}
// initialize the required modules
for (i = 0; i < modules.length; i += 1) {
Sandbox.modules[modules[i]](this);
}
// call the callback
callback(this);
// any prototype properties as needed
Sandbox.prototype = {
name: "Sandbox",
version: "1.0",
getName: function() {
return this.name;
}
}
};
Sandbox.modules = {};
Sandbox.modules.color = function (box) {
// private
var initialColor = $('#main').css('color');
// set a red color
box.setMainRed = function() {
$('#main').css('color','red');
return false;
},
// get the current color
box.getInitialColor = function () {
return initialColor;
};
}
// another module
Sandbox.modules.style = function (box) {
// set a red color
box.setStyle = function() {
$('#main').css('font-style','italic');
return false;
};
}
// page ready
$.ready(
Sandbox(['color', 'style'], function (box) {
console.log(box);
box.setMainRed();
box.setStyle();
console.log('try access initialColor: ', box.initialColor);
console.log('get initial color: ', box.getInitialColor());
})
);
But I am really unsure weather this is what I should be doing.
Especially adding the "modules" is somewhat confusing. Also earlier in the book he uses the namespace-pattern for this task, but not here. Why? Can't you do it here too?
But I failed to combine these two patterns.
Namespace pattern example inspired by the book:
var APP = APP || {};
// namespace function
APP.namespace = function (nsString) {
var parts = nsString.split('.'),
parent = APP,
i;
// strip redundant leading global
if ("APP" === parts[0]) {
parts = parts.slice(1);
}
for (i = 0; i < parts.length; i += 1) {
// create a property if it doesn't exist
if ("undefined" === typeof parent[parts[i]]) {
parent[parts[i]] = {};
}
parent = parent[parts[i]];
}
return parent;
}
// constructors
APP.namespace('modules.Color');
// immediate function
APP.modules.Color = (function () {
var currentColor = $('#main').css('color'),
// set a red color
setMainRed = function() {
$('#main').css('color','red');
return false;
},
// get the current color
getCurrentColor = function () {
return currentColor;
};
// revealing module pattern
return {
setMainRed: setMainRed,
getCurrentColor: getCurrentColor
};
}());
var doSomething = function () {
var color = APP.modules.Color;
color.setMainRed();
console.log(color.currentColor);
console.log(color.getCurrentColor());
return false;
}
// page ready
$.ready(
doSomething()
);
Here is example with detailed comments:
(function(){
/* function constructor */
function Sandbox(){
//Change arguments to array, as you know 'arguments' are not a true JS array
//Array.prototype.slice will provide shallow copy of 'arguments'
var args = Array.prototype.slice.call(arguments),
//remove last element from array and return it to caller
//our last argument is callback
callback = args.pop(),
//We can pass modules as strings or as array
//if first element is a string, take all arguemnts
//otherwise take one element (array)
modules = (args[0] && typeof args[0] === "string") ? args : args[0],
modulesLength = modules.length,
i;
//handle calling function constructor without 'new' keyword
if(!(this instanceof Sandbox)){
//Invoke me again!
return new Sandbox(modules, callback);
}
//we can add properties to 'this'
this.someProp = "Initialized property";
//Initialize all required modules
for(i = 0; i < modulesLength ; i++){
//pass reference to 'this' for each required module and invoke it
//'this' is poiting to new object which was created
//after calling new Sandbox()
Sandbox.modules[modules[i]](this);
}
//Invoke callback and pass 'this'
//now 'this' cotains all methods and properties
//attached in modules functions
callback(this);
};
//We can optionally create Sandbox methods
Sandbox.prototype = {
version: "1.0.1",
createdAt: new Date()
};
/* function as a first class object - saving all modules*/
Sandbox.modules = {};
/*Create $http,$scope and $ajax modules */
/*We need box object to add new functionality*/
/*We are creating new methods by attatching them to box obect*/
/*box is a reference to 'this' called as initializator from function constructor*/
Sandbox.modules.$http = function(box){
box.get = function(){
console.log("$http.get");
};
box.post = function(){
console.log("$http.post");
};
box.prop = "I'm $http property";
};
Sandbox.modules.$scope = function(box){
box.inject = function(param1, param2){
console.log("$scope.inject: " + param1 + " " + param2);
};
box.destroy = function(o){
console.log("$scope.destroy: " + o + " has been destroyed!");
};
};
Sandbox.modules.$ajax = function(box){
box.call = function(){
console.log("$ajax.call");
};
};
//Sandbox without calling 'new' was handled in function constructor
//We are requesting for 2 modules: $scope and $http
//callback function is our new playground
//box object has $scope and $http methods and properties inside, we are ready to go!
Sandbox(["$scope", '$http'], function(box){
console.log(box); //contains methods from $scope and $http
console.log(box.inject("John", "Doe"));
console.log(box.post());
//we can event nest our playgrounds
Sandbox(["$ajax"], function(box){
console.log(box); //contains only $ajax methods and properties
console.log(box.call());
//we can't invoke $scope or $http functions here
});
//we can't invoke $ajax functions here
});
})();
Link to JSFiddle: http://jsfiddle.net/Lodse4hj/

javascript class inherit from Function class

I like that in javascript, I can create a function, and then add further methods and attributes to that function
myInstance = function() {return 5}
myInstance.attr = 10
I would like to create a class to generate these objects. I assume I have to inherit from the Function base class.
In other words, I would like to:
var myInstance = new myFunctionClass()
var x = myInstance()
// x == 5
But I don't know how to create the myFunctionClass. I have tried the following, but it does not work:
var myFunctionClass = function() {Function.call(this, "return 5")}
myFunctionClass.prototype = new Function()
myInstance = new myFunctionClass()
myInstance()
// I would hope this would return 5, but instead I get
// TypeError: Property 'myInstance' of object #<Object> is not a function
I also tried the more complicated (and more proper?) inheritance method found here: How to "properly" create a custom object in JavaScript?, with no more luck. I have also tried using the util.inherits(myFunctionClass, Function) found in node.js. Still no luck
I have exhausted Google, and therefore feel that I must be missing something fundamental or obvious. Help would be greatly appreciated.
Your trying to inherit from Function. This is a right pain to do. I suggest you do the following instead
Live Example
var Proto = Object.create(Function.prototype);
Object.extend(Proto, {
constructor: function (d) {
console.log("construct, argument : ", d);
this.d = d;
// this is your constructor logic
},
call: function () {
console.log("call", this.d);
// this get's called when you invoke the "function" that is the instance
return "from call";
},
method: function () {
console.log("method");
// some method
return "return from method";
},
// some attr
attr: 42
});
You want to create a prototype object that forms the basis of your "class". It has your generic methods/attributes. It also has a constructor that gets invoked on object construction and a call method that gets invoked when you call the function
var functionFactory = function (proto) {
return function () {
var f = function () {
return f.call.apply(f, arguments);
};
Object.keys(proto).forEach(function (key) {
f[key] = proto[key];
});
f.constructor.apply(f, arguments);
return f;
}
}
A function factory takes a prototype object and returns a factory for it. The returned function when called will give you a new function object that "inherits" from your prototype object.
var protoFactory = functionFactory(proto);
var instance = protoFactory();
Here you create your factory and then create your instance.
However this isn't proper prototypical OO. we are just shallow copying properties of a prototype into a new object. So changes to the prototype will not reflect back to the original object.
If you want real prototypical OO then you need to use a hack.
var f = function () {
// your logic here
};
f.__proto__ = Proto;
Notice how we use the non-standard deprecated .__proto__ and we are mutating the value of [[Prototype]] at run-time which is considered evil.
JS does not allow a constructor to return a function, even though functions are objects. So you cant have an instantiation of a prototype that is itself executable. (Am I right in this? please correct if I'm not, it's an interesting question).
Though you could do a factory function:
var makeCoolFunc = function() {
var f = function() { return 5 };
f.a = 123;
f.b = 'hell yes!'
return f;
};
var func = makeCoolFunc();
var x = func();
You can extend Function and pass the wanted function body as String to the super constructor. The context of the function can be accessed with arguments.callee.
Example for an observable Attribute class:
export default class Attribute extends Function {
constructor(defaultValue){
super("value", "return arguments.callee.apply(arguments);");
this.value = defaultValue;
this.defaultValue = defaultValue;
this.changeListeners = [];
}
apply([value]){
if(value!==undefined){
if(value!==this.value){
var oldValue = this.value;
this.value=value;
this.changeListeners.every((changeListener)=>changeListener(oldValue, value));
}
}
return this.value;
}
clear(){
this.value=undefined;
}
reset(){
this.value=this.defaultValue;
}
addChangeListener(listener){
this.changeListeners.push(listener);
}
removeChangeListener(listener){
this.changeListeners.remove(listener);
}
clearChangeListeners(){
this.changeListeners = [];
}
}
Example usage:
import Attribute from './attribute.js';
var name= new Attribute();
name('foo'); //set value of name to 'foo'
name.addChangeListener((oldValue, newValue)=>{
alert('value changed from ' +oldValue+ ' to ' +newValue);
});
alert(name()); //show value of name: 'foo'
name('baa'); //set value of name to new value 'baa' and trigger change listener

Categories

Resources