Skip to content

Instantly share code, notes, and snippets.

@ScottKaye
Last active July 10, 2023 19:16
Show Gist options
  • Save ScottKaye/9963117 to your computer and use it in GitHub Desktop.
Save ScottKaye/9963117 to your computer and use it in GitHub Desktop.
A collection of potentially useful prototypes to make some things easier. Each of these should be crushable with http://www.iteral.com/jscrush/ . "Don't modify objects you don't own" is completely thrown out the window here in favour of coolness.
//Get a range of numbers between two numbers
//Usage: [1, 10].range returns [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Object.defineProperty(Array.prototype, "range", {
get: function () {
var range = [this[0]], i;
for (var i = this[0], len = this[1]; i < len; range.push(++i));
return range;
}
});
// Golfed TypeScript:
const range=(n:number,x:number,s=1):number[]=>new Array(-~((x-n)/s)).fill``.map((_,i)=>n+i*s);
//Returns an array of values interpolated between the first and second element.
//This will continue up until the max argument (m): interpolate(max)
//Adds "null" to the end of the array if that array isn't supported/nothing to interpolate.
//Usage: [1, 3].interpolate(15) returns [1, 3, 5, 7, 9, 11, 13, 15]
Object.defineProperty(Array.prototype, "interpolate", {
value: function (m) {
var r = [this[0]],
s = this[1] - this[0],
i;
if (s && m > 0) {
for (i = 0; r[i] + s <= m; r.push(r[i++] + s));
return r;
}
return this.concat(null);
}
});
//Calculate values between an array of values for n passes
//Usage: [1, 2, 3, 4].granularize(3); returns [1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3, 3.25, 3.5, 3.75, 4]
// [1, 2, 3, 4].granularize(2); returns [1, 1.5, 2, 2.5, 3, 3.5, 4]
Object.defineProperty(Array.prototype, "granularize", {
value: function(passes) {
//Safety
if (passes > 20) throw new Error("Granularizing " + passes + " times is going to take a long time.");
var i, j, place, current = this.slice(0);
for (i = 1; i < passes; ++i) {
place = [];
var len;
for (j = 0, len = current.length; j < len; ++j) {
place.push(current[j]), place.push((current[j] + current[j + 1]) / 2);
}
place.pop();
current = place;
}
return current;
}
});
//Multiply an array by another array
//Usage: [2, 4].times([4, 8]) returns [8, 32]
Object.defineProperty(Array.prototype, "times", {
value: function (a) {
return this.map(function(c, i) {
return c * a[i];
});
}
});
//Merge and remove duplicates of two arrays
//Usage: [1, 2, 3].merge([1, 2, 4, 5, 6]) returns [1, 2, 3, 4, 5, 6]
Object.defineProperty(Array.prototype, "merge", {
value: function (a) {
var s = this;
return this.concat(a.filter(function(c) {
return s.indexOf(c) < 0;
}));
}
});
//Remove non-unique elements from an array
//Usage: ["one", "two", "one", "three"].unique returns ["one", "two", "three"]
Object.defineProperty(Array.prototype, "unique", {
get: function() {
return this.filter(function(c, i, a) {
return a.indexOf(c) == i;
});
}
});
//LINQ-ish where function
//Usage: [{val: 1}, {val: 2}, {val: 3}, {val: 4}].where('val > 2'); returns [{val: 3}, {val: 4}]
// [{val: 1}, {val: 2}, {val: 3}, {val: 4}].where(function() { return this.val > 2; })); returns [{val: 3}, {val: 4}]
Object.defineProperty(Array.prototype, "where", {
value: function(query) {
switch(typeof query) {
case "string":
return this.filter(function(obj) {
return eval('obj.' + query.trim());
});
default:
return this.filter(function(obj) {
return query.call(obj);
});
}
}
});
//Listen for an event
//Usage: element.on("click", function() { ... });
Object.defineProperty(HTMLElement.prototype, "on", {
value: function(evt, func, capture) {
if (this.attachEvent) return this.attachEvent("on" + evt, func);
return this.addEventListener(evt, func, capture);
}
});
//Extend an object's properties to a default object
//Usage: {num: 1}.extend({ num: 5, operation: "multiply" }); returns {num: 1, operation: "multiply"}
Object.defineProperty(Object.prototype, "extend", {
value: function(defaults) {
for (var prop in defaults)
if (this.hasOwnProperty(prop))
defaults[prop] = this[prop];
return defaults;
}
});
//Converts an object (key=>value) to URL parameters, similar to PHP's http_build_query
//Usage: { key: "value", key2: "value2" }.asParams returns ?key=value&key2=value2
Object.defineProperty(Object.prototype, "asParams", {
get: function () {
var self = this;
return "?" + Object.keys(self).map(function (key) {
return encodeURIComponent(key) + "=" + encodeURIComponent(self[key]);
}).join("&");
}
});
//Tests if two objects are equal by comparing each key
//Usage: { key: "value" }.equals({ key: "value" }) returns true
Object.defineProperty(Object.prototype, "equals", {
value: function(obj) {
for (var prop in this)
if (this.hasOwnProperty(prop) && this[prop] !== obj[prop])
return false;
return true;
}
});
//Returns the difference between two objects
//Usage: { key: "value", key2: "value2" }.diff({ key: "changed", key2: "value2"}) returns { key: "changed" }
Object.defineProperty(Object.prototype, "diff", {
value: function (obj) {
var diff = {}, prop;
for (prop in this)
this.hasOwnProperty(prop) && obj[prop] != this[prop] && (diff[prop] = this[prop]);
for (prop in obj)
obj.hasOwnProperty(prop) && this[prop] != obj[prop] && (diff[prop] = obj[prop]);
return diff;
}
});
//Generates a "unique enough" ID to refer to objects as, one-way
Object.defineProperty(Object.prototype, "uniqid", {
get: function () {
return JSON.stringify(this).split("").map(function (m) {
return m.charCodeAt(0);
}).reduce(function (p, c, a) {
return p + c;
}).toString(36);
}
});
//Get or set pseudo element styles of an element from Javascript using some Shadow DOM trickery
//Limitation: Cannot get (can still set) styles for hover, focus, active, or visited. Only works for pseudo ELEMENTS.
//Usage: element.pseudo("after", "background: red") would make element's :after pseudo-element red
//Can also specify a CSSStyleDeclaration (element.style):
//Usage: element.pseudo("hover", document.querySelector(".hoverStyles").style)
//Example: Can be used to "copy" styles from one element to another: https://jsfiddle.net/n4erpea5/
Object.defineProperty(HTMLElement.prototype, "pseudo", {
value: function (pseudo, styles) {
if (styles) {
//Set style
var newStyles;
if (typeof styles === "string") {
newStyles = (styles + ";").replace(/;/g, " !important;");
} else if (styles instanceof CSSStyleDeclaration) {
newStyles = [];
[].forEach.call(styles, function (s) {
newStyles.push(s + ":" + styles[s]);
});
newStyles = newStyles.join(";");
}
pseudo = pseudo.toLowerCase();
//:before and :after can be set with :host:before and :host:after
//However, they won't work as :host(:before) and :host(:after)
//:hover, :focus, :active, and :visited will not with with :host:hover, etc
//However, they WILL work with :host(:hover), etc.
switch (pseudo) {
case "before":
case "after":
pseudo = ":" + pseudo;
break;
case "hover":
case "focus":
case "active":
case "visited":
pseudo = "(:" + pseudo + ")";
break;
default:
pseudo = "";
}
var root = this.createShadowRoot();
var html = "";
html += "<style>";
html += ":host" + pseudo + " { " + newStyles + "}";
html += "</style>";
html += "<content></content>";
root.innerHTML = html;
} else {
//Get style
pseudo = pseudo.replace(/:/g, "");
return window.getComputedStyle(this, pseudo);
}
}
});
//Converts a NodeList to an array
//Usage: document.getElementsByTagName("div").asArray;
Object.defineProperty(HTMLCollection.prototype, "asArray", {
get: function () {
var arr = [], i = this.length;
while (i--) arr.unshift(this[i]);
return arr;
}
});
//Math stuff
//Geometric mean
Object.defineProperty(Array.prototype, "geometricMean", {
value: function() {
return Math.pow(this.reduce(function(p, c) {
return p * c;
}), 1 / this.length);
}
});
//Average/mean
Object.defineProperty(Array.prototype, "mean", {
value: function() {
return this.reduce(function(p, c) {
return p + c;
}) / this.length;
}
});
//Median
//Usage: [1, 1, 2, 5, 5, 6, 9].median() returns 5
// [1, 1, 2, 6, 6, 9].median() returns 4 (average of 6 and 2)
Object.defineProperty(Array.prototype, "median", {
value: function() {
var self = this.sort(), m = this.length / 2;
return m % 1 ? self[m << 0] : (self[m << 0] + self[(m << 0) - 1]) / 2;
}
});
// Golfed TypeScript:
const median=(a:number[],m=(a.sort(),a.length/2)):number=>(a[(m-.1)|0]+a[m|0])/2;
//Mode
//Returns null if there is no mode (all items in series are unique)
Object.defineProperty(Array.prototype, "mode", {
value: function () {
var uniqs = {}, mode = {}, i;
this.sort().forEach(function (c) {
uniqs[c] = (uniqs[c] || 0) + 1;
});
if (Object.keys(uniqs).length == this.length) return null;
for (i in uniqs) {
mode = uniqs[i] > (mode.v || 0) ? {
i: i,
v: uniqs[i]
} : mode;
}
return mode.i;
}
});
//Population standard deviation
Object.defineProperty(Array.prototype, "stdDevPop", {
value: function () {
var n = this.length;
if (!n) return 0;
var sum = 0, sq_sum = 0, i;
this.forEach(function(c) {
sum += c;
sq_sum += c * c;
});
return Math.sqrt(sq_sum / n - Math.pow(sum / n, 2));
}
});
@nkosichek
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment