#JavaScript Patterns
Project page at: http://shichuan.github.io/javascript-patterns
JavaScript Design Patterns
Home Page: http://shichuan.github.io/javascript-patterns
#JavaScript Patterns
} else { // older browsers
utils.addListner = function (el, type, fn) {
should be:
utils.addListener
I think it just needs a bit of documentation that elem
is a DOM element, not a jQuery object. Also it should be noted that using jQuery.data(domElem, "key")
will not pull in the HTML5 data-* attribute data-key="value"
like calling jQuery(domElem).data("key")
would.
Here's an example showing how they fail:
http://jsbin.com/exapef/1/edit
Hello everybody,
This repository seems to be inactive for a quite long time. It has 20 open issues and 39 Pull Requests. That's why I create a new github organization to fork and maintain this repository.
Here is it: https://github.com/javascript-patterns/javascript-patterns
If you want to maintain this repository, please let know by leaving comment on this issue.
Thanks.
var myFunc = function (param) {
if (!myFunc.cache[param]) {
var result = {};
// ... expsensive operation ...
myFunc.cache[param] = result;
}
return myFunc.cache[param];
};
If param is e.g. "toString"
this will cause problems.
({})['toString'] // function toString() { [native code] }
The solution is to use hasOwnProperty
.
event-delegation.html
// .live() - best used for simple scenario
Since 1.9, there is no .live() method in jQuery
Hi guys. I've watched all of yours topics about patterns and antipatterns. Nice job! But, I have comments and questions for some topics. I think, some of your patterns is not good. So let's check.
regular-expression-literal.html
Using RegExp constructor can't be antipattern because sometimes we need to create regular expressions dynamically with some input data. For example:
//I know what this example is trivial and not good but it's only for example function hasClass(element, className){ var regular = new RegExp('(^|\\s)' + className + '(\\s|$)', 'g'); return regular.test(element.className); }
enforcing-new.html
Let's be more logical. If I write functionName()
I want to call some function. If I write new FunctionName()
I want to create some object. Using your pattern I can create new object even when I call function. But for what? Because we can save 4 symbols and it can minimize file size? Huh, it make me laugh. I think logic of code is more important than file size.
avoiding-implied-typecasting.html
I think, one of antipattern in JavaScript is comparison with true/false/null/undefined. Always we can avoid this comparison using next construction:
var zero = false, n = null; if(!zero){ //instead of zero === false } if(!some){ //instead of some === undefined or typeof some === 'undefined' } if(!n){ //instead of n === null }
for-loops.html
http://jsperf.com/for-loop-caching As you can see there is no difference. And when we cache array size we create new variable. I think it's not useful variable.
for-in-loops.html
For the last example. Why I should save link to Object.prototype.hasOwnProperty when all objects are have this method?
function-declarations.html
This topic is real antipattern. Why I can't use simple function declaration?
The difference between function someFunc(){}
and var someFunc = function(){}
is the moment when they are created. Simple function declaration will create function before script executing. Declaration function like new variable will create function when script will be working. And all of this functions will be local. So which variant is antipattern? But, simple function declaration can be used only in global scope or first IIFE. Otherwise local function will be created in advance even if you don't call the desired function.
conditionals.html
I think, construction bool && boo()
is not logical because it's not expression, it's condition. And condition can't be used like expression.
if (({foo:1, bar:1})[type]) {}
Create new object for one condition? WTF?
revelation.html and module.html
Why you use comparison object with "[object Array]" to indicate arrays when you can use object instanceof Array
or object.constructor === Array
.
klass.html
Classes in JavaScript... Again...
Why people can't understand prototypal-based programming and use it instead of this ugly classes? Why all prefer to use classical OOP?
First of all, classes are data types. In JavaScript we work with objects and we have only some primitive types like: number, string, boolean, function. We can't create our personal type. We can create some objects with the same properties.
Secondly, classes unites data and method to work with this data. Constructors in JavaScript do this too. Classical OOP was complicated by a variety of ways to create a class. And, when we create arcitecture of our application one of the main problem can be "Oh, in this class I can use virtual method. Or I should use composite pattern? Hmm...."
"There should be one — and preferably only one — obvious way to do it." (The Zen of Python)
In JavaScript we have only one way to describe objects. We create a function which will be a constructor. Then we can add some properties to prototype object (which placed in our constructor). All properties in prototype are common to all instances of our constructor. That's all. It's realy easy.
I hope you will read all this comments and understand my engilsh :)
Best regards,
Alexey Raspopov
define scareMe is function ,
when the prank = scareMe ,
i think the function 's mem-address-value copy to prank.prototype , is not a handle ,so the function run again not change???
Here you mention that function declarations are an anti-pattern. However you don't substantiate this. Do you say this because FunctionDeclaration hoisting is sometimes considered confusing?
I don't believe Function Declarations are an anti-pattern at all. In fact they're favourable in many cases --
The last example on literals-and-constructors/primitive-wrappers.html is commented incorrectly:
// primitive string
var greet = new String("Hello there");
// primitive is converted to an object
// in order to use the split() method
greet.split(' ')[0]; // "Hello"
// attemting to augment a primitive is not an error
greet.smile = true;
// but it doesn't actually work
console.log(typeof greet.smile); // "boolean"
It should be:
// string with wrapper
var greet = new String("Hello there");
// object has split() method
greet.split(' ')[0]; // "Hello"
// augmenting object
greet.smile = true;
console.log(typeof greet.smile); // "boolean"
Is there an "official" spanish translation of this repo?
Sent via Hubroid
I've come up with a really good convention for naming methods:
person.getData = function person_getData() {
};
We prepend with person_
so that the function name is unique from the identifier, avoiding errors in IE.
It also tells us EXACTLY what function we're dealing with in a stack trace.
@shichuan probably best to let you update the codebase with this new convention; if you approve. For a javascript error dashboard this will prove rather useful
In explanations for certain patterns, other anti-patterns are often used. I.E. in the explanation code for the "Single var pattern", the patterns for "Function Declarations" and "Access to the Global Object" are both ignored:
function updateElement() {
var el = document.getElementById("result")
, style = el.style;
// do something with el and style...
}
Shouldn't all patterns be used consistently, with only changing the focus example by example?
You say
substitute
i++
withi = i + 1
ori += 1
to avoid excessive trickiness
So why not substituting i--
with i = i -1
or i -= 1
in the 2 preferred methods ?
There are some wrong comments in this page, for example:
// but it doesn't actually work
console.log(typeof greet.smile); // "boolean"
is somewhat "wrong", I wouldn't nitpick but this is supposed to be about best practices :p
Anyway, it mentions that the typeof
check is better, which it's really not, you're doing little more than the example
above it, if anything you should do 'function' == typeof
in that case, but even then I wouldn't call that best practice
unless you're paranoid
On line 35 of the for-loop pattern the following comment appears.
// optimization 3 - substitute
i++with
i = i + 1 or
i += 1 to avoid excessive trickiness
Could you elaborate on "excessive trickiness"?
Why do we use
var MYAPP = MYAPP || {};
and not a singleton pattern?
The whole point of not doing much in the scroll event handler is because it degrades performance, but there's no reason to have a constant timer running. You should be running it only when the user starts scrolling:
var scrollTimer;
$(window).scroll(function() {
scrollTimer && clearTimeout(scrollTimer);
scrollTimer = setTimeout(function() {
// Check your page position and then
// Load in more results
// Whatever else...
}, 250);
});
On https://github.com/shichuan/javascript-patterns/blob/master/jquery-patterns/append.html there's a slight consistency error with your other patterns. It is recomended to use array.push() and then join it instead of appending string over and over
So, instead of
var myhtml = '';
$.each(reallyLongArray, function (count, item) {
myhtml += '<li>' + item + '</li>';
});
$('#ballers').html(myhtml);
Should be
var myHtml = [];
$.each(reallyLongArray, function(count, item) {
myHtml.push('<li>' + item + '</li>');
});
$('#ballers').html(myHtml.join(''));
regarding https://github.com/shichuan/javascript-patterns/blob/master/jquery-patterns/context-and-find.html
According to http://api.jquery.com/find/, jquery implements selector context with the .find function. So either of the methods are equally valid, and none of them are antipatterns.
The link supplied as documentation (http://paulirish.com/2009/perf/) mentions the same fact, and infact states at 12:18 "there no performance gain over doing that, versus the second one [method]"
Using find over context is purely a matter of readability and the preference of the developer.
You have too many issues and they seem to be piling up. Maintainers are awesome -- they can merge in reasonable PRs, etc. This site has too many views for it not to be maintained.
switch pattern case
statements are indented.
expect to be aligned with switch
declaration.
* 1. Aligning each `case` with `switch`
...
switch (inspect_me) {
case 0:
result = "zero";
It is kind of unclear why counting down and while (https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/for-loops.html) are preferred patterns, because modern browsers preoptimize these constructs. Maybe it will be a good idea to include some jsperf test, for example http://jsperf.com/for-vs-foreach/219.
The sample for jQuery selector cache, "using selector cache to avoid requery" is a little misleading; in the following code example, although the .photo element could be cached, if the user never clicks the list item, the .photo query will never happen. A better example would be with a window scroll event, like the reference suggests.
// antipattern
$('.list-item').click(function () {
$('.photo').hide();
});
// preferred
var photo = $('.photo');
$('.list-item').click(function () {
photo.hide();
});
https://github.com/shichuan/javascript-patterns/blob/master/jquery-patterns/append.html#L23
I think this line:
var newLI = '<li>' + item + '</li>';
should be like this:
var newLI = $('<li>' + item + '</li>');
seems it is only kind of trivil skill,
https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/function-declarations.html
// named function expression
/* Benefits:
* 1. Provides the debugger with an explicit function name: helps stack inspection.
* 2. Allows recursive functions: getData can call itself.
* Issues:
* 1. there are historic quirks with IE
*/
var getData = function getData () {
};
This is very bad idea. We have already possibility for recursion in previous both examples.
While all functions (absolutly annonimus also) can call itself using arguments.callee.
For Example:
var some = function(a){
if(a == 0 || a == 1)
return 1;
var t = arguments.callee;
return t(a-1) + t(a-2);
}
alert(some(5));
Beautiful work!
I wish some of the pattern examples had explanations or links to references. For example, in global_selector.js, it would be helpful to see an explanation for why one expression is better than another. Is our optimization criteria for this case performance or clarity?
#23 var setup = function (count) ...
Is'nt the "count" argument obsolete?
Hello guys.
In this conditional pattern doc, you say:
Using the normal pattern will generally outperform the regex (alternative method 1) in a loop, [...]"
Then I made a little test – still doubtful, but can give us an idea: Conditional Expressions Difference.
I really was expecting that regex would be faster/better outside a loop – as I outputted on the alert()
– but it doesn't seem to happen.
Yes, I know – jsPerf isn't the most trustful way of performance rating, but as I said, it can give us a starting point.
So, what does "outperform" really means?
Currently the pattern for detaching an element from the DOM before manipulating and reinserting it does not account for its position within the parent element. In the example given at https://github.com/shichuan/javascript-patterns/blob/master/jquery-patterns/detach.html if the table were the first child element under the parent it would end up as the last child element once the operation completed.
as I see it is no relation with the mobile? (I guess it means jQueryMobile)?
I was looking at the memoization patterns and specifically 'preferred method 2' (multiple arguments using JSON stringify) and noticed a possible issue:
var cachekey = JSON.stringify(Array.prototype.slice.call(arguments)),
Maybe it should mention that this will only work correctly for primitive (and Array) arguments, since the order in which properties of Objects are enumerated is undetermined and can even change between enumerations. (a JSON encoder that sorts the keys won't have this issue).
Take for example this object:
{a:1, b:2}
Could on execution result in theseJSONs and so miss the cache.
"{'a':1, 'b':2}"
"{'b':2, 'a':1}"
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.