Chain non-jquery methods in a jquery plugin - javascript

Let's say I write a jquery plugin that has a method that adds two values and sets the html to that value. I can chain it one way, but not the other and I want to understand why, and how I can make sure I can chain both ways.
$.fn.foo = function() {
this.result = 0;
this.doMath= function(a, b) {
this.result = a + b;
this.html(this.val);
return this;
}
return this;
}
var link = 'Link'
// works as expexted
var a = $(link).foo().doMath(1,2).appendTo('body')
// does not work, likely because appendTo returns jquery
var b = $(link).foo().appendTo('body').doMath(1,2)
https://jsfiddle.net/j7ut1f30/1/

After 2 weeks of trying everything, I finally acheived my goals.
class $Util {
static $wrapper(self) {
if (!self.$wrapper)
throw new ReferenceError('$Util.$wrapper: $wrapper not defined in context of first argument');
$.each($Util.jqueryPrototype, function(i, e) {
self[e] = function() {
self.$wrapper[e](...arguments);
return self;
}
});
}
}
$Util.jqueryPrototype = Object.getOwnPropertyNames($.prototype);
class foo {
constructor() {
this.$wrapper = $('p')
$Util.$wrapper(this);
return this;
}
test() {
console.log('j')
return this;
}
}
var s = new foo();
s.css('color', 'red').test().appendTo('body').test().css('color','green')
https://jsfiddle.net/24r6uxs1/

Related

jQuery object data structure

I'm trying to create a mini jQuery clone that can support method chaining. So far I've came up with this piece of code:
var $ = (function () {
var elements = [];
function methodOne() {
console.log('Method 1');
return this;
}
function methodTwo() {
console.log('Method 2');
return this;
}
return {
methodOne: methodOne,
methodTwo: methodTwo
};
}());
At page load, the $ variable gets populated with the jQuery clone object returned by the IIFE.
My question is, how can I make the $ object to be called directly as a function while still maintaining the method chaining functionality?
Right now, I can use $.methodOne().methodTwo() but I cant use $('some parameter').methodOne().methodTwo() just like jQuery does.
var $ = function (param) {
var elements = [];
console.log(param);
function methodOne() {
console.log('Method 1');
return this;
}
function methodTwo() {
console.log('Method 2');
return this;
}
return {
methodOne: methodOne,
methodTwo: methodTwo
};
};
$('This is a param').methodOne().methodTwo();
Working fiddle. The comments should be more or less self explanatory.
It might look a bit long, but it will let you create new mini jQuery object every time you call it.
var _ = (function () {
var Magic = function(query){
if(window === this)
return new Magic(query);
// reference to itself
var that = this;
//assign pseudo public methods and variables
that.elements = [];
that.methodTwo = methodTwo;
that.methodOne = methodOne;
//fills inner element array with DOM element
_get(query);
function _get(query){
var elem = document.getElementById(query);
that.elements.push(elem);
}
function methodOne() {
console.log('Method 1');
return that;
}
function methodTwo() {
console.log('Method 2', that.elements);
return that;
}
return this;
}
//returns function, which is assigned to a "_" variable
return function(query){
//everytime "_" is called, it will return new instance for object Magic which makes all the work
return new Magic(query);
}
}());

Execute "static" method of a parent of a constructor accessed from a constructor array in Javascript

