总的来讲,javascript模式是一本力荐的js进阶书,书里面涉及了不少在学习javascript过程当中会碰到的坑,而后提供了很不错的解决方法.虽然不少人吐槽这本书的翻译,可是糟糕的翻译仍是没法掩盖这是一本好书的事实.javascript
所以这里我会结合书上的知识和个人理解来写一些我认为值得借鉴的内容.java
随处可见的是使用new操做符的构造函数node
var People = function(){ this.type = "human"}; //构造函数 var aPerson = new People(); //用new操做符来实例化
因此当在new操做符下的构造函数究竟发生了什么?数组
//new操做发生的事情 var this = Object.create(People.prototype); //建立新的对象,而后继承自parent.prototype; this.type = "human"; //属性和方法被加入到this下; return this; //若是构造函数没有返回,则本身返回this;
如今有一个问题,若是用户在使用构造函数的时候,漏掉了new操做符,那么this就会被指向window/global上,从而出现错误;浏览器
var aPerson = People(); //这里的this指向window console.log(aPerson.type); //undefined console.log(window.type); //'human'
若是漏掉了new操做符可能会致使比较严重的问题.所以也会有了所谓的安全模式:缓存
var People = function(cfg){ if(!(this instanceof People)){ //核心代码 return new People(cfg); //作一个简单的检测 } .....//该干吗干吗 }
因此就算漏掉了new操做符,代码的检查机制也会帮你new,不会出现绑定的问题;安全
回调函数是解耦的神器,若是你的函数内部有一个部分会频繁变化,能够考虑把这些部分封装到一个函数里面做为回调函数传入,这样就能够解除不一样函数之间的耦合,而且会方便修改;ide
var function complexFunction(){ function A(); //变化少的部分 function B(); //变化多的部分 function C() //变化少的部分 } //重构以后: var function complexFunction(fn){ function A(); fn(); function C(); } complexFunction(function B(){ //变化很大的部分 });
这样就能够把会常常变化的部分从不变的函数部分中解耦出来;并且书中的例子更好,一样能够学习参考下:函数
//原始代码:第一个先在node里面建立数据 var findNodes =function(){ //大概的做用是在循环里面重复处理数据 var i = 100000, node = [], found; while(i){ i -= 1; node.push(found); } return nodes; } //这个函数的做用是循环数组来让他消失;为了解耦,因此分开了写; var hide = function(nodes){ var i =0, max = nodes.length; for(;i<max;i+=1){ nodes[i].style.display = "none"; }; }; hide(findNodes());
这样写的问题在于作这个事情须要循环两次,效率其实并不高;因此考虑用下面的方法重构:性能
//重构:提升效率和解耦 var findNodes = function(callback){ var i =100000, node=[], found; if( typeof callback !== "function"){ callback = false; //这里单独判断是为了放在循环以外 } while(i){ i -=1; //这里执行很复杂的过程 if(callback){ callback(found); } nodes.push(found); } } var hide = function(node){ node.style.display = "none"; }; findNodes(hide);
因此经过回调函数的会让函数解耦,特别是在循环体系以内;
若是一个函数有一些准备工做要作,可是这些工做也许只须要执行一次就行了,那么你须要用自定义函数来提升性能;
var count = function(){ var number = 0; console.log("Init Done!") //完成只会执行一次的初始化 count = function(){ //这里用新的函数覆盖原函数 number++; console.log(number); } } Test: count(); //Init Done; count(); //1 count(); //2
因此完成了第一次的初始化,而后完成了一些初始化的工做.这里能够和下面的技巧一块儿联合使用;
若是你开头就须要判断一些东西,而后以后这个判断都不须要执行,那么你可能须要使用这种方法;
提及来比较抽象,可是这个比较常见,好比说浏览器须要知道你正在使用的浏览器,可是这个信息通常只会有一次判断就能够了,好比说下面的方法效率就很低;
var utils = { addListener:function(el,type,fn){ if(typeof window.addEventListener ==="function"){ el.addEventListener(type,fn,false); }else if(typeof document.attachEvent ==="function"){ // 判断这是IE el.attachEvent("on"+type,fn); } } }
可是实际上这种信息我只须要判断一次就好;可是若是写在了utils里面,那么每次都须要执行;因此咱们能够优化成为:
var utils = { //这里只是简单的设置一个接口,实际的执行留在后面的初始化分支里面 addListener:null }; // if(typeof window.addEventListener === "function"){ utils.addListener = function(type,fn,false){ el.addEventListener(type,fn,false); } }else(typeof document.attachEvent ==="function"){ utils.addListener = function(type,fn,false){ el.attachEvent("on"+type,fn); } }
函数是一个对象,那么也就是能够在属性里面添加一些信息.好比说数组的length,函数的name属性就是原本就存在的;
那么咱们也可使用这个特性来给某些计算开销很大的函数,增长一个缓存,若是下次还须要计算这个值,就能够直接返回缓存中的量;
var func = function(param){ if(!func.cache[param]){ var result = {}; //作一些很复杂的计算 func.cache[param] = result; } return func.cache[param]; }; myFunc.cache = {};
当你在作一个通用组件的时候,有时候你也须要留出必定的配置项出来让用户来设置;
var Widget = function(cfg){ cfg = cfg||{}; //若是传入了就用,没有的话就传入{}; cfg.name && this.setName(cfg.name); cfg.theme && this.setTheme(cfg.theme); ......//一系列的配置项 }
大概的思路就是说若是用户有传入配置项,那么就使用配置项.
以前学js的继承的时候,一直很揪心的问题就是,到底什么会继承,什么不会呢?这里刚刚作一个总结
var Gadget = function(){ this.say1 = function(){ console.log("1~")}; var say2= function(){ console.log("2~")}; }; Gadget.prototype.say3 = function(){console.log("3")}; Gadget.say4 = function(){console.log("4")}; //This is a test; var gadget = new Gadget(); gadget.say1(); //1 经过this继承方法效率不高,可是其实是可使用的 gadget.say3(); //3 最好的仍是经过prototype的方法继承.正常访问; Gadget.say2(); //报错!在Gadget里面设置的会没法访问; Gadget.say4();// 4,正常使用,所以经过属性的方法添加到Gadget里面的是能够做为Gadget静态方法调用的