Oleksiy's Blog

JavaScript core singularity

09/17/2015

Having some spare time to play with the concole, so...

Function.constructor === Function; // true

Object.constructor === Function; // true;

Function instanceof Object; // true

Object instanceof Function; // true

Object instanceof Object; // true

Function instanceof Function; // true

Object.getPrototypeOf(Object) instanceof Object; // true

Object.getPrototypeOf(Function.prototype) === Object.prototype; // true

Object.getPrototypeOf(Function).constructor === Function; // true

Object.prototype.constructor === Object; // true

Object.getPrototypeOf(Object.getPrototypeOf(Object)).constructor === Object; // true

Object.getPrototypeOf(Object.getPrototypeOf(Object)).toString(); // "[object Object]" (okay, it's an object...)

Object.getPrototypeOf(Object.getPrototypeOf(Object)) instanceof Object; // false

Object.getPrototypeOf(Object.getPrototypeOf(Object)) instanceof Function; // false

Object.getPrototypeOf(Object).toString() === (function () {}).toString(); // true

Object.getPrototypeOf(Object) instanceof Function; // false

Object.prototype === Object.getPrototypeOf(Object); // false

Object.prototype === Object.getPrototypeOf(Object.getPrototypeOf(Object)); // true

And a less one...

Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(Function.prototype) === Object.getPrototypeOf(Object.getPrototypeOf(Object)))).isPrototypeOf(Object.getPrototypeOf(Object))// true
Tags: javascript, WTF

Enjoying thick-arow lambdas

09/16/2015
const sum = x => x ? y => y ? sum(x+y) : x : x
sum(1)(2)(3)(4)(5)() // 15

Yay!!!

Tags: brainfuck, ES6

Swap variables in JavaScript

07/05/2015

A quite common interview question is how to swap two variables w/o creating a third one for that purpose. That's a good one for checking you understanding of core language concepts, rather than best-practice. I'd prefer using intermediate var, rather than violate comprehension.

Array approach

a = [b][b = a, 0];

or another equivalent one:

a = [b, b = a][0];

The claim of not using a var is right here, but technically we create an inline array object in between which lives while the context's active, which can contain more operational overhead than a simple var using.

Closure approach

a = (function (c) { b = a; return c; }(b));

Here we store the intermediate value in lexical scope instead. That's not the best performer either although.

Bitwise approach

If you're dealing with integers and want to make your colleaugues hate you a little bit more, use this:

x^=(y^(y=x));

Let's zoom in:

a = (a = a ^ b, b = a ^ b, a ^ b);

And more zoom:

a = a ^ b;
b = a ^ b;
a = a ^ b;

This approach is also known as XOR algorithm.

Arithmetic approach:

a = b + (b=a, 0);

This one is type sensitive. For strings it may look like this:

a = b + (b=a, '');

And less one:

b=a+(a=b)-b;

ES6 way

It's just making our live easier:

[a,b] = [b,a];

Return first!

04/22/2015

During AngularJS sourcecode investigation, I took a practice of place return {api} on the top of the revealing module, like here.

That construction can blow the mind of someone who has just come from other programming languages. JSLint does not like that as well. JSHint deals with "latedef": "nofunc" property.

But for those who know well JavaScript and understands how hoisting works, that should not make an issue.

WTF?!! What is this confusion for?

Well, there are some benefits.

Interface Segregation

First you see after opening a file is its interface. You don't need to scroll-down and dive into implementation.

var myModule = (function() {
  // interface first
  return {
    init: init
  };

  // implementation then
  function init (arguments) {
    // body...
  }
}());

State control

If you're writing a stateful module this way, you will need to declare your module state variables on the top, because any other expressions except function declarations won't ever execute. So that you know exactly what state you're working with from the beginning and defend yourself that nothing will brake your code by resetting variable between function declarations underneath:

var myModule = (function() {
  var stateVariable = true;
  return {
    init: init
  };

  function init (arguments) {
    // body...
  }
  // these expressions won't ever executed
  stateVariable = false;
  var x = 123;
}());

You may have experienced side effects of uncontrolled state. That practice can help you keep your instance state more controlled within a module.

Function expressions don't work.

I hate when functions are declared via var, so I see it's beneficial. That is more fragile, less readable and makes callstack be a set of Anonymous functions.

var myModule = (function() {
  var stateVariable = true;
  return {
    init: init // init is returned as undefined
  };

  var init = function (arguments) {
    // body...
  }
}());

Summary

So everything here is about codestyle. It is specific, so be ready for flying crap from your team when taking it into conventions :).


Extending services in AngularJS

04/06/2015

A good way to extend service for child module, is a good alternative for inheritance.

childModule.config(function($provide) {
    $provide. 
      decorator('parentFactory', function($delegate, childFactory) {
        return _.compose(childFactory, $delegate);
      });
  });

$delegate represents returned value of factory that being decorated. This decoration will be available within a paricular childModule. I declared my factories as function returned and used Underscore.js _.compose() method which returns a function which applies function passed through arguments continuously (leftwards) to returned value of previous one. If I had worked with object returned factories, I would probably apply _.extend($delegate, childFactory)

