Skip to content

Instantly share code, notes, and snippets.

@berzniz
Last active May 22, 2022 23:15
Show Gist options
  • Save berzniz/7632148 to your computer and use it in GitHub Desktop.
Save berzniz/7632148 to your computer and use it in GitHub Desktop.
Some small javascript hacks for hipsters
// Boring
if (isThisAwesome) {
alert('yes'); // it's not
}
// Awesome
isThisAwesome && alert('yes');
// Also cool for guarding your code
var aCoolFunction = undefined;
aCoolFunction && aCoolFunction(); // won't run nor crash
var x = 1;
debugger; // Code execution stops here, happy debugging
x++;
var x = Math.random(2);
if (x > 0.5) {
debugger; // Conditional breakpoint
}
x--;
var deeplyNestedFunction = function() {
var private_object = {
year: '2013'
};
// Globalize it for debugging:
pub = private_object;
};
// Now from the console (Chrome dev tools, firefox tools, etc)
pub.year;
['first', 'name'].join(' '); // = 'first name';
['milk', 'coffee', 'sugar'].join(', '); // = 'milk, coffee, sugar'
// Boring
if (success) {
obj.start();
} else {
obj.stop();
}
// Hipster-fun
var method = (success ? 'start' : 'stop');
obj[method]();
// default to 'No name' when myName is empty (or null, or undefined)
var name = myName || 'No name';
// make sure we have an options object
var doStuff = function(options) {
options = options || {};
// ...
};
var firstName = 'Tal';
var screenName = 'ketacode'
// Ugly
'Hi, my name is ' + firstName + ' and my twitter screen name is @' + screenName;
// Super
var template = 'Hi, my name is {first-name} and my twitter screen name is @{screen-name}';
var txt = template.replace('{first-name}', firstName)
.replace('{screen-name}', screenName);
var a = [1,2,3,4,5,6,7,8,9,10];
console.time('testing_forward');
for (var i = 0; i < a.length; i++);
console.timeEnd('testing_forward');
// output: testing_forward: 0.041ms
console.time('testing_backwards');
for (var i = a.length - 1; i >= 0; i--);
console.timeEnd('testing_backwards');
// output: testing_backwards: 0.030ms
var z = 15;
doSomeMath(z, 10);
xxx // Great placeholder. I'm the only one using xxx and it's so easy to find in code instead of TODOs
doSomeMoreMath(z, 15);
@cScarlson
Copy link

Arbiter Pattern

Decorate a Function instance as a namespace so you can invoke the namespace with default (arbitrated) behavior. Use a "Facade" to protect private methods on the class.

var Class = function Class() {

    function publicMethod() {}
    function privateMethod() {}

    // export precepts
    this.publicMethod = publicMethod;
    this.privateMethod = privateMethod;

    return this;
};

var Facade = function Facade($class) {

    function init() {
        $class.privateMethod();
    }

    function doDefault() {
        return this;
    }

    function publicMethod(param) {
        $class.publicMethod(param);
        return this;
    }

    // export precepts
    this.doDefault = doDefault;
    this.publicMethod = publicMethod;

    return this;
};

var A = new (function Arbiter(Class, Facade) {
    var options = { };

    var F = Facade.call(function F() {
        if (this instanceof F) return new Arbiter(Class, Facade);
        return F.doDefault.apply(F, arguments);
    }, new Class());

    return F;  // as A
})(Class, Facade);

A() === A.doDefault() === A.publicMethod()() === A()()();
A.publicMethod();
A.privateMethod();  // Error
let a = A
  , b = new A()
  ;
a === b;  // false

@cScarlson
Copy link

cScarlson commented Jan 22, 2018

Sorting Collections on Multiple Keys [ Efficiently ]

Intention

You may have a sort function that is being called in multiple parts of an application where the the sorting logic. You also may have to sort upon multiple keys of items in a collection and the prioritization of how those keys should effect the sorting algorithm may vary across modules. When these criteria are the case, it may be better to modify the source code of the sorting function, this is a problem if you are using the sorter in multiple places. Even in the case of only one module calling Array.prototype.sort, you may still want a single sort function whose signature remains the same and operates just like any other basic sort function.