Phew, even the question was hard to write. Here's the problem: I have a "game", more like a random simulator, which needs to choose a random action from an array of actions, like this one:
actions = [ Action1, Action2, Action3 ]
I have actions written as classes inheriting from the Action parent class:
function Action() {
this.targets = [];
this.used = [];
this.execute = function(player) {
doStuff();
return whatever;
};
}
//btw the below I've seen in a JS OOP tutorial but it doesn't work and I have to implement init() in every child action
Action.init = function(player) {
var a = new this.constructor();
return a.execute(player);
};
Action.checkRequirements = function() {
return true;
};
Action1.prototype = new Action();
Action1.prototype.constructor = Action1;
function Action1 {
this.execute = function(player) {
doStuff();
return whatever;
}
}
Action1.init = function(player) {
var a = new Action1();
return a.execute(player);
}
So what I'm doing to execute an action and get its results is var foo = actions.getRandomVal().init(); (getRandomVal is a simple custom script that returns a random value from the array) It works well, creates the object instance which properly inherits all properties and methods, executes the exec() method and returns its results... but now I have a checkRequirements() method which I want to implement in like 10% of the 100+ actions I wish to do, and I want it to simply be inherited from the Action class so that when it is not implemented in the child class it simply returns true and I don't have an idea how. If I do var a = actions.getRandomVal(); and then a.checkRequirements(); it throws an exception that a.checkRequirements is not a function.
PS: this is a relatively small non-profit project for a (large) group of friends, I don't need it to work in every browser, it needs to work in Chrome and I can just tell them to use Chrome for it.
Since you only need to work with Chrome, I'd suggest to use ES6 class syntax which does all the inheritance properly, without the chance to mess up. This includes your Action1 constructor to inherit properties ("static class members") from the Action constructor as you'd expect.
class Action {
constructor() {
this.targets = [];
this.used = [];
}
execute(player) {
doStuff();
return whatever;
}
static init(player) {
var a = new this(); // no .constructor
return a.execute(player);
}
static checkRequirements() {
return true;
}
}
class Action1 {
execute(player) {
doOtherStuff();
return whateverelse;
}
}
It looks to me like you're calling checkRequirements() on an instance:
a.checkRequirements();
But it's implemented statically:
Action.checkRequirements = function() {
return true;
};
You probably want to bind this function to the prototype, so change the code above to this:
Action.prototype.checkRequirements = function() {
return true;
};
Then when you want to override this in a derived type, like Action1, you can do this:
Action1.prototype.checkRequirements = function () {
return (whatever);
}
As per comments, my guess is you want something like this...
// base Action type providing basic implementation
// Wrapped in an IIFE to prevent global scope pollution
// All functions are prototype bound to allow prototypical inheritance.
var Action = (function () {
function Action() {
this.targets = [];
this.used = [];
};
Action.prototype.doStuff = function () {
return;
}
Action.prototype.execute = function (player) {
this.doStuff();
return "whatever";
}
Action.prototype.checkRequirements = function () {
return "foo";
}
return Action;
})();
var Action1 = (function () {
Action1.prototype = new Action();
Action1.prototype.constructor = Action1;
function Action1() {
}
Action1.prototype.checkRequirements = function () {
// Super call
return Action.prototype.checkRequirements.call(this);
}
return Action1;
})();
var Action2 = (function () {
Action2.prototype = new Action();
Action2.prototype.constructor = Action2;
function Action2() {
}
Action2.prototype.checkRequirements = function () {
return "bar";
}
return Action2;
})();
// Set up array.
var array = [Action1, Action2];
// Create instances (this is where you would pick at random)
var a1 = new array[0]();
var a2 = new array[1]();
// var aofn = new array[rnd]();
// Tests
alert(a1.checkRequirements()); // Should "foo" because it called super (Action).
alert(a2.checkRequirements()); // Should "bar" because it's overridden.
Check it out on TypeScript Playground

new function(){} vs new Function();

