Background: I'm reading the online book Eloquent JavaScript and one of the exercises in Chapter 6 mentions that a "Sequence" can behave similarly to a linked list. Here is the link to the exercise, and I've copied a bit of relevant text:
Another solution is to avoid changing state in the object. You can expose a method for getting the current element (without advancing any counter) and another for getting a new sequence that represents the remaining elements after the current one (or a special value if the end of the sequence is reached).
I am trying to build a Sequence by recursively calling the implementing class's (ArraySeq) constructor within the interface class. However when running a test in node, I'm getting TypeError: Cannot read property '0' of undefined at Sequence.ArraySeq.
I've copied and pasted my (incomplete) implementation:
/**
* Sequence interface
*/
function Sequence(current, rest) {
this.current = current;
this.rest = rest;
}
Object.defineProperty(Sequence.prototype, "end", {
get: function() {
return this.rest === undefined;
}
});
Sequence.prototype.next = function() {
return this.rest;
};
/**
* Array implementation of sequence
*/
function ArraySeq(array) {
if (array === []) {
Sequence.call(undefined, undefined);
} else {
Sequence.call(array[0], new ArraySeq(array.slice(1)));
}
}
ArraySeq.prototype = Object.create(Sequence.prototype);
/**
* Logs all elements in a Sequence
*/
function logSequence(sequence) {
while (sequence.rest !== undefined) {
console.log(sequence.current);
sequence = sequence.rest;
}
}
logSequence(new ArraySeq([1, 2]));
Thank you for reading this far, any help or guidance is greatly appreciated!
As I noted in comments:
array.splice[1] will give you undefined. You want array.slice(1) - the whole array without the first element: slice, not splice. array.splice(1) will delete the second element from the array and return that element - not what you want.
You wrote Sequence as a constructor, but you are not calling it as a constructor. Instead of Sequence.call, use new Sequence.
Conversely, you are calling new ArraySeq, but ArraySeq does not look like a constructor. Use just ArraySeq, and make it return stuff (return new Sequence...).
Use if (!array.length) to test for array being non-empty. array === [], and even array == [], can never return true, because objects (and thus arrays) are compared based on object identity, not equality, and you just created a new one (so there is no chance it is the same object as something that already existed).
And of course, ArraySequence is not defined; that was supposed to be ArraySeq, right?
With those changes, your code works. EDIT: However, the exercise wants ArraySeq to be an object, so still a bit more work... First of all, "interface" is not an object. It is just how an object should behave. My go at the exercise would be:
function ArraySeq(array) {
this.array = array;
this.index = 0;
}
Object.defineProperty(ArraySeq.prototype, "end", {
get: function() {
return this.index >= this.array.length;
}
});
Object.defineProperty(ArraySeq.prototype, "next", {
get: function() {
return this.array[this.index++];
}
});
/**
* Logs all elements in a Sequence
*/
function logSequence(sequence) {
while (!sequence.end) {
console.log(sequence.next);
}
}
logSequence(new ArraySeq([1, 2]));
The "interface" here is .end and .next. If you want to go the route of your quote, then it changes slightly. The interface here is .end, .rest and .value:
function ArraySeq(array) {
this.array = array;
}
Object.defineProperty(ArraySeq.prototype, "end", {
get: function() {
return this.array.length == 0;
}
});
Object.defineProperty(ArraySeq.prototype, "rest", {
get: function() {
return new ArraySeq(this.array.slice(1));
}
});
Object.defineProperty(ArraySeq.prototype, "value", {
get: function() {
return this.array[0];
}
});
/**
* Logs all elements in a Sequence
*/
function logSequence(sequence) {
while (!sequence.end) {
console.log(sequence.value);
sequence = sequence.rest;
}
}
logSequence(new ArraySeq([1, 2]));
first, splice is method.
array.splice(1) instead of array.splice[1].
and use array.length == 0 in array === [].
if two object is different object, then === operator treated as false even all element is same.
Related
I was working on a hackerrank problem and test cases showed that something was wrong with my 'remove' method. I always got undefined instead of true/false.
I know splice returns array of deleted elements from an array. When I console.log inside map, it looked like everything was fine when I was deleting first element (I was getting what I expected except true/false). But when 'name' I am deleting is not first element, I didn't get what I expected to get. Could you help me fix this? And of course, I never get true or false...
class StaffList {
constructor() {
this.members = [];
}
add(name, age) {
if (age > 20) {
this.members.push(name)
} else {
throw new Error("Staff member age must be greater than 20")
}
}
remove(name) {
this.members.map((item, index) => {
if(this.members.includes(name)) {
console.log(name)
let removed = this.members.splice(item, 1);
console.log(removed)
return true;
} else {
return false;
}
})
}
getSize() {
return this.members.length;
}
}
let i = new StaffList;
i.add('michelle', 25)
i.add('john', 30);
i.add('michael', 30);
i.add('jane', 26);
i.remove('john');
console.log(i);
Your return statements are wrapped within .map() (which you misuse in this particular case, so you, essentially, build the array of true/false), but your remove method does not return anything.
Instead, I would suggest something, like that:
remove(name){
const matchIdx = this.members.indexOf(name)
if(matchIdx === -1){
return false
} else {
this.members.splice(matchIdx, 1)
return true
}
}
In the remove method, you're using map with the array, which runs the function you give as argument for each array element. But I believe you don't want to do that.
Using the example you have bellow, basically what you do there is check if the array contains the name 'john', and if so, you delete the first item that appears in the array (which would be 'michelle'). This happens because the map function will run for every element, starting on the first one, and then you use that item to be removed from the array. After that, it returns the function, and no other elements get removed.
So my suggestion is just getting rid of the map function and running its callback code directly in the remove method (you would need to get the name's index in the array to use the splice method).
It is not clear why you need to use iterative logic to remove an item. You can simply use findIndex() to get the position of the member in the array. If the index is not -1, then you can use Array.prototype.slice(index, 1) to remove it. See proof-of-concept example below:
class StaffList {
constructor() {
this.members = [];
}
add(name, age) {
if (age > 20) {
this.members.push(name)
} else {
throw new Error("Staff member age must be greater than 20")
}
}
remove(name) {
const index = this.members.findIndex(x => x === name);
if (index !== -1) {
this.members.splice(index, 1);
}
}
getSize() {
return this.members.length;
}
}
let i = new StaffList;
i.add('michelle', 25)
i.add('john', 30);
i.add('michael', 30);
i.add('jane', 26);
i.remove('john');
console.log(i);
Use a filter method instead of map it's more elegant and you can return the rest of the array as well instead of true or false unless the problem you're working on requires true of false specifically.
You could write something like this:
remove(name) {
if (!this.members.some(el => el === name)) return false;
this.members = this.members.filter(item => item !== name);
return true;
}
One can make an object iterable by implementing [Symbol.iterator].
But how can one override the behavior of the [] operator?
For example i have a an object which has an array inside of it and i want to be able to access that given an index like obj[3].
is that possible?
example
const SignalArray = (data = []) => {
...
return {
add,
remove,
onAdd,
onRemove,
onSort,
removeOnAdd,
removeOnRemove,
removeOnSort,
[Symbol.iterator]() {
return {
next: () => {
if (index < data.length) {
return { value: data[index++], done: false };
} else {
index = 0;
return { done: true };
}
}
}
}
}
}
how can one override the behavior of the [] operator?
Only via Proxy, added in ES2015. You'd provide a get trap and handle the property keys you want to handle.
Here's an example where we check for property names that can be successfully coerced to numbers and return the number * 2:
const o = new Proxy({}, {
get(target, prop, receiver) {
const v = +prop;
if (!isNaN(v)) {
return v * 2;
}
return Reflect.get(...arguments);
}
});
o.x = "ex";
console.log(o[2]); // 4
console.log(o[7]); // 14
console.log(o.x); // "ex"
If you want to override setting the array element, you'd use set trap. There are several other traps available as well. For instance, in a reply to a comment, you said:
...if you hate es6 classes and want to write a wrapper around an array that gives it extra functionality, like an observable array for example...
...that would probably involve a set trap and overriding various mutator methods.
I am stumped with this memoize problem. I need to create a function that will check to see if a value has already been calculated for a given argument, return the previous result, or run the calculation and return that value.
I have spent hours on this and while I am new to JS. I cannot get my head around how to do this. I cannot use any built in functions and would really like to understand what I need to do.
Here is what I have so far, which is so wrong it feels like pseudo-code at this point. I have searched existing memoize questions out here but I cannot seem to make any solution work yet. Any help is much appreciated.
myMemoizeFunc = function(passedFunc) {
var firstRun = passedFunc;
function check(passedFunc){
if(firstRun === undefined){
return passedFunc;
}else{return firstRun;}
}
};
Sorry, I should have been more clear. Here are my specific requirements:
myMemoizeFunc must return a function that will check if the calculation has already been calculated for the given arg and return that val if possible. The passedFunc is a function that holds the result of a calculation.
I understand this may seem like a duplicate, but I am marking as not so, as I am having some serious difficulty understanding what I should do here, and need further help than is given in other posts.
This is what my thought process is bringing me towards but again, I am way off.
myMemoizeFunc = function(passedFunc) {
var allValues = [];
return function(){
for(var i = 0; i < myValues.length; i++){
if(myValues[i] === passedFunc){
return i;
}
else{
myValues.push(passedFunc);
return passedFunc;
}
}
}
};
I should not be returning i or passedFunc here, but what else could I do within the if/else while checking for a value? I have been looking at this problem for so long, I am starting to implement code that is ridiculous and need some fresh advice.
I think the main trick for this is to make an object that stores arguments that have been passed in before as keys with the result of the function as the value.
For memoizing functions of a single argument, I would implement it like so:
var myMemoizeFunc = function (passedFunc) {
var cache = {};
return function (x) {
if (x in cache) return cache[x];
return cache[x] = passedFunc(x);
};
};
Then you could use this to memoize any function that takes a single argument, say for example, a recursive function for calculating factorials:
var factorial = myMemoizeFunc(function(n) {
if(n < 2) return 1;
return n * factorial(n-1);
});
Consider this an extension on the answer of Peter Olson.
For a variable number of arguments you could use something like this.
Note: This example is not optimal if you intent to pass complex arguments (arrays, objects, functions). Be sure to read further and not copy/paste blindly.
function memo(fn) {
const cache = {};
function get(args) {
let node = cache;
for (const arg of args) {
if (!("next" in node)) node.next = new Map();
if (!node.next.has(arg)) node.next.set(arg, {});
node = node.next.get(arg);
}
return node;
}
return function (...args) {
const cache = get(args);
if ("item" in cache) return cache.item;
cache.item = fn(...args);
return cache.item;
}
}
This builds the following cache tree structure:
const memoizedFn = memo(fn);
memoizedFn();
memoizedFn(1);
memoizedFn(1, 2);
memoizedFn(2, 1);
cache = {
item: fn(),
next: Map{ // <- Map contents depicted as object
1: {
item: fn(1),
next: Map{
2: { item: fn(1, 2) }
}
},
2: {
next: Map{
1: { item: fn(2, 1) }
}
}
}
}
This solution leaks memory when passing complex arguments (arrays, object, functions) that are no longer referenced afterwards.
memoizedFn({ a: 1 })
Because { a: 1 } is not referenced after the memoizedFn call it would normally be garbage collected. However now it can't be because cache still holds a reference. It can only be garbage collected once memoizedFn itself is garbage collected.
I showed the above first because it shows the base concept and demonstrates the cache structure in a somewhat simple form. To clean up cache that would normally be garbage collected we should use a WeakMap instead of a Map for complex objects.
For those unfamiliar with WeakMap, the keys are a "weak" reference. This means that the keys do not count towards active references towards an object. Once an object is no longer referenced (not counting weak references) it will be garbage collected. This will in turn remove the key/value pair from the WeakMap instance.
const memo = (function () {
const primitives = new Set([
"undefined",
"boolean",
"number",
"bigint",
"string",
"symbol"
]);
function typeOf(item) {
const type = typeof item;
if (primitives.has(type)) return "primitive";
return item === null ? "primitive" : "complex";
}
const map = {
"primitive": Map,
"complex": WeakMap
};
return function (fn) {
const cache = {};
function get(args) {
let node = cache;
for (const arg of args) {
const type = typeOf(arg);
if (!(type in node)) node[type] = new map[type];
if (!node[type].has(arg)) node[type].set(arg, {});
node = node[type].get(arg);
}
return node;
}
return function (...args) {
const cache = get(args);
if ("item" in cache) return cache.item;
cache.item = fn(...args);
return cache.item;
}
}
})();
const fib = memo((n) => {
console.log("fib called with", n);
if (n == 0) return 0;
if (n == 1) return 1;
return fib(n - 1) + fib(n - 2);
});
// heavy operation with complex object
const heavyFn = memo((obj) => {
console.log("heavyFn called with", obj);
// heavy operation
return obj.value * 2;
});
// multiple complex arguments
const map = memo((iterable, mapFn) => {
console.log("map called with", iterable, mapFn);
const result = [];
for (const item of iterable) result.push(mapFn(item));
return result;
});
console.log("### simple argument demonstration ###");
console.log("fib(3)", "//=>", fib(3));
console.log("fib(6)", "//=>", fib(6));
console.log("fib(5)", "//=>", fib(5));
console.log("### exlanation of when cache is garbage collected ###");
(function () {
const item = { value: 7 };
// item stays in memo cache until it is garbade collected
console.log("heavyFn(item)", "//=>", heavyFn(item));
console.log("heavyFn(item)", "//=>", heavyFn(item));
// Does not use the cached item. Although the object has the same contents
// it is a different instance, so not considdered the same.
console.log("heavyFn({ value: 7 })", "//=>", heavyFn({ value: 7 }));
// { value: 7 } is garbade collected (and removed from the memo cache)
})();
// item is garbade collected (and removed from memo cache) it is no longer in scope
console.log("### multiple complex arguments demonstration ###");
console.log("map([1], n => n * 2)", "//=>", map([1], n => n * 2));
// Does not use cache. Although the array and function have the same contents
// they are new instances, so not considdered the same.
console.log("map([1], n => n * 2)", "//=>", map([1], n => n * 2));
const ns = [1, 2];
const double = n => n * 2;
console.log("map(ns, double)", "//=>", map(ns, double));
// Does use cache, same instances are passed.
console.log("map(ns, double)", "//=>", map(ns, double));
// Does use cache, same instances are passed.
ns.push(3);
console.log("mutated ns", ns);
console.log("map(ns, double)", "//=>", map(ns, double));
The structure stays essentially the same, but depending on the type of the argument it will look in either the primitive: Map{} or complex: WeakMap{} object.
const memoizedFn = memo(fn);
memoizedFn();
memoizedFn(1);
memoizedFn(1, 2);
memoizedFn({ value: 2 }, 1);
cache = {
item: fn(),
primitive: Map{
1: {
item: fn(1),
primitive: Map{
2: { item: fn(1, 2) }
}
}
},
complex: WeakMap{
{ value: 2 }: { // <- cleared if { value: 2 } is garbage collected
primitive: Map{
1: { item: fn({ value: 2 }, 1) }
}
}
}
}
This solution does not memoize any errors thrown. Arguments are considered equal based on Map key equality. If you also need to memoize any errors thrown I hope that this answer gave you the building blocks to do so.
There are a number of memoization libraries available. Doing memoization efficiently is not as straight forward as it seems. I suggest a library be used. Two of the fastest are:
https://github.com/anywhichway/iMemoized
https://github.com/planttheidea/moize
See here for a comprehensive(-ish) list of memoization libraries: https://stackoverflow.com/a/61402805/2441655
This question already has an answer here:
Double-Queue Code needs to be reduced
(1 answer)
Closed 9 years ago.
Is there any way for me to shorten this code by using pointers?
I need to make a class that has mostly the same function as a given array class unshift,shift,push and pop but with different names.
var makeDeque = function()
{
var a= [], r=new Array(a);
length = r.length=0;
pushHead=function(v)
{
r.unshift(v);
}
popHead=function()
{
return r.shift();
}
pushTail=function(v)
{
r.push(v);
}
popTail=function()
{
return r.pop();
}
isEmpty=function()
{
return r.length===0;
}
return this;
};
(function() {
var dq = makeDeque();
dq.pushTail(4);
dq.pushHead(3);
dq.pushHead(2);
dq.pushHead("one");
dq.pushTail("five");
print("length " + dq.length + "last item: " + dq.popTail());
while (!dq.isEmpty())
print(dq.popHead());
})();
Output should be
length 5last item: five
one
2
3
4
Thanks!
Maybe I'm oversimplifying, but why not just add the extra methods you need to the Array prototype and call it directly?
I need to make a class that has mostly the same function as a given array class unshift,shift,push and pop but with different names.
I suppose you could add these "new" methods to Array.prototype.
Like this perhaps?
var makeDeque = (function (ap) {
var Deque = {
length: 0,
pushHead: ap.unshift,
popHead: ap.shift,
pushTail: ap.push,
popTail: ap.pop,
isEmpty: function () {
return !this.length;
}
};
return function () {
return Object.create(Deque);
};
})(Array.prototype);
DEMO
If it's still too long, you can always directly augment Array.prototype like others already mentionned. We agree that it's all experimental here and the only goal is to save characters.
!function (ap) {
ap.pushHead = ap.unshift;
ap.popHead = ap.shift;
ap.pushTail = ap.push;
ap.popTail = ap.pop;
ap.isEmpty = function () {
return !this.length;
};
}(Array.prototype);
function makeDeque() {
return [];
}
This can be compressed to 174 chars:
function makeDeque(){return[]}!function(e){e.pushHead=e.unshift;e.popHead=e.shift;e.pushTail=e.push;e.popTail=e.pop;e.isEmpty=function(){return!this.length}}(Array.prototype)
DEMO
Not sure why you need this, but my suggestions per best practice are:
Don't override the Array.prototype. The reason for this is because other libraries might try to do the same, and if you include these libraries into yours, there will be conflicts.
This code is not needed. var a= [], r=new Array(a);. You only need ...a = [];.
Ensure you are creating a real class. In your code, makeDeque is not doing what you want. It is returning this which when a function is not called with the new keyword will be the same as the window object (or undefined if you are using what is called as "strict mode"). In other words, you have made a lot of globals (which are usually a no-no, as they can conflict with other code too).
When you build a class, it is good to add to the prototype of your custom class. This is because the methods will only be built into memory one time and will be shared by all such objects.
So I would first refactor into something like this:
var makeDeque = (function() { // We don't need this wrapper in this case, as we don't have static properties, but I've kept it here since we do want to encapsulate variables in my example below this one (and sometimes you do need static properties).
function makeDeque () {
if (!(this instanceof makeDeque)) { // This block allows you to call makeDeque without using the "new" keyword (we will do it for the person using makeDeque)
return new makeDeque();
}
this.r = [];
this.length = 0;
}
makeDeque.prototype.setLength = function () {
return this.length = this.r.length;
};
makeDeque.prototype.pushHead=function(v) {
this.r.unshift(v);
this.setLength();
};
makeDeque.prototype.popHead=function() {
return this.r.shift();
this.setLength();
};
makeDeque.prototype.pushTail=function(v){
this.r.push(v);
this.setLength();
};
makeDeque.prototype.popTail=function() {
return this.r.pop();
this.setLength();
};
makeDeque.prototype.isEmpty=function() {
return this.r.length === 0;
};
return makeDeque;
}());
Now you could shorten this as follows, but I wouldn't recommend doing this, since, as it was well said by Donald Knuth, "premature optimization is the root of all evil". If you try to shorten your code, it may make it inflexible.
var makeDeque = (function() {
function makeDeque () {
if (!(this instanceof makeDeque)) {
return new makeDeque();
}
this.r = [];
this.length = 0;
}
makeDeque.prototype.setLength = function () {
return this.length = this.r.length;
};
for (var i=0, methodArray = [
['pushHead', 'unshift'], ['popHead', 'shift'], ['pushTail', 'push'], ['popTail', 'pop']
]; i < methodArray.length; i++) {
makeDeque.prototype[methodArray[i][0]] = (function (i) { // We need to make a function and immediately pass in 'i' here because otherwise, the 'i' inside this function will end up being set to the value of 'i' after it ends this loop as opposed to the 'i' which varies with each loop. This is a common "gotcha" of JavaScript
return function () {
var ret = this.r[methodArray[i][1]].apply(this.r, arguments);
this.setLength();
return ret;
};
}(i));
}
makeDeque.prototype.isEmpty=function() {
return this.r.length === 0;
};
return makeDeque;
}());
If you need to get the length by a length property, as opposed to a method like setLength() which sets it manually after each update, either of the above code samples could be shortened by avoiding the setLength() method, but you'd need to use the Object.defineProperty which does not work (or does not work fully) in older browsers like IE < 9.
Was looking for "equivalent for some method in javascript" and "return just one value if is in array", but saw only the answers to the way in which to determine the type of variables or too many unnecessary.
I bypass all inputs in html and i want something like this:
$('#goodsFilter')
.find('input[type="number"]')
.some(function(i,el){
return (isNumber($(el).val())) ? 1 : 0;
});
But it throws an error:
"TypeError: 'undefined' is not a function" (eg. Safari 6.0.4).
UPD: Error comes from the last line, yeah, where });.
isNumber:
function isNumber(n) { return !isNaN(parseFloat(n)) && isFinite(n); }
This should check for the presence of each input information, and, if at least one of them is not empty, return 1, otherwise 0.
How can I replace it to work in most modern browsers?
UPD:
Problem was solved. I'm a little confused in choosing the answer. The code of #RobG implementation of .some() is more understandable for beginners (and I am) so I switched my vote.
For anyone else who comes to this thread, you can use some() on a jQuery object this way:
$.makeArray($(...)).some(function(x) { ... })
jQuery.makeArray() converts the jQuery object into an Array, so you can use some() on it.
As suggested by #alf-eaton, you could use:
$(…).toArray().some(function(node) { … })
Array.prototype.some returns true or false, so you can do:
.some(function(el){
return !isNaN(el.value);
}
You don't say where the error comes from, is it from the call to isNumber?
Edit
Ah, so your issue is with some.
If you want a jQuery some method, then it should at least mimic the built–in ECMAScript some, which takes two arguments: a callback function and an optional this argument.
The callback function should take three arguments: the value, the index (optional) and an optional value to use as the this argument. It should access the numeric members in ascending order and only visit members that actually exist.
So it should be something like (noting that jQuery.fn === jQuery.prototype):
jQuery.fn.some = function(fn, thisArg) {
var result;
for (var i=0, iLen = this.length; i<iLen; i++) {
if (this.hasOwnProperty(i)) {
if (typeof thisArg == 'undefined') {
result = fn(this[i], i, this);
} else {
result = fn.call(thisArg, this[i], i, this);
}
if (result) return true;
}
}
return false;
}
So if you want now you can do:
var result = $('#goodsFilter')
.find('input[type="number"]')
.some(function(el) {
return isNumber(el.value);
})? 1 : 0;
or you can do either of the following to coerce true to 1 and false to 0:
var result = Number($('#goodsFilter')
.find('input[type="number"]')
.some(function(el) {
return isNumber(el.value);
}));
or
var result = +($('#goodsFilter')
.find('input[type="number"]')
.some(function(el) {
return isNumber(el.value);
}));
The above is only lightly tested, the optional thisArg parameter might be redundant.
You could use the .filter method, and then check the length.
$('#goodsFilter')
.find('input[type="number"]')
.filter(function(i,el){ return isNumber($(el).val())); })
.length > 0
$(...).is(function) should work too. The jQuery API documentation states (emphasis mine):
Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments.
So using the example in the question, we would have something like:
var result = $('#goodsFilter')
.find('input[type="number"]')
.is(function(idx, el) {
return isNumber(el.value);
})? 1 : 0;
. . In the most basic version, you can just create a "some" function:
function eSome(arr, f) { var i = 0, n = arr.length;
for (;i<n;i++) { if (!i in arr) { continue }
if (f(i, arr[i])) { return true; }
} return false;
}
var list = [0, 1, 2, 3, 4, 5];
var testFunction = function (i, e) { return e === 2; };
console.log(eSome(list, testFunction));
//returns true and the loop ran only for the necessary three times.
. . If you want to chain the .some call in a jQuery object, you can add it as a jQuery function as well, using something like this (now tested and fixed) example:
jQuery.fn.some = function (f) { var i = 0, n = this.length;
for (;i<n;i++) { if (!i in this) { continue }
if (f(i, this[i])) { return true; }
}
return false;
}
$('.a').some(function (i, el) { return ($(el).text() == 'weeee!'); });
. . As #RobG pointed out in the comments, the native Array.prototype.some implementation calls your callback with a different set of parameters. I'm following the OP's sample code, but you can mimic the ECMA implementation's parameter with if (f(this[i], i, this)) { return true; } inside the loop.
. . You can also shim it on Array.prototype.some, but I strongly advise against any direct modifications to the built-in prototypes.
Implementation in Vanilla Javascript( with arrow syntax)
function some(arr,callback){
for(let i=0;i<arr.length;i++){
if(callback(arr[i],i,arr)){
return true;
}
}
return false;
}
some use:
check if an array has an even number:
function hasEvenNum(arr){
return arr.some(value=>{
return value % 2 === 0;
});
}
Try to use [].prototype.call method, the first argument will be an Array-like value, the second one is a function that will be called on each element.
[].some.call($('#goodsFilter').find('input[type="number"]'), function (el) {
return isNumber($(el).val());
});