TL:DR:

var Model = function Model(a, b, c, d) {

    this.a = a;
    this.b = b;
    this.c = c;
    this.d = d;

    return this;
};

var collection = [
    new Model(3, 3, 3, 3),
    new Model(2, 2, 2, 2),
    new Model(0, 1, 2, 3),
    new Model(0, 1, 2, 2),
    new Model(1, 2, 3, 1),
    new Model(1, 2, 2, 1),
    new Model(0, 0, 0, 0),
    new Model(1, 1, 1, 1),
];

// 3: Sort by Multiple keys (Reusable) using sortByKey()
function sortByKey(k, a, b) {
    if (a[k] > b[k]) return  1;
    if (a[k] < b[k]) return -1;
    return 0;
}

// 6: Sort by Multiple keys (Reusable + Optimized) using Reusable prioritySort()
function prioritySort(keys, a, b) {
    var i = 0, keys = Array.prototype.slice.call(keys || [ ], 0);
    while (i === 0 && keys.length) i = sortByKey.call(this, keys.shift(), a, b);
    return i;
}
var sort = prioritySort.bind(collection, [ 'a', 'b', 'c', 'd' ]);
collection.sort(sort);
console.log('>', collection);
// >
[
    { "a": 0, "b": 0, "c": 0, "d": 0 },
    { "a": 0, "b": 1, "c": 2, "d": 2 },
    { "a": 0, "b": 1, "c": 2, "d": 3 },
    { "a": 1, "b": 1, "c": 1, "d": 1 },
    { "a": 1, "b": 2, "c": 2, "d": 1 },
    { "a": 1, "b": 2, "c": 3, "d": 1 },
    { "a": 2, "b": 2, "c": 2, "d": 2 },
    { "a": 3, "b": 3, "c": 3, "d": 3 }
]
Details
var Model = function Model(a, b, c, d) {

    this.a = a;
    this.b = b;
    this.c = c;
    this.d = d;

    return this;
};

var collection = [
    new Model(3, 3, 3, 3),
    new Model(2, 2, 2, 2),
    new Model(0, 1, 2, 3),
    new Model(0, 1, 2, 2),
    new Model(1, 2, 3, 1),
    new Model(1, 2, 2, 1),
    new Model(0, 0, 0, 0),
    new Model(1, 1, 1, 1),
];

// // 1: Sort by a Single key
function sort(a, b) {
    if (a.a > b.a) return  1;
    if (a.a < b.a) return -1;
    return 0;
}
collection.sort(sort);

// 2: Sort by Multiple keys
function sort$A(a, b) {
    if (a.a > b.a) return  1;
    if (a.a < b.a) return -1;
    return 0;
}
function sort$B(a, b) {
    if (a.b > b.b) return  1;
    if (a.b < b.b) return -1;
    return 0;
}
function sort$C(a, b) {
    if (a.c > b.c) return  1;
    if (a.c < b.c) return -1;
    return 0;
}
function sort$D(a, b) {
    if (a.d > b.d) return  1;
    if (a.d < b.d) return -1;
    return 0;
}
collection.sort(sort$A).sort(sort$B).sort(sort$C).sort(sort$D);

// 3: Sort by Multiple keys (Reusable) using sortByKey()
function sortByKey(k, a, b) {
    if (a[k] > b[k]) return  1;
    if (a[k] < b[k]) return -1;
    return 0;
}
var sort$A = sortByKey.bind(this, 'a')
  , sort$B = sortByKey.bind(this, 'b')
  , sort$C = sortByKey.bind(this, 'c')
  , sort$D = sortByKey.bind(this, 'd')
  ;
collection.sort(sort$A).sort(sort$B).sort(sort$C).sort(sort$D);

// 4: Sort by Multiple keys (Reusable + Optimized) using Methods-Array
function sort(a, b) {
    var i = 0, methods = [ sort$A, sort$B, sort$C, sort$D ];
    while (i === 0 && methods.length) i = methods.shift().call(this, a, b);
    return i;
}
collection.sort(sort);