I picked up some code and I am just getting to understand the new Function();. Going through jslint the new Function(); was highlighted as unexpected. I started to experiment with it doing the following.
var func = new Function();
func.property = "some property";
return func;
A replacement.
var func = new function(){
this.property = "some property";
}
return func;
Both work and the second one is neglected by js-lint.
Am I doing anything spectacular here, or is this exactly the same? Is it syntactical correct to use new Function(); like this?
Original code excerpt is attached.
var $ = (function() {
function doCSS(prop, val) {
var isSet = Boolean(val),
action = CSSStyleDeclaration.prototype.setProperty,
args = arguments;
if (isSet) {
this.each(function(node, i) {
action.apply(node.style, args);
});
return this;
} else if (typeof(prop) === 'object') {
this.each(function(node, i) {
Object.keys(prop).forEach(function(property) {
node.style[property] = prop[property];
});
});
return this;
} else {
return this.nodes[0].style[prop];
}
}
// chaining of methods
return (function(selector, context) {
var q = new Function();
q.selector = selector;
q.context = context || document;
q.nodeList = q.context.querySelectorAll(selector);
q.each = function(action) {
[].forEach.call(q.nodeList, function(item, i) {
action(item, i);
});
return this;
};
q.click = function(action) {
[].forEach.call(q.nodeList, function(item, i) {
item.addEventListener("click", action, false);
});
return this;
};
q.toString = function() {
return q.selector;
};
q.css = function(prop, val) {
return doCSS.call(this, prop, val);
};
return q;
});
})
Is any of these two wrong in syntax?
EDIT
After getting some of the great advice I adapted the code to the following:
var $ = (function($) {
function doCSS(prop, val) {
var isSet = Boolean(val),
action = CSSStyleDeclaration.prototype.setProperty,
args = arguments;
if (isSet) {
this.each(function(node, i) {
action.apply(node.style, args);
});
return this;
} else if (typeof(prop) === 'object') {
this.each(function(node, i) {
Object.keys(prop).forEach(function(property) {
node.style[property] = prop[property];
});
});
return this;
} else {
return this.nodes[0].style[prop];
}
}
// chaining of methods
return (function(selector, context) {
var element = context || document;
var q = {
selector: selector,
nodeList: element.querySelectorAll(selector),
each: function(action) {
[].forEach.call(this.nodeList, function(item, i) {
action(item, i);
});
return this;
},
click: function(action) {
[].forEach.call(this.nodeList, function(item, i) {
item.addEventListener("click", action, false);
});
return this;
},
toString: function() {
return selector;
},
css: function(prop, val) {
return doCSS.call(this, prop, val);
},
}
return q;
});
})($);
$("#myElement").css({
background: "blue",
color: "#fff"
});
<div id="myElement">Say Hi</div>
It works just fine and looks a lot cleaner. JS Lint is nice to me and I can tackle the next issue.
In the first case, you create a new object and you apply the Function constructor.
Return value is a function.
In the second example, you create a new object and you apply an anonymous function as constructor.
Return value is an object.
Both statements are indeed different. I will focus on the second statement to point out the difference.
var newObj1 = new function () {
this.prop1 = "test1";
this.prop2 = "test2"
};
Is equivalent to the following:
var Example = function () {
this.prop1 = "test1";
this.prop2 = "test2"
};
var newObj2 = new Example();
The only difference being that in the first example the constructor function called is an anonymous function. Note, that when a function is called with the new keyword in javascript it exhibits special behavior.
In your first statement the constructor function called is an already defined function, Function.
As has been pointed out your first statement returns a function while the second returns an object. Neither, is wrong but one returning a function and the other an object could have implications in other sections of your code.
Yes it is not right approach to create objects
because objects created through new Function() are less efficient than the functions created using function expression
The global Function object has no methods or properties of its own, however, since it is a function itself it does inherit some methods and properties through the prototype chain from Function.prototype
for more reference
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
Hope this helps
Check the following code snippet
var func = new Function();
func.property = "some property";
"some property"
console.log(func);
now when you check in the console it says it as anonymous
but when an object created through function expression
var func=new function(){this.x=10;}
console.log(func);
this returns an objects
I guess you understand the difference

Call parent method in JavaScript class but stll have access to prototype methods inside object instance?

