Sequence from Class OO to Object Delegation pattern - javascript

My intention is to use function logFive2 to iterate over
a sequence object like ArraySeq2 or RangeSeq2 although I want to create the RangeSeq2 using Object delegation pattern and stay away from Class like way(ArraySeq2). What I am doing wrong with RangeSeq2?
My code doesn't work because logFive2 does not iterate over RangeSeq2 and I cannot see why. If you have any idea about what goes wrong please let me see. Thank you.
function logFive2(sequence){
for(var i = 0; i < 5 && sequence != null; i++){
console.log(sequence.head());
sequence = sequence.rest();
}
}
function ArraySeq2(array,offset){
this.array = array;
this.offset = offset;
}
ArraySeq2.prototype.rest = function(){
console.log("to follow " + this.offset);
return ArraySeq2.make(this.array,this.offset + 1);
};
ArraySeq2.prototype.head = function(){
return this.array[this.offset];
};
ArraySeq2.make = function(array,offset){
if(offset == null) offset = 0;
if(offset >= array.length)
return null;
else return new ArraySeq2(array,offset);
}
logFive2(ArraySeq2.make([1, 2,5,6,9,11]));
// → 1
// → 2
The part above works fine ______________ RangeSeq2 object it is my problem
var RangeSeq2 = {
init: function(from,to){
this.from = from;
this.to = to;
},
rest: function(){
if (from > to)
return null;
else
return this.init(this.from + 1,this.to);
},
head: function(){
return this.from;
}
};
var RangeTT = Object.create(RangeSeq2);
RangeTT.init(100,1000);
logFive2(RangeTT.init(100,1000));

function logFive2(sequence){
for(var i = 0; i < 5 ; i++){
console.log(sequence.head());
sequence.rest();
}
}
var RangeSeq2 = {
rest: function(){
if (this.from > this.to) {
return null;
}
else
return this.from += 1,this.to;
},
head: function(){
return this.from;
}
};
var RangeTT = Object.create(RangeSeq2);
RangeTT.from = 100;
RangeTT.to = 1000;
logFive2(RangeTT);
//100
//101
//102
//103
//104
Sorted out! the problem was so much simpler than I thought will be.
My problem was trying to do an unhealthy mixture of classical inheritance and instantiation over the Object delegation because I didn't understood how it works.
Soon as I managed to understand how "this" works and soon I understood Object.create (which is very powerful ) , the __proto__ and knew the difference it has compared to function Object.prototype I could find a solution.
1.My first mistake I think was trying to create state in the object by calling the method init() without having a property to hold the values in the object.
2.The rest() method would query on variables which would not exist on the object.
I have to mention that I had to change the iterator function LogFive2() to be suitable for the object delegation design in my case.

Related

Javascript - see if object contains function, if so, return it