// 5: Sort by Multiple keys (Reusable + Optimized) using sortByKey() & Keys-Array
function sort(a, b) {
    var i = 0, keys = [ 'a', 'b', 'c', 'd' ];
    while (i === 0 && keys.length) i = sortByKey.call(this, keys.shift(), a, b);
    return i;
}
collection.sort(sort);

// 6: Sort by Multiple keys (Reusable + Optimized) using Reusable prioritySort()
function prioritySort(keys, a, b) {
    var i = 0, keys = Array.prototype.slice.call(keys || [ ], 0);
    while (i === 0 && keys.length) i = sortByKey.call(this, keys.shift(), a, b);
    return i;
}
var sort = prioritySort.bind(collection, [ 'a', 'b', 'c', 'd' ]);
collection.sort(sort);

var before = JSON.stringify(collection, null, '\t');
collection.sort(sort);
var after = JSON.stringify(collection, null, '\t');

console.groupCollapsed("Before");
console.log(before);
console.groupEnd();
//
console.groupCollapsed("After");
console.log(after);
console.groupEnd();

console.log('>', collection);
// >
[
    { "a": 0, "b": 0, "c": 0, "d": 0 },
    { "a": 0, "b": 1, "c": 2, "d": 2 },
    { "a": 0, "b": 1, "c": 2, "d": 3 },
    { "a": 1, "b": 1, "c": 1, "d": 1 },
    { "a": 1, "b": 2, "c": 2, "d": 1 },
    { "a": 1, "b": 2, "c": 3, "d": 1 },
    { "a": 2, "b": 2, "c": 2, "d": 2 },
    { "a": 3, "b": 3, "c": 3, "d": 3 }
]

@mendes5
Copy link

mendes5 commented Aug 29, 2019

Fast prototyping:

html:

<button btn >Test</button>
<canvas x ></canvas>

js:

const button = document.querySelector('[btn]');
const canvas = document.querySelector('[x]');

Logging on arrow functions

Pretty common but didn't see anyone pointing it here

// convert it
const myFunction (a, b) => doStuff(a, b);
// to it
const myFunction (a, b) => console.log('called myFunction') || doStuff(a, b);

Clearing the console screen without calling functions

Object.defineProperty(window, 'clear', { // or `cls` if you want
  get() {
    console.clear();
  }
});

Now just type clear and hit enter. You can do this with pretty much anything actually.

Random item of array:

const myArray = ['a', 'b', 'c', 'd', 'e'];

const randomItem = myArray[Math.random() * myArray.length << 0]; // `0.999 << 0` returns `0`

Key/Value looping (if you use for loops)

const thing = {
  a: 1,
  b: 2,
  c: 3,
};

for(let [key, value] of Object.entries(thing)) {
 console.log(key, value);
}

Safe deep property access:

const safeAccess = (obj, path = []) =>
  obj && path.length
    ? safeAccess(obj[path[0]], path.slice(1))
    : obj;

//Before:
const size = nested 
  && nested.input 
  && nested.input.files
  && nested.input.files[0]
  && nested.input.files[0].meta
  && nested.input.files[0].meta.size;

//Now:
const size = safeAccess(nested, ['input', 'files', 0, 'meta', 'size']);

Operations on the parameter list

const itemAt = (array, index, value = array[index]) => value;

itemAt(['a', 'b', 'c', 1]); // 'b'

Random Proxy hacks:

const it = new Proxy({}, { get(target, name) { return x => x[name] } })
array.map(x => x.propName)
// vs
array.map(it.propName)

const call = new Proxy({}, { get(target, name) { return x => x[name]() } })
fetch(...).then(x => x.json()).then(console.log)
// vs
fetch(...).then(call.json).then(console.log)

const method = new Proxy({}, { get(target, name) { return (...args) => x => x[name](...args) } })
array.forEach(obj => obj.update('A', 1))
// vs
array.forEach(method.update('A', 1))

const eq = new Proxy({}, { get(target, name) { return comp => x => x[name] === comp } })
array.find(item => item.id === 'uuid')
// vs
array.find(eq.id('uuid'))

Im pretty sure that some of this stuff is illegal in some countries...

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