jquery reminder
Things you better know before you write JS code.
unorganized code is hell
It mess everthing up.
Bad pattern Including :
- Always use global objects
- God object
- One operation in multiple event
- Variable name conflict
- Scope issue
- null issue
Always use global objects
base.js
window.User = $("#table");
page.js
$("#user").click(function(){
User.append("<tr><td>new user</td></tr>");
});
Bad Practice!
God object
GOD OBJECT
var Comment = {
usercomment: {
edit: function(str){
$("#item"+this.current_id).text(str);
Comment.usercomment.update();
},
init:function(){
$("#btn").click(function(){
Comment.tablecomment.show();
});
},
list:function(){ /* ....... */}
},
tablecomment: {
show:function(){/* ....... */}
},
/* ...... */
};
Comment.usercoment.init();
one operation in multiple event.
$("#btn").click(function(){
var $target = $("#target");
$target.find(".view").hide();
$target.find(".edit").show();
});
$("#target").find(".edit .submit").click(function(){
//validation
//submit
});
$("#target").find(".edit .cancel").click(function(){
$target.find(".view").show();
$target.find(".edit").hide();
});
one operation in multiple event
var $target = $("#target");
$target.on("edit",function(){
var $this = $(this);
$this.find(".view").hide();
$this.find(".edit").show();
});
$target.on("submit",function(){
//validation
//submit
});
$target.on("cancel",function(){
$target.find(".view").show();
$target.find(".edit").hide();
});
$("#btn").click(function(){ $target.trigger("edit"); });
$target.find(".edit .submit").click(function(){
$target.trigger("submit");
});
$target.find(".edit .cancel").click(function(){
$target.trigger("cancel");
});Variable name conflict
var item = $(".item");
for(var i = 0 ,len = item.length ; i < len ; ++i){
/*........*/
var details = item.eq(i).find(".details");
for(var i = 0 , len = details.length; i<len; ++i){
/* .... */
}
}
VARIABLE NAME CONFLICT
var k = 1;
function test(){
console.log(k); //expect 1 but print undefined ,
var k = 5;
console.log(k);
}
test();
Scope
var item = $(".item");
for(var i = 0 ,len = item.length; i<len ;++i){
item.eq(i).click(function(){
alert(i);
});
}
//When it got trigger , i is always item.length
test(); //expect error but it print "hi"
function test(){
console.log("hi");
}
Null issue
function test(options){
//oops , options is undefined
var k = options.position.x;
}
function test(options){
options = $.extend({},options);
}
function test(options){
options = options || {};
}
function test(options){
if(options != null && options.position != null){
var k = options.position.left;
}
}
function test(options){
var position = (options && options.position)
|| {left:null,top:null};
}
Other Useful pattern
- Scope Protection
- Pub-sub pattern (wiki)
- Prevent Browser Repaint
- Plugin template
- Template Issue
- AMD (RequireJS)
- Promise Pattern
Scope Protection
Limit your variable scope as need.
To prevent NAMING CONFLICT by default.
(function($,/*...*/,undefined){
var k = 1;
})(jQuery,/*other global objects*/);
console.log(k);//You can't access k here.
scope protection
(function($,undefined){
var user = ""; //scope is protected in local
window.item = ""; //global variable
})(jQuery);
console.log(user);// undefined , you can't access it here.
SCOPE PROTECTION
If you want to use global variable , DECLARE it .
- Write the global object explicitly
- Use upper case variable name
- Use function instead of properties if possible
Scope Protection
window.User = {
name : "Tony" ,
State :"Logined"
};
window._user ={
name : "Tony" ,
State :"Logined"
};
window.getUser = function(){
return this._user;
}Pub-sub pattern
- Decoupled event trigger and listener
- Encapsulation the implementation
Use jQuery custom event to implement it.
Global event -> document or global object ($({}))
Dom-based event -> dom
Prevent Browser Repaint
Prevent a lot of dom changes in a loop or timer.
Use css class instead of changing dom style properties.
var users = ["user1", /*.......*/ ,"user999"],
table = $("#table");
for(var i= 0 ,len = user.length ; i < len ;++i){
table.append("<tr><td>"+user[i]+"</td></tr>");
}
vs
var users = ["user1", /*.......*/ ,"user999"],
table = $("#table"),
out = [];
for(var i= 0 ,len = user.length ; i < len ;++i){
out.push("<tr><td>"+user[i]+"</td></tr>");
}
table.append(out.join(""));
Plugin template
(function ($,undefined) {
$.fn.myplugin = function (opts) {
// default configuration
opts = $.extend({},opts);
// main function
var init = function (obj) {
};
// initialize every element
this.each(function () {
init($(this));
});
return this;
};
// auto start
$(function () {
$('.myplugin').myplugin();
});
})(jQuery);
Template Issue
How to write html in JS?
<script type="text/template" id="user-tmp"></script>
<textarea id="user-tmp">(htmlescaped content) </textarea/>
var js = (json_encode content);
var js = '<div> '+myobj.name + '</div>';
AMD (RequireJS)
Stop maintaining <Script> tag EVERY PAGE.
Use define / require to load Lib dynamic.
<script src="jquery.js"></script> <!-- <script src="jquery.min.js"></script>--> <script src="jquery.ui.js"></script> <script src="jquery.form.js"></script> <script src="jquery.validations.js"></script> <script src="page.js"></script>
vs
<script src="require-jquery.js" main="page"></script>
require(["jquery","jquery.ui","jquery.form","jquery.validations"],
function($){
//content of page js
}
);
Promise Pattern
It's easy to get confused by the API.
Separated event publish and handler.
"When to ready" => Deferred
"Handler" => Promise
Just like "Ready" event.
PROMISE PATTERN
When we call
//as same as $(document).ready(function(){});
$(function(){
alert("hi");
});
It's usually "NOT READY" yet,
but we know it will be invoked after page ready.
(That's how document said.)
PROMISE PATTERN
What if we implement with Deferred?
Count down example :
function countdown(ms){
var time = $.Deferred();
setTimeout(function(){
time.resolve();
},ms);
return time.promise();
}
countdown(5000).done(function(){
alert("5 seconds, timeout!");
});
http://jsfiddle.net/vsNnq/
Q & A
Any questions ?
Thanks
You could find slides on JavaScript.tw FB group.
jquery reminder
By TonyQ Wang
jquery reminder
- 5,772