Is it possible to call parent method in JavaScript class but to still have access to prototype methods from parent and child class. Here is code example:
var Base = function() {
this.baseMethod = function(){
return 'baseMethod';
};
this.baseInitMethod = function() {
return 'baseInitMethod';
}
}
Base.prototype.basePrototypeMethod = function() {
return "basePrototypeMethod";
};
var Specific = function() {
Base.call(this);
this.baseInitMethod = function() {
// call baseInitMethod from Base class
}
this.specificMethod = function(){
return 'specificMethod';
}
this.specificInitMethod = function() {
return this.basePrototypeMethod();
}
}
Specific.prototype.specificPrototypeMethod = function() {
return 'specificPrototypeMethod' + '-' + this.baseInitMethod();
}
for(var p in Base.prototype) {
Specific.prototype[p] = Base.prototype[p]
}
var s = new Specific();
console.log(s.baseMethod());
console.log(s.baseInitMethod());
console.log(s.basePrototypeMethod());
console.log(s.specificMethod());
console.log(s.specificInitMethod());
console.log(s.specificPrototypeMethod());
I want to call baseInitMethod in Base class from baseInitMethod method inside Specific class but so that all function calls from above still works. Is that possible?
Your Specific.prototype object should inherit from the Base.prototype object. Currently you're copying over all its properties to the object with this code:
for(var p in Base.prototype) {
Specific.prototype[p] = Base.prototype[p]
}
But you should actually use Object.create to establish a real prototype chain:
Specific.prototype = Object.create(Base.prototype);
Specific.prototype.specificPrototypeMethod = function() {
return 'specificPrototypeMethod' + '-' + this.baseInitMethod();
}
I want to call baseInitMethod in Base class from baseInitMethod method inside Specific class
Yes. In your Specific constructor, you first need get Base's baseInitMethod instance method, before you overwrite the property of the instance:
function Specific() {
Base.call(this);
var parentInitMethod = this.baseInitMethod;
this.baseInitMethod = function() {
// call baseInitMethod from Base class:
parentInitMethod.call(this /*, arguments…*/);
}
…
}
so that all function calls from above still works.
I'm not sure what you mean by that exactly. The specificPrototypeMethod will always call the baseInitMethod of the current instance, which would be Specific's overwritten one not the original that was defined in Base.
Here is what you need to do:
var Base = function () {
};
Base.prototype.baseMethod = function () {
return 'baseMethod';
};
Base.prototype.baseInitMethod = function () {
return 'baseInitMethod';
};
Base.prototype.basePrototypeMethod = function () {
return "basePrototypeMethod";
};
var Specific = function () {
Base.apply(this, arguments);
};
Specific.prototype.baseInitMethod = function () {
Base.prototype.baseInitMethod.apply(this,arguments);
};
Specific.prototype.specificMethod = function () {
return 'specificMethod';
};
Specific.prototype.specificInitMethod = function () {
var basePrototypeMethodCallResult = Base.prototype.basePrototypeMethod.apply(this,arguments);
};
You're overwriting the baseInitMethod of Base inside Specific, with Specific's definition, so why would you ever want to call the Base version? If you simply remove the overwrite of the function you should call the Base definition:
var Base = function() {
this.baseMethod = function(){
return 'baseMethod';
};
this.baseInitMethod = function() {
return 'baseInitMethod';
}
}
Base.prototype.basePrototypeMethod = function() {
return "basePrototypeMethod";
};
var Specific = function() {
Base.call(this);
this.baseInitMethod(); // calls the Base definition only
this.specificMethod = function(){
return 'specificMethod';
}
this.specificInitMethod = function() {
return this.basePrototypeMethod();
}
}
One might argue "Why always trying to mimic 'classical' behaviour and fuss with call and apply instead of embracing the prototype delegation pattern instead?"
Here is what I would code :
var Base = {
baseVariable1: "baseValue1",
baseVariable2: "baseValue2",
baseMethod: function () {
return 'baseMethod';
},
baseInitMethod: function () {
return 'baseInitMethod';
}
}
var Specific = Object.create(Base);
Specific.variable1 = "value1";
Specific.variable2 = "value2";
Specific.specificInitMethod = function () {
return 'specificInitMethod' + '-' + this.baseInitMethod();
}
Specific.specificMethod = function () {
return 'specificMethod' + '-' + this.baseInitMethod();
}
var s = Object.create(Specific);
console.log(s.baseInitMethod());
console.log(s.baseVariable1);
console.log(s.baseVariable2);
console.log(s.variable1);
console.log(s.variable2);
console.log(s.baseMethod());
console.log(s.specificInitMethod());
console.log(s.specificMethod());
class Parentable {
get parent() {
return this.__proto__.__proto__;
}
}
class A extends Parentable {
say() {
console.log('Hello from A');
}
}
class B extends A {
say() {
console.log('Im not A, I am B! But A send you a message:');
this.parent.say();
}
}
(new B()).say();

