I'm reading "JavaScript the Good Parts" and it mentions cascades as a way to do method chaining in JavaScript but I can't find any code that explains how these methods should be implemented.
getElement('myBoxDiv').
move(350, 150).
width(100).
height(100).
color('red').
border('10px outset').
padding('4px').
appendText("Please stand by").
on('mousedown', function (m) {
this.startDrag(m, this.getNinth(m));
}).
on('mousemove', 'drag').
on('mouseup', 'stopDrag').
later(2000, function ( ) {
this.
color('yellow').
setHTML("What hath God wraught?").
slide(400, 40, 200, 200);
}).
tip('This box is resizeable');
The trick is that the method itself should only return this. That way, each time you chain these methods together, the object itself is the base of the call.
SomeObj.width(40) would then return just SomeObj, so adding the call .height(50) would function, and continue along.
In a cascade, we can call many methods on the same object in sequence in a single statement.
Lets try this example,
var Calc = function(){
this.result=0;
this.add = function(){
for(var x=0; x<arguments.length; x++){
this.result += arguments[x];
}
return this;
};
this.sub = function(){
for(var x=0; x<arguments.length; x++){
this.result -= arguments[x];
}
return this;
};
this.mult = function(){
if(this.result==0)this.result = 1;
for(var x=0; x<arguments.length; x++){
this.result *= arguments[x];
}
return this;
};
this.div = function(){
if(this.result==0) return this;
for(var x=0; x<arguments.length; x++){
this.result /= arguments[x];
}
return this;
};
this.eq = function(){
return this.result
};
}
var cal1 = new Calc();
cal1.add(3).sub(1).add(2) // Here result = 4;
These methods always return the object they belong to this, e.g.:
var txtProcesor = {
txt: '',
removeWhite: function () {
this.txt = this.txt.replace(/\s+/g, '');
return this;
},
evenToUp: function () {
var res = "";
for (var i = 0; i < this.txt.length; i++) {
if (i % 2 == 0) res += this.txt[i].toUpperCase();
else res += this.txt[i];
}
this.txt = res;
return this;
}
}
txtProcesor.txt = " abc def ";
alert(txtProcesor.removeWhite().evenToUp().txt);
This is basically the way JQuery works. The idea is to make each of those functions return objects which contain those functions again so to speak.
EDIT: You can download JQuery and look at the source code for it, because this is exactly what is going on in that library.
Here is a demo combine cascade with callback, and the usage, hope this will help.
let calNum = function(num) {
this.num = num;
this.add = function(dif, callback) {
this.num = this.num + dif;
callback(this.num);
return this;
}
this.sub = function(dif, callback) {
this.num = this.num - dif;
callback(this.num);
return this;
}
this.multi = function(m, callback) {
this.num = this.num * m;
callback(this.num);
return this;
}
return this;
};
calNum(3).add(3,function(result) {
console.log(result);
}).multi(2, function(result) {
console.log(result);
}).sub(1, function(result) {
console.log(result);
}); // The final result is 11
I was also going through the same book but didn't find any implementation of the concept. However I found this nice and short blog on this.
Here is how you can enable cascades:
function number(value) {
this.value = value;
this.plus = function (sum) {
this.value += sum;
return this;
};
this.return = function () {
return this.value;
};
return this;
}
console.log(new number(5).plus(1).return());
Related
I'm going through Codecademy's lesson on building a Blackjack game with Javascript.
I'm having trouble coming up with code to put in the for-loop. I'm supposed to write a "score" method in the Hand constructor. It should loop over all of the cards in the Hand, summing up the result of the "getValue" call to each and return that sum.
Can someone help me out please? Thank You.
Here's my attempt, the relevant code is inside the for-loop at the bottom:
// Card Constructor
function Card(s, n) {
var suit = s;
var number = n;
this.getSuit = function() {
return suit;
};
this.getNumber = function() {
return number;
};
this.getValue = function() {
if (number >= 10) {
return 10;
} else if (number === 1) {
return 11;
} else {
return number;
}
};
};
//deal function
var deal = function() {
var randNum = Math.floor(Math.random() * 13) + 1;
var randSuit = Math.floor(Math.random() * 4) + 1;
console.log(randNum, randSuit);
return new Card(randSuit, randNum);
};
function Hand() {
var handArray = [];
handArray[0] = deal();
handArray[1] = deal();
this.getHand = function() {
return handArray;
};
this.score = function() {
var sum;
for (var i = 0; i < handArray; i++) {
sum += handArray[i].getValue;
return sum;
}
};
};
Well something like this should work :
this.score = function() {
return handArray.reduce( function( memo, val){
return memo + val.getValue();
});
};
I think you need to return the score, outside of the loop, like so:
this.score = function() {
var sum;
for (var i = 0; i < handArray; i++) {
sum += handArray[i].getValue();
}
return sum;
};
This fixed it. Thanks for your help!
this.score = function(){
var sum =0;
for(var i =0; i<handArray.length; i++){
sum += handArray[i].getValue();
};
return sum;
};
Hello I saw "this" (now I just simplified it) code on a website source.
The question is:
Why is this._position defined with m(p) instead of just p ?
does it have some logical explanation ?
var emptyFunction = function j() {};
emptyFunction.thatReturnsValue = function(j) {
return j;
};
var m = emptyFunction.thatReturnsValue;
function o(){
this._position = 'left';
}
o.prototype.setPosition = function(p) {
'use strict';
this._position = m(p);
return this;
};
o.prototype.getPosition = function(){
return this._position;
}
function calculatePosition(oInst){
var position;
//( do some math to figure out the best position)
position = 'right';
oInst.setPosition(position);
}
function realWork(){
var orientation = new o();
calculatePosition(orientation);
console.log(orientation.getPosition());
}
empty function is used for more things:
**
function h(j) {
return function() {
return j;
};
}
var emptyFunction = function j() {};
emptyFunction.thatReturns = h;
emptyFunction.thatReturnsFalse = h(false);
emptyFunction.thatReturnsTrue = h(true);
emptyFunction.thatReturnsNull = h(null);
emptyFunction.thatReturnsThis = function() {
return this;
};
emptyFunction.thatReturnsValue = function(j) {
return j;
};
**
How to write an Object for using this object like below
var cal = new calculator;
cal.add(10).add(20).miniz(2).div(2);
console.log(cal.result()); // result 14
Here you go, this is one way to do it:
My Example
var calculator = function() {
this.curr = 0;
this.add = function(n) {
this.curr += n;
return this; // returning this at the end of each method is the key to chaining
};
this.miniz = function(n) {
this.curr -= n;
return this;
};
this.div = function(n) {
this.curr = this.curr / n;
return this;
};
this.result = function() {
return this.curr;
};
};
You need to change the instantiation to this:
var cal = new calculator();
Just to get you started:
function Calculator() {
var value = 0;
this.add = function (v) {
value += v;
return this;
};
this.result = function () {
return value;
};
}
var cal = new Calculator;
console.log(cal.add(10).result()); // result 10
may be this is will help some what..
var Calc = function(){
this.value = 0;
};
Calc.prototype.add = function(val){
this.value += val;
return this;
};
then you can use like new Calc().add(100).add(100)
but before make sure understood how prototyping is working,
for ref : a sample
function calculator(){
this.val = 0;
this.add = function(num){
this.val += num;
return this;
};
this.miniz = function(num){
this.val -= num;
return this;
};
this.div = function(num){
this.val /= num;
return this;
};
this.result = function(){
return this.val;
};
}
I have a small piece of code written like in below.
var MY = MY || {};
MY.Farm = (function () {
var add = function(x){
console.log(x)
return this + this;
};
return {
add: function(x){
return add(x);
}
}
});
On a separate file I create sheep an instance of MY.Farm
var sheep = new MY.Farm()
I want to be able to call the function like the following with an output 6
sheep.add(3).add(2).add(1)
Any ideas how I can achieve this? What are the changes required to the MY.Farm snippet to accommodate this?
Thanks in advance.
Something like this
var MY = MY || {};
MY.Farm = (function () {
var x=0;
return {
add: function(newX){
if(typeof(newX) !="undefined") {
x+=newX;
return this;
}
return x;
}
}
});
var sheep = MY.Farm();
console.log( sheep.add(2).add(4).add());
http://jsfiddle.net/7q0143er/
You're not too far off. The trick is you need to keep track of the value somewhere, like in a private variable, and add needs to return this. Finally, you need a way to get the value out when you're done:
MY.Farm = function () {
var total = 0;
return {
add: function(x) {
total += x;
return this;
},
value: function() {
return total;
}
};
};
var sheep = new MY.Farm();
sheep.add(3);
console.log(sheep.value()); // => 3
console.log(sheep.add(1).add(2).value()); // => 6
I'm testing the observable pattern in javascript. My callbacks in the array never seem to execute. What is wrong with my syntax?
<script type="text/javascript">
var Book = function (value) {
var onChanging = [];
this.name = function () {
for (var i = 0; i < onChanging.length; i++) {
onChanging[i]();
}
return value;
}
this.addTest = function (fn) {
onChanging.push(fn);
}
}
var b = new Book(13);
b.addTest(function () { console.log("executing"); return true; });
b.name = 15;
</script>
From your code above it looks like you need to call your function name instead of assigning a value something like:
var b = new Book(13);
b.addTest(function () { console.log("executing"); return true; });
b.name(); //<-- Before b.name = 15
Setting b.name = 15 doesn't execute the function, it just overwrites the value of b.name.
You could use getters and setters to react to a changing value. See John Resig's blog post or the MDN reference
I edited your code to use them:
var Book = function (value) {
this.onChanging = [];
this._name = "";
}
Book.prototype = {
addTest: function (fn) {
this.onChanging.push(fn);
},
get name() {
return this._name;
},
set name(val) {
for (var i = 0; i < this.onChanging.length; i++) {
this.onChanging[i](val);
}
this._name = val;
}
};
var b = new Book(13);
b.addTest(function (val) {
console.log("executing", val);
return true;
});
b.name = 15;
b.name = 17;
working demo.
You can also make a more generic solution that can work for all your properties without having to define the getters and setters, a lot of frameworks use this approach.
Book = function () {
this._events = [];
this._rawdata = {};
}
Book.prototype = {
bind: function (fn) {
this._events.push(fn);
},
// pass the property, and it returns its value, pass the value and it sets it!
attr: function (property, val) {
if (typeof val === "undefined") return this._rawdata[property];
this._rawdata[property] = val;
for (var i = 0; i < this._events.length; i++)
// we pass out the val and the property
this._events[i](val, property);
}
};
b = new Book();
b.bind(function (val) {
console.log("executing", val);
return true;
});
b.attr("name","The Hobbit");
b.attr("SKU" ,1700109393901);
console.log(b.attr("name")); // --> The Hobbit
http://jsfiddle.net/wv4ch6as/
Of course you would want to change the binder so that you can bind onto properties not one bind for all properties, but I think this gets the idea.