I have a function which takes in a String. The function checks if the object in the list has this function(functionName). If it contains that function, how can I return it? Obviously, return list[i].message would work, but thats not what im after. I want do use the parameter functionName in this case.
function message(){
return "hello";
}
function test(functionName);
listLength = list.length;
for(i = 0; i < listLength; i++){
if(list[i].hasOwnProperty(functionName}{
return (?)
}
}
var x = test("message");
alert(x);
Grateful for response
the comment from Pointy is right, but you have to consider that having a function detached by its owner will screw the scope, so you will no longer have access to the right this object
var test = {
number: 0,
testFunction: function() {
return this.number;
}
}
console.log(test.testFunction()); // output: 0
var x = test.testFunction;
console.log(x()); // output: undefined
maybe you should use
var y = test.testFunction.bind(test);
console.log(y()); // output: 0

In angular updating one variable inexplicably updates another

I am using angular and plotly to plot either the raw data or a moving average. I have the moving average working but I am running into an issue with assigning variables. I retrieve an array of user objects which each have an x and y key with arrays associated with them.
$scope.init=function(){
$rootScope.page='companyResults';
$scope.isPlotlyDone = false;
$scope.moving = false;
var refresh = function () {
incidentService.dayWiseTripsByUser(...).then(function (plotArray){
$scope.unaffectedPlot = plotArray;
$scope.movingAveragePlot = allMoving(plotArray);
console.log($scope.unaffectedPlot[0].y);
console.log($scope.movingAveragePlot[0].y);
});
};
refresh();
}
Im that code block, I would expect that $scope.unaffectedPlot[0].y and $scope.movingAveragePlot[0].y would have different arrays since I ran the latter through the following set of functions. The curious thing is that both $scope variables are synced, so if I run the second through allMoving the unaffectedPlot variable also gets smoothed and neither get synced obviously if I don't call allMoving. What am I missing about Angular? What is a good way to have a moving average work with a toggle? My plan is to show one variable or the other depending on if a button is clicked.
var d3_numeric = function(x) {
return !isNaN(x);
}
var d3sum = function(array, f) {
var s = 0,
n = array.length,
a,
i = -1;
if (arguments.length === 1) {
// zero and null are equivalent
while (++i < n) if (d3_numeric(a = +array[i])) s += a;
} else {
while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a;
}
return s;
};
var movingWindowAvg = function (arr, step) {
return arr.map(function (_, idx) {
var wnd = arr.slice(idx - step, idx + step + 1);
var result = d3sum(wnd) / wnd.length; if (isNaN(result)) { result = _; }
return result;
});
};
var allMoving = function(pltArray) {
var movingArray = [];
pltArray.forEach(function(plot){
var oneMoving = plot;
oneMoving.y = movingWindowAvg(plot.y, 5);
movingArray.push(oneMoving);
});
return movingArray;
}
This actually isn't an angular issue. I had to test it some since I didn't see what was going on either.
When you wrote
oneMoving.y = blah
you were actually altering the contents of plot for each element and in turn altering the contents of plotArray unintentionally (since plot is an object)
So you are only creating a reference variable when you say 'var onMoving = plot' )
To outright solve your problem you can clone plot but that isn't so clean of a process
One easy yet dirty way is
JSON.parse(JSON.stringify(obj))
from this thread
I threw together a shotty example that captures what was going wrong for you
var array = [{one:1, two:2},{one:1, two:2},{one:1, two:2}],
copyArray = array,
newArr = doStuff(array)
function doStuff(a) {
var otherNewArr = []
a.forEach(function(ae) {
var aVar = ae
aVar.one = 5
otherNewArr.push(aVar)
})
return otherNewArr
}
console.log(copyArray,newArr)
And to fix it just replace
var aVar = ae
with
var aVar = JSON.parse(JSON.stringify(ae))

indexOf() : is there a better way to implement this?

EDIT
Thank you guys, and i apologize for not being more specific in my question.
This code was written to check if a characters in the second string is in the first string. If so, it'll return true, otherwise a false.
So my code works, I know that much, but I am positive there's gotta be a better way to implement this.
Keep in mind this is a coding challenge from Freecodecamp's Javascript tree.
Here's my code:
function mutation(arr) {
var stringOne = arr[0].toLowerCase();
var stringTwo = arr[1].toLowerCase().split("");
var i = 0;
var truthyFalsy = true;
while (i < arr[1].length && truthyFalsy) {
truthyFalsy = stringOne.indexOf(stringTwo[i]) > -1;
i++
}
console.log(truthyFalsy);
}
mutation(["hello", "hey"]);
//mutation(["hello", "yep"]);
THere's gotta be a better way to do this. I recently learned about the map function, but not sure how to use that to implement this, and also just recently learned of an Array.prototype.every() function, which I am going to read tonight.
Suggestions? Thoughts?
the question is very vague. however what i understood from the code is that you need to check for string match between two strings.
Since you know its two strings, i'd just pass them as two parameters. additionally i'd change the while into a for statement and add a break/continue to avoid using variable get and set.
Notice that in the worst case its almost the same, but in the best case its half computation time.
mutation bestCase 14.84499999999997
mutation worstCase 7.694999999999993
bestCase: 5.595000000000027
worstCase: 7.199999999999989
// your function (to check performance difference)
function mutation(arr) {
var stringOne = arr[0].toLowerCase();
var stringTwo = arr[1].toLowerCase().split("");
var i = 0;
var truthyFalsy = true;
while (i < arr[1].length && truthyFalsy) {
truthyFalsy = stringOne.indexOf(stringTwo[i]) > -1;
i++
}
return truthyFalsy;
}
function hasMatch(base, check) {
var strOne = base.toLowerCase();
var strTwo = check.toLowerCase().split("");
var truthyFalsy = false;
// define both variables (i and l) before the loop condition in order to avoid getting the length property of the string multiple times.
for (var i = 0, l = strTwo.length; i < l; i++) {
var hasChar = strOne.indexOf(strTwo[i]) > -1;
if (hasChar) {
//if has Char, set true and break;
truthyFalsy = true;
break;
}
}
return truthyFalsy;
}
var baseCase = "hello";
var bestCaseStr = "hey";
var worstCaseStr = "yap";
//bestCase find match in first iteration
var bestCase = hasMatch("hello", bestCaseStr);
console.log(bestCase);
//worstCase loop over all of them.
var worstCase = hasMatch("hello", worstCaseStr);
console.log(worstCase);
// on your function
console.log('mutation bestCase', checkPerf(mutation, [baseCase, bestCaseStr]));
console.log('mutation worstCase', checkPerf(mutation, [baseCase, worstCaseStr]));
// simple performance check
console.log('bestCase:', checkPerf(hasMatch, baseCase, bestCaseStr));
console.log('worstCase:', checkPerf(hasMatch, baseCase, worstCaseStr));
function checkPerf(fn) {
var t1 = performance.now();
for (var i = 0; i < 10000; i++) {
fn(arguments[1], arguments[2]);
}
var t2 = performance.now();
return t2 - t1;
}