Assigning multiple methods to an application in JavaScript

I have now officially spent all day trying to assign a variable in JavaScript!
Forgive me for asking this same question 4 different ways, but here's what I started out with this morning, and this works. I just need to add a second method to it now.
Application = {};
(function() {
var closure = {};
Application.myFirstMethod = function() {
if (arguments.length) {
closure = arguments[0];
} else {
return closure;
}
}
})();
Application.myFirstMethod(3.14);
result = Application.myFirstMethod();
log(result);
So my question is: and please be patient with me, if I add mySecondMethod to Application, then how do I keep the value of arguments[0] without using the variable that is currently called closure?
How about this, it defines a function that takes a string and returns a getter/setter function. The string is used to indicate what property to get/set the value as in variables.
Demo
Application = {};
(function() {
var variables = {};
Application.myFirstMethod = makeGetterSetter('myFirst');
Application.mySecondMethod = makeGetterSetter('mySecond');
function makeGetterSetter(name) {
return function () {
if (arguments.length) {
variables[name] = arguments[0];
} else {
return variables[name];
}
};
}
})();
Application.myFirstMethod(4);
result1 = Application.myFirstMethod();
Application.mySecondMethod(5);
result2 = Application.mySecondMethod();
console.log(result1);
console.log(result2);
If you wanted to have a getter or setter with custom logic in it before either event then it would be easiest to just define them separately. Stick with the this[property] pattern to keep all your fields in one spot.
Application.myCustomMethod = function() {
if (arguments.length) {
// some logic
variables['custom'] = arguments[0];
} else {
// some logic
return variables['custom'];
}
}
It looks like you are searching for adding properties to objects, in the Prototype-Oriented Programming Language sense of the term; just use the "this" object, which stands for the current calling context, and which will be set to your Application object when calling the methods:
Application = {};
(function() {
Application.myFirstMethod = function() {
if (arguments.length) {
this.foo = arguments[0];
} else {
return this.foo;
}
};
Application.mySecondMethod = function() {
if (arguments.length) {
this.bar = arguments[0];
} else {
return this.bar;
}
};
})();
Application.myFirstMethod(3.14);
console.log(Application.myFirstMethod());
Application.mySecondMethod(2097);
console.log(Application.mySecondMethod());
console.log(Application.myFirstMethod());
Here's what I figured out. I probably need to use the word new somewhere though.
Application = {};
(function() {
Application.myFirstMethod = FirstMethod();
Application.mySecondMethod = SecondMethod();
function FirstMethod() {
var closure = {};
return function(myArgument) {
if (arguments.length) {
closure.result = arguments[0]; // myArgument
} else {
return closure.result;
}
}
}
function SecondMethod() {
var closure = {};
return function(myArgument) {
if (arguments.length) {
closure.result = arguments[0]; // myArgument
} else {
return closure.result;
}
}
}
})();
Application.myFirstMethod(3.14);
result = Application.myFirstMethod();
log(result);
Application.mySecondMethod(2013);
result = Application.mySecondMethod();
log(result);

Categories

Resources