I'm trying to backwards engineer the array methods push, pull, shift, unshift, but I can't seem to figure out how to a) construct it b) call it. How could I do this? Here are the conditions:
returns an empty array object. this object should have the
following methods: push(val) adds val to the end of the array
pop() removes a value from the end and returns it unshift(val) adds
val to the beginning of the array shift() removes a value from the
beginning and returns it the goal of this problem is to reverse
engineer what array methods are actually doing and return an object
that has those methods
Here is what I initially thought it should look like.
function createArray() {
//CODE HERE
this.push = function Push(value){
if(index >= 0){
Mainarray[index++]=value;}
};
this.pop = function (){
if(index >= 0){
index--;
return Mainarray[index];
}
else{
// display message of Empty Array
console.log('Error: Item is not array');
}
};
this.unshift = function(){return ;};
}
You could use prototypes — like this:
function YourArray() {
this.arr = [];
this.index = 0;
}
YourArray.prototype.push = function( value ) {
this.arr[ this.index++ ] = value;
return this;
}
var arr = new YourArray();
arr.push('foo');
function NewArray() {
this.array = [];
}; /* Class */
NewArray.prototype.push = function(data) {
this.array.push(data);
} /* Method */
/* You should use prototypes, because all methods will became common, and if you are created methods like this.pop = function (){} then any instance will copy this functions */
var n = new NewArray();
n.push(2);
console.log(n);
Advantages of using prototype, vs defining methods straight in the constructor?
You can recreate the push method by assigning you array at position the length of the same array a value.
This is the prototype for the push:
Array.prototype.push = function(element) {
this[this.length] = element;
};
and this is for the pop method:
Array.prototype.pop = function() {
var key = this.stack.pop();
var prop = this.object[key];
delete this.object[key];
return prop;
};
You can make your own methods by changing the prototype names.
push to mypush or sthing
Example for your push function createArray:
this.push = function pushValue(value) {
this.arr[this.arr.length] = value;
};
I used native arrays methods as values assigned to keys in the returned object. The trick is to declare an array inside the object and use it as a reference. It should pass the checks you`re looking for.
function createArray() {
//CODE HERE
return {
arr: [],
push: function (val) {this.arr.push(val)},
pop: function() {return this.arr.pop()},
unshift: function (val) {return this.arr.unshift(val)},
shift: function() {return this.arr.shift()}
}
}
Related
I'm doing some practice with javascript data structures and am essentially trying to extend Array.
class Collection {
constructor(array){
let collection = Object.create(Array.prototype);
collection = (Array.apply(collection, array) || collection);
collection.clear = () => {
while(this.length > 0){
this.pop();
}
return this
};
return(collection);
}; }
The problem is that when I do the following
c = new Collection([1,2,3]);
c.clear();
c is still [1,2,3] when I am expecting [ ]. Why does modifying this not modify c?
Why does modifying this not modify c?
because this references an instance of Collection that you create with new Collection(...), while your constructor returns the value of let collection; which is NOT this in that context.
Besides that, your code is quite interresting. I think this is what you were trying to build:
class Collection extends Array {
constructor(array) {
// call the constructor of the Array class
super(array.length);
// copy the values from `array` onto `this`;
Object.assign(this, array);
}
clear() {
// that's all it takes to empty an Array
this.length = 0;
}
}
var c = new Collection([1, 2, 3]);
console.log(c);
c.clear();
console.log(c);
This is for the way you defining the function.
As you re defining as lamda expression, the value of this is not getting bound properly.
Change into to normal function declaration.
class Collection {
constructor(array){
let collection = Object.create(Array.prototype);
collection = (Array.apply(collection, array) || collection);
debugger;
collection.clear = function() {
while(this.length > 0){
this.pop();
}
return this
};
return(collection);
}; }
var c = new Collection([1,2,3]);
c.clear();
console.log(c);
Extend has proven challenging because I'm trying to manipulate the arguments object.
My current extend function does not account for more than one argument after the initial given object
_.extend = function(object, sources) {
return _.reduce(sources, function(memo, current) {
memo[Object.keys(sources)] = current || 0;
return memo;
}, object)
}
At first, I tried to make a copy of the arguments object, turn it into an array, and shift() the first argument out. This is terribly inelegant, but has still proven to be ineffective
I realized that apply() or call() should be used in this context somehow. When I tried it, it also didn't work.
_.extend = function(object) {
var copy = [].slice.call(arguments);
copy.shift();
doIT.apply(this, copy);
var doIt = function(copy) {
return _.reduce(copy, function(memo, current) {
memo[Object.keys(copy)] = current || 0;
return memo;
}, object)
}
doIt(copy);
}
Any ideas on what I can do to fix this?
There's no need to use apply on your function, just call it normally. By doing so, you are passing your shifted array as a list of arguments into your function. Since you are only working with copy in your parameter list then only one argument would make it. There's no need for call either, as you can easily invoke the function since no this context is required. Lastly, since your function is not a function declaration, it won't be available until the expression holding the function has been evaluated (available after var doIt).
Now, your doIt function is doing something wrong:
memo[Object.keys(copy)] = current || 0;
Object.keys(copy) returns an array with copy keys. So you are doing:
memo[array] = current || 0;
The array will be casted to a string, but it's definitely not something you want either. What you need to is iterate each element properties of the copy array (each on is on current) and copy those properties into your first object (memo accumulator). Like this:
var extend = function (object) {
var copy = [].slice.call(arguments);
copy.shift();
var doIt = function (copy) {
return copy.reduce(function (memo, current) {
Object.keys(current).forEach(function (key) {
memo[key] = current[key];
});
return memo;
}, object)
}
return doIt(copy);
}
However, extends still need to handle the appropriated getters and setters. So you'll need to do something like:
var extend = function (object) {
var copy = [].slice.call(arguments);
copy.shift();
var doIt = function (copy) {
return copy.reduce(function (memo, current) {
Object.keys(current).forEach(function (key) {
var pDesc = Object.getOwnPropertyDescriptor(current, key);
Object.defineProperty(memo, key, pDesc);
});
return memo;
}, object)
}
return doIt(copy);
}
I would like to store function pointers in an Array and then execute all of them in a foreach loop.
var array = new Array();
array['foo'] = function() { doFoo(); };
array['bar'] = function() { doBar(); };
How do I iterate and execute all functions in array?
First, if you really want to use non-numeric property names, you don't need an array:
var obj = {};
obj["foo"] = function() { doFoo(); }
obj["bar"] = function() { doBar(); }
To iterate and call the functions:
for (var k in obj) {
obj[k]();
}
To be pedantic, it's usually considered a good idea to make sure you're not running into unexpected properties inherited from the prototype:
for (var k in obj) {
if (obj.hasOwnProperty(l))
obj[k]();
}
I'm curious how to go about implementing my own sort function on the Array object. Ignoring all the usual warnings/dangers about extending/overriding a built-in, consider this:
Array.prototype.sort = function() {
this = mySortFunction(this);
function mySortFunction(arr) { ... };
};
Inside the closure, this refers to the Array object [number, number2, number3, etc.]. How do I go about reassigning this to be the result of my internal sorting function? Is it possible?
Your solution seems a little redundant:
Array.prototype.sort = function() {
this = mySortFunction(this);
function mySortFunction(arr) {
arr = yetAnotherSortFunction(arr)
function yetAnotherSortFunction(arr2) {...}
// and so on...
};
};
If you really want to do it this way, why not reference your array directly in the first place:
Array.prototype.sort = function() {
// your implementation:
// for (var i = this.length, ...
// if (this[0] == ...
// this[i] = ...
// ...
};
So I have a class foo that has a method which returns an array bar. I have another function that calls foo.getBar and then filters the array. I want to be able to always get the original contents of bar when I use a different filter, but bing seems to be just creating a reference to bar, not a separate array. I have tried using return this.bar.valueOf(); in my function foo, still not working. When I remove items from bing they are also removed from bar. Someone please enlighten me on creating a unique array instead of a reference.
function foo(x, y, z){
this.bar = new Array();
...
this.bar = [ some , stuff , in , bar ];
this.getBar = function getBar(){
return this.bar;
}
...
}
var FooObject = new foo(x,y,z);
function baz(){
var bing = FooObject.getBar();
bing.splice(remove some pieces of the array);
}
The easiest (and as far as I know, fastest) way to get a copy of an array is to use the slice method. Without any arguments, it defaults to array.slice(0, array.length), so it will copy the entire array.
Your getBar function would look like this:
this.getBar = function getBar(){
return this.bar.slice();
}
Note that this is a shallow copy, so any changes to the objects in the array will affect the original (adding and removing items won't affect it though).
For objects, use the clone method:
function cloneObject(source) {
for (i in source) {
if (typeof source[i] == 'source') {
this[i] = new cloneObject(source[i]);
}
else {
this[i] = source[i];
}
}
}
var obj1= {bla:'blabla',foo:'foofoo',etc:'etc'};
var obj2= new cloneObject(obj1);
What you'll have to do is something like the following, passing a function as a parameter and force a pass-by-value;
function foo(x, y, z) {
this.bar = ['uno', 'dos', 'tres'];
}
foo.prototype.getBar = function() {
return this.bar;
}
...
function getBar(fn) {
return fn();
}
...
var f = new foo(x, y, z);
var bing = getBar(f.getBar);
Returning a "clone" will make sure original array is untouched. Note that such clone will be shallow.
function foo(x, y, z){
this.bar = [ some , stuff , in , bar ];
...
this.getBar = function getBar(){
return this.bar.concat([]);
}
...
}
Unfortunately javascript arrays and objects are always passed by reference. If you are guaranteed that your foo.bar array is 1-dimensional/contains no arrays or objects,
Then you can do:
var bing = FooObject.getBar().slice(0);
Which will do a 1-deep copy of foo.bar, resulting in your bing array being independent of the foo.bar array.
Otherwise you'll have to roll/find a deep copy method, such as the $A function in mootools
var newArray = $A(oldArray)