Inheritance vs Decoration

Decoration is not inheritance, since after inheritance you have two instances, and after decoration only one.

That does NOT work if you're going to have more than one extension within a module. That practice restricts you to extract it into separate modules and cause module hierarchy overhead, so consider that in your design.

As a positive thing in that is making you design your application better and disallows you to use super-class directly from child's module by braking the Law of Demeter.

Anyhow, that way you manipulate your dependencies in declarative way on level of configuration, not implementation, which is good!


Working with tree objects in JavaScript

04/04/2015

During recent refactoring of the core of my job project, I became really sad when i found these kinds of piece of... code:

storedData.events[requestData.date] = {};
storedData.events[requestData.date][requestData.categoryId] = {};
storedData.events[requestData.date][requestData.categoryId].data = result;
storedData.events[requestData.date][requestData.categoryId].updated = currentTime;
_deferred.resolve(storedData.events[requestData.date][requestData.categoryId].data);

These kinds of blocks were dispersed throughout the application. The structure of nesting this caching tree was different for different cases, so I came up with idea to create a lean and flexible interface for accessing this object.

So by using TDD, I expected to have a method store() which takes dynamic set of arguments, the last of ones will contain the data. E.g.:

cache.store('events', 'today', 16, ['event1', 'event2']);

should store the data and set the timestamp:

{ events: { 
  today: { 
    16: {
      data: ['event1', 'event2'] ,
      timestamp: 1428089159822
    }
  }
} }

I broke down this task to several simpler ones and defined them as functions: pack() - should produces nested tree object of merge() - should recursively merge from source object to target object dive() - should recursively get the value by provided path

As utility I used UnderscoreJS.

Tests first

Alright, so I based on that wrote the tests:

it('should pack to hierarchical structure', function() {
    expect(priv.pack(['events', 'today', 16, ['event1', 'event2']])).
      toEqual({
        events: {
          today: {
            16: {
              data: ['event1', 'event2'],
              updated: mocks.timestamp
            }
          }
        }
      });
  });

  it('should store events data', function() {
    pub.store('events', 'today', 16, ['event1', 'event2']);
    pub.store('events', 'tomorrow', 150, ['event3', 'event4']);
    pub.store('event', 12345, { name: 'Event 5'});

    expect(pub.storedData.events).
      toEqual({
        today: {
          16: {
            data: ['event1', 'event2'],
            updated: mocks.timestamp
          },
        },
        tomorrow: {
          150: {
            data: ['event3', 'event4'],
            updated: mocks.timestamp
          },
        }
      });

    expect(pub.storedData.event).toEqual({
      12345: {
        data: { name: 'Event 5'},
        updated: mocks.timestamp
      }
    });

  });

Nested object from array

function store () {
  var args   = [].slice.apply(arguments), // to array
      source = pack(args);
  merge(storedData, source);
  return source;
}

// creates hierarchical structure and stores last array element as data
function pack (args) {
  var args = args.slice(0),
      obj = {}, arg = args.splice(0,1)[0];

  obj[arg] = args.length > 0 ? pack(args) : undefined;
  return obj[arg] ? obj : new Cached(arg);
}

Deep Merge

function merge (target, source) {
  _.each(_.keys(source), function (key) {
    target[key] = source[key] instanceof Cached ?
      source[key] : target[key] || source[key]; // change if endpoint otherwise choose an existing
    merge(target[key], source[key]);
  });
}

I also created a constructor of cached object to distinguish it in setting and getting:

function Cached (data) {
  _.extend(this, {
    data: data,
    updated: timeFactory.getCurrentTime()
  });
}

For accessing the database i needed a stored() method which recursively travels by object by path given in arguments. This function was slightly simpler to implement.

So I created dive() function and left the business stuff in facade stored() to make it syntactically sweeter.

function stored () {
  var args   = [].slice.apply(arguments),
      cached = dive(args, storedData);
  return cached && cached instanceof Cached ?
    cached.data : undefined;
}

function dive (args, obj) {
  var args = args.slice(0),
      key  = args.shift();
  return !obj ? undefined :
    args.length > 0 ?
      dive(args, obj[key]) : obj[key];
}

Then I added more tests:

  it('should set and get data from/to cache', function() {
    pub.store('events', 'today', 16, ['event1', 'event2']);
    pub.store('events', 'tomorrow', 52, ['event3', 'event4']);

    expect(pub.stored('events', 'today', 16)).
      toEqual(['event1', 'event2']);

    expect(pub.stored('events', 'tomorrow', 52)).
      toEqual(['event3', 'event4']);

    expect(pub.stored('events', 'live', 10)).
      toBeUndefined();

    expect(pub.stored('some', 'invalid', 'path')).
      toBeUndefined();
  });

