OK, OK, probably is just that I cannot wait to start writing stuff with [tinydown](https://github.com/WebReflection/tinydown#tinydown) but I tweeted about this after last #FlightNight and @angustweets demo ... so here what is behind [Flight](http://twitter.github.io/flight/) mixins choice.
### The Basics
JavaScript polymorphism is probably one of the best things you can find out there.
Not kidding, the flexibility that this language offers when it comes to context injection and runtime class definition is simply amazing, as simple, and amazing, is this idea:
```js
// most basic example
function enriched() {
this.method = function () {
// do stuff
};
}
```
Most common books and online documents usually describe above example as a _constructor with privileged methods_.
Well, that's actually what you get if you `var obj = new enriched();` but that's just one story.
Flight uses a different story, offering alternative methods with better semantics but basically going down to:
```js
enriched.call(object);
```
### Mixins Baby!
Using above pattern we can enrich any sort of object with the extra benefit of having a private scope the moment we invoke once the function.
This gives us the opportunity to pass arguments or simply have some private, shared in case of a prototype, variable too.
```js
// with arguments and private variables
var Mixin = function Mixin(arg0, argN) {
// private variables
var scoped = {};
// privileged methods
this.method = function method() {
return scoped;
};
// default properties or initialization
this.prop = arg0 || 'default';
this.other = argN;
};
// ========================================
// as Singleton
var singleton = new Mixin;
singleton.method(); // object
singleton.prop; // default
singleton.other; // undefined
// as prototype with defaults
function Class() {}
Mixin.call(Class.prototype, 'a', 'b');
var instance1 = new Class,
instance2 = new Class;
instance1.method(); // object
instance2.method(); // same object
// same methods
instance1.method === instance2.method; // true
// and same object
instance1.method() === instance2.method(); // true
instance1.prop; // a
instance1.other; // b
instance2.prop; // a
instance2.other; // b
```
I have realized how powerful is this simply considering the same approach with prototypes rather than each objects, where methods are of course created per each invokation of the mixin, but that would be indeed absolutely meant and expected.
What I am saying, is that if you are worried about too many closures and functions generated per each mixin, and you believe your mixin does not need any initialization and methods can be used anywhere without needing a private scope, here all you can do to follow same pattern and save a bit of memory:
```js
var Mixin = function(){
// created once and never again
function method1(){}
function method2(){}
function methodN(){}
return function () {
this.method1 = method1;
this.method2 = method2;
this.methodN = methodN;
};
}();
```
I guess that's it, right? But what if we need some sort of initialization per each mixin?
### Initializing A Mixing
There could be things we need to do to ensure the mixin will work as expected per each instance but if we want to coexist out there in the wild, we cannot name methods like `.init()` because of the name clashing if more than a mixin needs to be initialized ... are you following?
One possible solution that came into my mind is to prefix, with `init` the method, and use the mixin name as suffix.
```js
// defaults plus init
var Mixin = function Mixin(dflt0, dfltN) {
// private variables
var scoped = {};
// privileged methods
this.method = function method() {
return scoped;
};
// avoid multiple mixins name clashing
// prefix eventual initialization
// with 'init' plus mixinname
this.initMixin = function (arg0, argN) {
this.prop = arg0 || dflt0 || 'default';
this.other = argN || dfltN;
};
};
```
If we follow this approach, we can initialize any mixin we want at any time, e.g.:
```js
// explicit initialization
function Class(arg0, argN) {
this.initMixin(arg0, argN);
}
Mixin.call(Class.prototype, 'a', 'b');
var instance1 = new Class,
instance2 = new Class('different');
instance1.prop; // a
instance2.prop; // different
instance1.other; // b
instance2.other; // b
```
Per each instance we can then enrich the constructor so that every mixin that needs to be initialized at that time can be simply call the non clashing method.
#### Some Bad Idea You might Have
Well, it is common in JS to think about `for/in` loops and stuff so that if we know a prefix we can automate tasks ... but in this case I strongly discourage this approach unless you are not 100% sure all mixins initializations support same signature.
```js
// *DONT* automatic mixin initialization
function Class() {
for (var key in this) {
if (key.slice(0, 4) === 'init') {
this[key]();
// or
this[key].apply(this, arguments);
}
}
}
```
In few words, using above technique means coupling mixins with a specific, probably unknown in advance, class signature so it is strongly discouraged.
Sticking with an explicit mixin initialization is not only faster but able to create any sort of mixin signature.
### Events To The Rescue
As @kpk reminds me, [Flight is event based](https://twitter.com/kpk/status/323272363053551616) so there's also an easy way to do more after all mixins initialization: `this.after('initialize', fn);`
### As Summary
This is only one part of [Flight](http://twitter.github.io/flight/) where [**performance**](http://jsperf.com/mixin-fun/31) were strongly considered for all old and new browsers and this works.
In an era were many developers are looking for better classes this framework came out with such simple and powerful solution I can't believe I would like to have anything more than this for real apps!
Enjoy the Flight philosophy and embrace powerful simplicity any time you _A-HA_ it ;)
behind the design
looking for a full-immersion/face-to-face
HTML5, JavaScript, and Mobile Web Development training in the heart of London?
Book your spot
Showing posts with label performance. Show all posts
Showing posts with label performance. Show all posts
Sunday, April 14, 2013
Flight Mixins Are Awesome!
Saturday, March 30, 2013
Yet Another Reason To Drop __proto__
I know it might sound boring but I really want to put everything down and laugh, or cry harder, the day TC39 will realize
I've already mentioned this in the 5 Reasons You Should Avoid __proto__ post but I forgot to include an example.
You can test all this code with Chrome Canary or Firefox/Nightly and the most basic thing you need to know is this:
In few words, I believe you don't want to fear security and logic problems every single time you set a property to a generic object ... am I correct?
Now imagine some library such underscore.js, has the most common and generic way to create an object from another one, copying properties ...
This is nothing an explicit
It must be said some engine makes that
I haven't been able to reason against them regardless examples and reasons ... but you could have fun trying too before it's too late!
__proto__ was one of the most terrible mistakes.A Simple Dictionary Attack
ES6 says thatObject.create(null) should not be affected anyhow from Object.prototype.I've already mentioned this in the 5 Reasons You Should Avoid __proto__ post but I forgot to include an example.
You can test all this code with Chrome Canary or Firefox/Nightly and the most basic thing you need to know is this:
var n = Object.create(null);
n.__proto__ = {};
for (var k in n) console.log(k); // __proto__ !!!
Object.keys(n); // ["__proto__"] !!!
Got it? So, __proto__ is enumerable in some browser, is not in some other but it will be in all future browsers. Let's go on with examples ...
// store values grouped by same key
function hanldeList(key, value) {
if (!(key in n)) {
n[key] = [];
}
n[key].push(value);
}
// the Dictionary as it is in ES6
var n = Object.create(null);
Above code simply does not need to be aware of any problems except in older environment that won't work as expected. If the key is __proto__ instead of storing the value there will be most likely an error or the object will inherit from an empty array the moment n[key] = [] will be executed.In few words, I believe you don't want to fear security and logic problems every single time you set a property to a generic object ... am I correct?
Now imagine some library such underscore.js, has the most common and generic way to create an object from another one, copying properties ...
function copy(obj) {
var result = {}, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = obj[key];
}
}
return result;
}
// or if you want ...
function extend(a, b) {
for (var key in b) {
if (b.hasOwnProperty(key)) {
a[key] = b[key];
}
}
return a;
}
Now guess what happens if you would like to copy or extend that list we had before, where __proto__ will be own property for the n variable and the loop is not checking the key as it should ... the object a, or the new one, will automatically extend an Array and break completely its own expected behaviors ^_^This is nothing an explicit
Object.setPrototypeOf() could cause ... moreover...Real World Performance Impact
Every utility such lo-dash or underscore should now do this kind of check per each loop if these would like to be considered safe:
function copy(obj) {
var result = {}, key;
for (key in obj) {
if (
obj.hasOwnProperty(key) &&
key !== '__proto__'
) {
result[key] = obj[key];
}
}
return result;
}
Now try to investigate in your real-world daily code how many times you change __proto__ compared with how many times you loop over properties ... I give you a test case to compare performance and remember: mobile matters!Really Hard To Debug
Being a special property in theObject.prototype and not just a function you could wrap and keep under control, in a new scenario where any object could be instanceof anything at any time, the inability to intercept __proto__ calls and changes before it happens will be a painful experience in terms of debugging ... what was that instance before? Most likely, you'll never know ^_^It must be said some engine makes that
descriptor.setter reusable but this is not the case of current V8, as example, neither the case for all mobile browsers out there today.A Stubborn Decision
What's driving me crazy about this property and all problems it brings, is that regardless there is a possible "speccable"Object.setPrototypeOf() alternative that would not suffer from anything I've described in all these posts, and just as reminder there is already a spec'd and widely available Object.getPrototypeOf() in ES5, TC39 will go on and make the problem a standardized one ^_^I haven't been able to reason against them regardless examples and reasons ... but you could have fun trying too before it's too late!
Friday, March 29, 2013
Simulating ES6 Symbols In ES5
Symbols, previously known as Names, are a new way to add real private properties to a generic object.
In any case it looks like private symbols will be a better way to go than WeakMap when all we would like to have is a private property. Symbols can be used as Enums too, being unique as any other object is.
Bear in mind, regardless being a hack, this script does not actually cause any problem to any other script or library you are using today but it needs ES5 compatible browsers such all mobiles plus all desktops and IE9 or greater.
// basic Symbol example
var BehindTheScene = (function(){
var symbol = new Symbol;
function BehindTheScene(){
this[symbol] = {};
}
BehindTheScene.prototype.get = function(k) {
return this[symbol][k];
};
BehindTheScene.prototype.set = function(k, v) {
return this[symbol][k] = v;
};
return BehindTheScene;
}());
var obj = new BehindTheScene;
obj.set('key', 123);
obj.key; // undefined
obj.get('key'); // 123
In few words symbol makes possible to attach properties directly without passing through a WeakMap. A similar behavior could be obtained indeed via WeakMaps:
// similar WeakMap example
var BehindTheScene = (function(){
var wm = new WeakMap;
function BehindTheScene(){
wm.set(this, {});
}
BehindTheScene.prototype.get = function(k) {
return wm.get(this)[k];
};
BehindTheScene.prototype.set = function(k, v) {
return wm.get(this)[k] = v;
};
return BehindTheScene;
}());
var obj = new BehindTheScene;
obj.set('key', 123);
obj.key; // undefined
obj.get('key'); // 123
Why Symbols
To be honest I am not sure but these somehow bring some magic to the object rather than wrapping magic around it, as it is for the WeakMap example, so at least performance should be better ... right? Well, the current shim VS shim says thatindexOf() is faster than an implicit toString(): check this test out by yourself ;)In any case it looks like private symbols will be a better way to go than WeakMap when all we would like to have is a private property. Symbols can be used as Enums too, being unique as any other object is.
Simulating Symbols In Current ES5 JavaScript
As easy as this:
var Symbol;
if (!Symbol) {
Symbol = (function(Object){
// (C) WebReflection Mit Style License
var ObjectPrototype = Object.prototype,
defineProperty = Object.defineProperty,
prefix = '__simbol' + Math.random() + '__',
id = 0;
function get(){/*avoid set w/out get prob*/}
function Symbol() {
var __symbol__ = prefix + id++;
defineProperty(
ObjectPrototype,
this._ = __symbol__,
{
enumerable: false,
configurable: false,
get: get, // undefined
set: function (value) {
defineProperty(this, __symbol__, {
enumerable: false,
configurable: true,
writable: true,
value: value
});
}
}
);
}
defineProperty(Symbol.prototype, 'toString', {
enumerable: false,
configurable: false,
writable: false,
value: function toString() {
return this._;
}
});
return Symbol;
}(Object));
}
A very basic example here:
var sym = new Symbol;
var o = {};
o[sym]; // undefined
o[sym] = 123;
console.log(o[sym]); // 123
for (var k in o) {
console.log(k); // nothing at all
// there is nothing to for/in
}
delete o[sym]; // true
Of course, you can try also the very first example, the one with a shared, private, symbol variable, that will simply work as expected :)Bear in mind, regardless being a hack, this script does not actually cause any problem to any other script or library you are using today but it needs ES5 compatible browsers such all mobiles plus all desktops and IE9 or greater.
Tuesday, March 26, 2013
5 Reasons You Should Avoid __proto__
Update: when you've done with this post, there's even more in comments and the newer one: Yet Another Reason To Drop __proto__
Too many discussions without real outcome about
TC39 refused to standardize this property because of the amount of problems it brings. Apparently will be part of ES6 but is not there yet.
As example, try this in some environment:
Having a property configurable means you cannot trust it's going to work because anyone could have decided to remove it ... why ...
Using
The extra silent agreement here is that
Bad news is: you cannot redefine
Polymorphism has always been possible through mixins and borrowed methods but again, no way an object could suddenly be any sort of instance with such lightweight casting unable to ensure any desired behavior.
What I mean, is that using
This is different from
Here some advantage:
Too many discussions without real outcome about
__proto__ magic evilness or feature. It's time to understand why using it is, today, a bad idea.__proto__ Is NOT Standard (yet)
__proto__ is a silent, non spec'd, agreement. What's the problem? Keep reading ;)__proto__ Could NOT Be There
The silent non standard agreement sees__proto__ as configurable property of the Object.prototype.As example, try this in some environment:
(this.alert || console.warn)( delete Object.prototype.__proto__ ); // false or true ?The outcome is migrating from
false to true. As example, current Chrome has a non configurable descriptor, while Canary has a configurable one. Same is for latest node.js, Firefox, and who know who else.Having a property configurable means you cannot trust it's going to work because anyone could have decided to remove it ... why ...
__proto__ Makes null Objects Unpredictables
Theoretically, this is all you need to create one or more objects that inherits fromnull
var Dict = Object.create.bind(Object, null);
var dictionary = Dict();
dictionary[property] = 1;
if (otherProperty in dictionary) {
// do stuff
}
// or
if (dictionary[someOtherThing]) {
// do stuff
}
We cannot trust, as example in Chrome, that any property can be set there because if for some reason the property name is __proto__, that object inheriting null will completely be unusable/screwed.Using
hasOwnPropertyDescriptor() is not even an option since objects that inherit from null do not inherit these methods from Object.prototype.The extra silent agreement here is that
Object.create(null) should return objects that are not affected anyhow by any property from Object.prototype and __proto__ ain't any exception!__proto__ Is NOT Secure
Since any bloody object could be modified directly or deeply anywhere in the middle of its prototypal chain, you can consider all your instances somehow exposed to any sort of attack.Bad news is: you cannot redefine
__proto__ to prevent this, at least you cannot in current version of Chrome and mobile browsers:
function ProtoSafe() {}
Object.defineProperty(
ProtoSafe.prototype,
'__proto__',
{
get: function () {
return ProtoSafe.prototype;
},
set: function () {
throw 'immutable';
}
}
);
Error: cannot redefine property __proto__
__proto__ Influences Your Logic
This is last point but actually still important. In ES3 it has never been possible to redefine inheritance over an already created instance and this has never been a real problem.Polymorphism has always been possible through mixins and borrowed methods but again, no way an object could suddenly be any sort of instance with such lightweight casting unable to ensure any desired behavior.
What I mean, is that using
[].slice.call(arguments) has a meaning: if there is a length in the used object, create an array with indexes filled from 0 to that length - 1.This is different from
generic.__proto__ = Array.prototype; because the length could be missing and the resulted object behavior be unexpected, broken, or again unpredictable.Still A Cheap Way To Cast
This is the only advantage and the reason some library adopted__proto__ without even thinking about it: performance boost, compared to a whole slice, are a win, and specially in mobile and DOM libraries where results are always threat as ArrayLike objects.Object.setPrototypeOf(object, proto) To The Rescue!
In ES5 allObject things are managed through the Object constructor so why not having a method in charge of the __proto__ behavior, since Object.getPrototypeOf(object) is already available?Here some advantage:
- no way a property can destroy an object, the
obj[propName]check againstpropName !== '__proto__'won't be needed anymore: performance! - cheap casting still available so not a performance issue
- standardizing
Object.setPrototypeOf(object, proto)can bring new possibilities suchObject.freezePrototype(object)in order to ensure immutable inheritance when and if needed
A Cheaper Example
If you want to ensure TC39 will ever consider to drop this property in favor of better methods in theObject, here what you should stick in your library that is using proto:
var setPrototypeOf = Object.setPrototypeOf || function(o, p){
o.__proto__ = p;
return o;
};
It's cheap and performance, again, are as good as before!
Friday, December 28, 2012
A Cross Platform Inherit Function
This (apparently non working) gist gave me the hint. Stuff I've been dealing with for a while, finally used to bring an
Object.create(firstArgOnly) cross platform/engine/client/server code that works. The name? inherit()More Reliable Than Object.create()
The reason I didn't even try to polyfill the ES5Object.create() method is quite easy: it is not possible to shim it in a cross platform way due second argument which requires descriptors features, highly improbable to simulate properly.
Even if browsers support the create() method, inherit() guarantee that no second argument will ever be used so we are safe from inconsistencies within the function.
Forget hasOwnProperty !
Yeah, one of the coolest things about being able to inherit from null is the fact not evenObject.prototype is inherited so we can create real empty objects without worrying about surrounding environment, 3rd parts obtrusive libraries, and the boring and slow obj.hasOwnProperty(key) check.
// some obtrusive code
Object.prototype.troll = function (up) {
throw up;
};
// empty object in every browser/env
var dict = inherit(null);
dict.anyKey = anyValue;
// later on ...
for (var key in dict) {
// only 'anyKey'
}
That's correct, objects that inherit from null are not affected by the Object.prototype ... really, we cannot even print them without defining a toString method!
Update: On IE DontEnum Bug
Unfortunately the fact IE does not enumeratetoString and other native Object.prototype names is not solved here for the simple reason here we are not solving that problem, here we are solving inheritance. However,I think is a must know that even objects created via this function needs an extra loop or something like this:Not Only Null
This function should just work with anything we might need to inherit and we can also inherit from inheriting objects without problems. Consider this an end of the year tiny present just to remind some basic concept about JS that is still valid: Objects inherit from Objects and that's pretty much it :) Enjoy and see you next year!Wednesday, November 28, 2012
My Name Is Bound, Method Bound ...
it seems to me the most obvious thing ever but I keep finding here and there these common anti pattern:
// 1. The timer Case this.timer = setTimeout( this.doStuff.bind(this), 500 ); // 2. The Listener Case (objOrEl || this).addEventListener( type, this.method.bind(this), false );
What Is Wrong
I have explained a while ago what's wrong and how to improve these cases but I understand the code was too scary and the post was too long so here the summary:- every
setTimeout()call will create a new bound object and this is both redundant and inefficient plus it's not GC friendly - there is no way to retrieve that listener created inline so it's impossible to remove the listener any time is necessary ... yes, even after, when you do refactoring 'cause you will need to clean up listeners
What You Need
The short version is less than a tweet, 64bytes:function b(o,s,t){return(t=this)[s="@"+o]||(t[s]=t[o].bind(t))}
This is the equivalent of:
// as generic prototype method
function bound(methodName) {
var boundName = "__bound__" + methodName;
return this[boundName] || (
this[boundName] = this[methodName].bind(this)
);
}
// as generic utility
function bound(object, methodName) {
var boundName = "__bound__" + methodName;
return object[boundName] || (
object[boundName] = object[methodName].bind(object)
);
}
// as stand alone dependencies free prototype method
var bound = function(){
function bound(methodName) {
var boundName = uniqueId + methodName;
return this[boundName] || (
this[boundName] = bind.call(this[methodName], this)
);
}
var
uniqueId = "__bound__", // + Math.random(),
bind = bound.bind || function bind(self) {
var callback = this;
return function bound() {
return callback.apply(self, arguments);
};
}
;
return bound;
}();
// really ... you can write
// this little thing in many ways
Pick One And Use It !
These are benefits over the simple, ultra fast, performance oriented, and memory safe approach:
// 1. The timer Case
this.timer = setTimeout(
this.bound("doStuff"), 500
);
// 2. The Listener Case
(objOrEl || this).addEventListener(
type, this.bound("method"), false
);
- every
setTimeout()call, if any, will create one single bound object - you can remove the listener at any time through the same call, i.e.
(objOrEl || this).removeEventListener(type, this.bound("method"), false);
Is That It ?
You are free to over complicate this concept as much as you want as long as you got the point: there's no need to create a new bound Object per each call plus your life will be much easier following this pattern focusing on logic rather than possible typos, boring variable assignments, etc etc ... this works and it's what you need and what you want now. I'm also moving my hands as a Jedi so I hope I've convinced you!
Subscribe to:
Posts (Atom)