Object Oriented Javascript Chapter 4 Exercise 4

Hi all I'm learning Javascript with the Stoyan Stefanov's book. I'm stuck on Chapter 4 Exercise 4:
Imagine the String()constructor didn't exist. Create a constructor
function MyString()that acts like String()as closely as possible.
You're not allowed to use any built-in string methods or properties,
and remember that String()doesn't exist. You can use this code to
test your constructor:
>>> var s = new MyString('hello');
>>> s[0];
"h"
I can't think on a way to achieve "s[0]", at least not with the knowledge I have now.
Any thoughts?
Thanks
Objects can have properties of themselves defined using array like syntax. String chars can be accessed with array like syntax.
function MyString (str) {
this.length = 0; // string length
var i = 0;
while(str[i] != undefined) {
this.length++;
i++;
}
for (var i=0; i< this.length;i++)
{
this[i]=str[i];
}
}
var s=new MyString('hello');
alert(s[0]); //h
here is my solution for this exercice :
function MyString(msg){
var array_msg = msg.split("");
array_msg.toString = function(){
return array_msg.join("");
};
array_msg.valueOf = function(){
return array_msg.toString();
};
array_msg.charAt = function(i){
if(array_msg[i] === undefined){
return array_msg[0];
}else{return array_msg[i];}
};
array_msg.concat = function(msg2){
return array_msg.join("")+" "+msg2;
};
array_msg.slice = function(d,f){
var res = "";
if(f<0){
f = array_msg.length + f;
}
for(var i=d; i<f; i++){
res += array_msg[i]
}
return res;
};
array_msg.split = function(el){
return array_msg.toString().split(el);
};
return array_msg;
}
A slight variation of the above...more of a tweak than anything
var MyString = function (s) {
for (var i = 0; i < s.length; i++){
this[i] = s[i]
}
this.length = function() .....
You also don't need to assign it to anything as extra as the comment suggests. this[i] will be created for the length of the string passed to s
EDIT:
Part of the question in the book says not to use existing string methods so can't use charAt so I've switched it to s[I]
This is another variation of one of the above solutions but instead of using a for loop I am using a while loop. I don't usually use while loops for these kinds of things but it worked really well here.
Adding the length property is optional.
function MyString(str) {
this.length = 0; // Creating an optional length property
this.value = str;
var i = 0;
while(str[i] != undefined) {
this[i] = str[i];
this.length++;
i++;
}
}
var name = new MyString('billy');
console.log(name.value); // 'billy'
console.log(name[0]); // 'b'
console.log(name.length); // 5

Generating a random value, keeping a history of returned values

For a project I'm working on, I needed a Javascript function that would return a random number, in a given range, without repeating itself until the whole range is 'depleted'. As there was no such thing around, I have managed to create it myself.
The function will also require an id to be passed. This way, if you require multiple random numbers, each with their own history, the id keeps track of them all.
The function works, however I need some advice;
is this the 'proper' way to achieve what I want to achieve?
how fast will inArray() perform with very big ranges (maxNum) values? I have a feeling that large numbers will slow the function down, as it is randomizing numbers until it generates a number that is still 'valid' (i.e. not in the history array). But I can't figure out another way to do this..
The script:
var UniqueRandom = {
NumHistory: [],
generate: function (maxNum, id) {
if (!this.NumHistory[id]) this.NumHistory[id] = [];
if (maxNum >= 1) {
var current = Math.round(Math.random() * (maxNum - 1)), x = 0;
if (maxNum > 1 && this.NumHistory[id].length > 0) {
if (this.NumHistory[id].length !== maxNum) {
while ($.inArray(current, this.NumHistory[id]) !== -1) {
current = Math.round(Math.random() * (maxNum - 1));
x = x + 1;
}
this.NumHistory[id].push(current);
} else {
//reset
this.NumHistory[id] = [current];
}
} else {
//first time only
this.NumHistory[id].push(current);
}
return current;
} else {
return maxNum;
}
},
clear: function (id) {
this.NumHistory[id] = [];
}
};
usage would be: (100 being the range (0-100) and the_id being.. well, the id)
UniqueRandom.NumHistory[100, 'the_id']
I have set up a Fiddle with a demo.
It's not best practice. Imo it would be better to instantiate an object per series of numbers that needs to be generated.
I'd suggest generating an array of all possible values and shuffling it. Then you can just pop of it.
I took Jack's code and adapted it to work with the popping array method.
function fisherYates ( myArray ) {
var i = myArray.length;
if ( i == 0 ) return false;
while ( --i ) {
var j = Math.floor( Math.random() * ( i + 1 ) );
var tempi = myArray[i];
var tempj = myArray[j];
myArray[i] = tempj;
myArray[j] = tempi;
}
}
function RandomGenerator(maxNum) {
this.max = maxNum;
this.initRandomArray();
}
RandomGenerator.prototype.generate = function() {
// if no more numbers available generate new array
if( this.left === 0 ) this.initRandomArray();
this.last = this.arr.pop();
this.left = this.arr.length;
this.history.push( this.last );
return this.last;
}
RandomGenerator.prototype.initRandomArray = function() {
this.arr = [];
this.history = [];
this.last = null;
this.left = this.max;
for( var i = 0; i < this.max; i++ ) {
this.arr.push( i );
}
fisherYates( this.arr );
}
var mygen = new RandomGenerator(100);
console.log( mygen.generate() );
I got the fisherYates algorithm from here.
The approach of generating a new random number if it is already found in a history object will result in unnecessary looping.
Fiddle here
I tend to think that it is indeed not most efficient. I dont immediately get the //first time only.
Further, you can make code more readable by skipping the else return .. and writing the condition to be the opposite, e.g.:
if (maxNum >= 1) {
//code
} else {
return maxNum;
}
becomes
if (maxNum < 1) { // or maybe even if maxNum == 0
return maxNum;
}
//code
Also your x variable seems to be redundant.
I would probably implement it like this, using actual instances of random generators. This keeps the history of each generator separated.
function RandomGenerator(maxNum)
{
this.max = maxNum;
this.history = {};
this.histn = 0;
}
// generate random number in range [0..maxNum)
RandomGenerator.prototype.generate = function()
{
var value;
if (this.histn == this.max ) {
return false;
}
do {
value = Math.floor(Math.random() * this.max );
} while (this.history[value]);
this.history['' + value] = 1;
++this.histn;
return value;
}
var mygen = new RandomGenerator(100);
console.log(mygen.generate());
In my implementation I'm choosing a plain object for the history instead of an array; testing whether a value has been generated before is done by testing a property instead of $.inArray().
I agree with Alex that in most use cases, you'd want to generate an array of all values, shuffle them, and then pop them as you need them instead.
Here is an example:
var getShuffledUniqueRandoms = function(count, suffix) {
var values = [];
for (var i = 1; i < count+1; i++) {
values.push(i + suffix);
}
// Shuffle function originally from:
//+ Jonas Raoni Soares Silva
//# http://jsfromhell.com/array/shuffle [v1.0]
return (function(o){ //v1.0
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
})(values);
}
var values = getShuffledUniqueRandoms(10, "index");
$('button').click(function() {
if (values.length == 0) {
$('body').append('<p>Out of values.</p>');
} else {
$('body').append('<p>' + values.pop() + '</p>');
}
});
​
​FIDDLE
With this algorithm, it has a bigger upfront cost, but at least it has a known time it'll take to complete (roughly O(n)).
With the algorithm where you are constantly checking to see if a random value is in an array, it'll get slower and slower with each new iteration.
Now if your data set is always relatively small, your algorithm could work a little better, but anything larger than 10 or so and it starts losing it's edge.

Categories

Resources