And this is really helpful thinking in TDD. While hacking my module, I realized some cases that my algorithm didn't do because of silly mistakes. Like this one:

  it('should override existing data', function() {
    pub.store('event', 100, {name: 'old data'});
    pub.store('event', 100, {name: 'new data'});
    pub.store('event', 101, {name: 'other data'});
    expect(pub.stored('event', 100).name).toEqual('new data');
    expect(pub.stored('event', 101).name).toEqual('other data');
  });

In passion of syntactic perfection and optimization, I missed the basic thing: events had not been updating by store() function. Though UT helped me out, as always, I resolved that by adding instance checking merge() function.

Now after adding Cached() constructor it works as just fine.

Although, big refactoring is still in progress...


Lovhate Codestyle

10/28/2014

I love:

  • Functional programming
  • Tiny self-described atomic functions
  • Declarative way of doing things instead of direct calling functions
  • ?: ternary operators, if it's reasonable
  • Singletons
  • Flat and concise constructions
  • Modular decomposition

I HATE:

  • Large functions: 10+ lines of code are cumbersome, 20 and more -- are frightening!
  • Long and nested constructions, aka if/else aka switch/case aka nested functions in closure or whatever. I would cut hands off for that.
  • if/else is evil, switch/case is even worse, btw.
  • Poor organized code. E.g. doing everything on controllers, smart templates, etc.
  • Doing something just for meeting the deadline, sacrificing quality
  • //TODO: somebody will refactor this crap i've done here in better time, after i release this and become a manager
  • // I made so much efforts to write it, I can't just remove it now, so I'll comment it out

Password Strength directive for AngularJS

10/28/2014

Have just written yet another tool password strength checker.

Module:

angular.module('myApp.strengthPassword', [])
    .directive('myPasswordStrength', ['passwordStrengthService',
        function (service) {

            function updateValues (password, scope) {
                password            = password || '';
                scope.lengthLevel   = service.getLengthLevel(password);
                scope.strengthLevel = service.getStrengthLevel(password);
                scope.strengthLabel = service.getLabel(scope.strengthLevel);
            }

            function link (scope) {
                scope.$watch('password', function(password) {
                    updateValues(password, scope);
                });
            }

            return {
                restrict: 'EA',
                replace: true,
                scope: { password: '=' },
                templateUrl: 'directives/strengthpassword/strengthpassword.tpl.html',
                link: link
            };
    }])

    .factory('passwordStrengthService', ['passwordStrengthConstants',
        function (constant) {
            var _matchPatterns  = constant.patterns;
            var _maxLengthLevel = constant.maxLengthLevel;

            function _getStrengthLevel (password) {
                for(var level in _matchPatterns) {
                    if (_matchPatterns[level].test(password)) { return level; }
                }
            }

            function _getLengthLevel (password) {
                var level = password.length / _maxLengthLevel * 100;
                return level < 100 ? level : 100;
            }

            function _getLabel (level) {
                return constant.labels[level];
            }

            return {
                getStrengthLevel    : _getStrengthLevel,
                getLengthLevel      : _getLengthLevel,
                getLabel            : _getLabel
            };
        }])

    .constant('passwordStrengthConstants', {
        patterns : {
            empty   : /^$/i,                                                   // not looping if empty
            strong  : /^.*(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W).*$/, // 8+ sym, small+capital, digits, alpha
            medium  : /^.*(?=.{6,})(?=.*[a-z])(?=.*[\d\W]).*$/i,               // 6+ sym letters, digits
            weak    : /^.*(?=.{6,})(?=.*[a-z\d]).*$/i,                         // 6+ letters or digits
            useless : /^.*$/i                                                  // anything other
        },

        labels: {
            empty   : '',
            strong  : 'Good password!',
            medium  : 'Password is acceptable, but you could better',
            weak    : 'Your password is a piece of crap',
            useless : 'Password is too short'
        },

        maxLengthLevel : 20
    });

Template:

<div class="password-strength">
    <div class="password-strength-label">
        {{strengthLabel || 'js.passwordStrength'}}
    </div>
    <div class="bar-container">
        <div class="bar {{strengthLevel}}" style="width: {{lengthLevel}}%"></div>
    </div>
</div>

HTML:

<input type="password" name="password" id="password" ng-model="password" />
<div my-password-strength password="password"></div>

LESS/SASS:

.password-strength {
  margin-bottom: 10px;

  .bar-container {
    background: #eee;
    margin-bottom: 10px;

    .password-strength-label {
      margin-bottom: 5px;
    }

    .bar {
      height: 5px;
      -ms-transition:     width .5s ease;
      -webkit-transition: width .5s ease;
      transition:         width .5s ease;

      &.strong  { background: #008641; }
      &.medium  { background: #2573d9; }
      &.weak    { background: #f60; }
      &.useless { background: #e51400; }
    }
  }
}

Hello World!

10/28/2014

Hello World is the first thing developers print out using something new. So this writing this in my blog won't be an exception of my helloworldish way of exploring anything new.

Hello dear World! Lorem Ipsum to you! :-)

Tags: Hello World!