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,515