zoukankan      html  css  js  c++  java
  • Pro Javascript Design Patterns勘误Errata汇总(持续更新中)

    结合从网上搜集的资料,现将Pro Javascript Design Patterns一书几处有错误嫌疑的地方整理出来。

    1. P.28: Chapter 3: Encapsulation and Information Hiding > Fully Exposed Object  错误类型:印刷错误+计算方法错误

    原代码为:

    Book.prototype = {
      checkIsbn: function(isbn) {
        if(isbn == undefined || typeof isbn != 'string') {
          return false;
        }

        isbn = isbn.replace(/-/. ''); // Remove dashes.
        if(isbn.length != 10 && isbn.length != 13) {
          return false;
        }

        var sum = 0;
        if(isbn.length === 10) { // 10 digit ISBN.
          If(!isbn.match(\^\d{9}\)) { // Ensure characters 1 through 9 are digits.
            return false;
          } var sum = 0; if (isbn.length === 10) { console.log("checking for 10..."); if (!isbn.match(/^\d{9}/)) { return false; } for ( var i = 0; i < 9; i++) { sum += isbn.charAt(i) * (10 - i); } var checksum = sum % 11; checksum = (checksum === 10) ? "X" : checksum; if (isbn.charAt(9) != checksum) { return false; } } else { if (!isbn.match(/^\d{12}/)) { return false; } for ( var i = 0; i < 12; i++) { sum += isbn.charAt(i) * ((i % 2 === 0) ? 1 : 3); } var checksum = sum % 10; if (isbn.charAt(12) != checksum) { return false; } } ...
    };

    应更正为:

    Book.prototype = {
      checkIsbn: function(isbn) {
        if(isbn == undefined || typeof isbn != 'string') {
          return false;
        }

        isbn = isbn.replace(/-/g, ''); // Remove dashes.
        if(isbn.length != 10 && isbn.length != 13) {
          return false;
        }

        var sum = 0;
        if(isbn.length === 10) { // 10 digit ISBN.
          if(!isbn.match(\^\d{9}\)) { // Ensure characters 1 through 9 are digits.
            return false;
          }

        var sum = 0;
        if(isbn.length === 10) { // 10 digit ISBN.
          If(!isbn.match(\^\d{9}\)) { // Ensure characters 1 through 9 are digits.
            return false;
          } var sum = 0; if (isbn.length === 10) { console.log("checking for 10..."); if (!isbn.match(/^\d{9}/)) { return false; } for ( var i = 0; i < 9; i++) { sum += isbn.charAt(i) * (10 - i); } var checksum = (11 - sum % 11) % 11; checksum = (checksum === 10) ? "X" : checksum; if (isbn.charAt(9) != checksum) { return false; } } else { if (!isbn.match(/^\d{12}/)) { return false; } for ( var i = 0; i < 12; i++) { sum += isbn.charAt(i) * ((i % 2 === 0) ? 1 : 3); } var checksum = (10 - sum % 10) % 10; if (isbn.charAt(12) != checksum) { return false; } }

    ...
    };

    关于验证ISBN号的正确计算方法,我参考了维基百科上的International Standard Book Number。这一点作者太疏忽大意了。

    2. P.38: Chapter 3: Encapsulation and Information Hiding > Constants  错误类型:印刷错误+结构错误

    原代码为:

    var Class = (function() {
      
      // Constants (created as private static attributes).
      var UPPER_BOUND = 100;
      
      // Privileged static method.
      this.getUPPER_BOUND() {
        return UPPER_BOUND;
      }
    
      ...
    
      // Return the constructor.
      return function(constructorArgument) {
        ...
      }
    })();
    
    
    /* Grouping constants together. */
    
    var Class = (function() {
      
      // Private static attributes.
      var constants = {
        UPPER_BOUND: 100,
        LOWER_BOUND: -100
      }
      
      // Privileged static method.
      this.getConstant(name) {
        return constants[name];
      }
    
      ...
    
      // Return the constructor.
      return function(constructorArgument) {
        ...
      }
    })();
    
    
    /* Usage. */
    
    Class.getConstant('UPPER_BOUND');
    

    应更正为:

    var Class = (function() {
      
      // Constants (created as private static attributes).
      var UPPER_BOUND = 100;
      
      // Privileged static method.
      this.getUPPER_BOUND=function() {
        return UPPER_BOUND;
      }
    
      ...
    
      // Return the constructor.
      return function(constructorArgument) {
        ...
      }
    })();
    
    
    /* Grouping constants together. */
    
    var Class = (function() {
      
      // Private static attributes.
      var constants = {
        UPPER_BOUND: 100,
        LOWER_BOUND: -100
      }
      
      // Privileged static method.
      this.getConstant=function(name) {
        return constants[name];
      }
    
      ...
    
      // Return the constructor.
      return function(constructorArgument) {
        ...
      }
    })();
    
    
    /* Usage. */
    
    Class.getConstant('UPPER_BOUND');
    

    关于此处代码的运行,有人提出并不能达到作者所提出的需求,因为即使照上面的方法更正后,由于this.getUPPER_BOUNDthis.getConstant都是在自执行函数的内部运行,这里的this实际上将指向全局变量,即window。在StacksOverflow上,有人提出此讨论,众人相继给出解决办法,敬请参阅原文

    3. P.89: Chapter 6: Chaining > Using Callbacks to Retrieve Data from Chained Methods  错误类型:印刷错误+结构错误

    原代码为:

    // Accessor without function callbacks: returning requested data in accessors.
    window.API = window.API || {};
    API.prototype = function() {
      var name = 'Hello world';
      // Privileged mutator method.
      setName: function(newName) {
        name = newName;
        return this;
      },
      // Privileged accessor method.
      getName: function() {
        return name;
      }
    }();
    
    // Implementation code.
    var o = new API;
    console.log(o.getName()); // Displays 'Hello world'.
    console.log(o.setName('Meow').getName()); // Displays 'Meow'.
    
    // Accessor with function callbacks.
    window.API2 = window.API2 || {};
    API2.prototype = function() {
      var name = 'Hello world';
      // Privileged mutator method.
      setName: function(newName) {
        name = newName;
        return this;
      },
      // Privileged accessor method.
      getName: function(callback) {
        callback.call(this, name);
        return this;
      }
    }();
    
    // Implementation code.
    var o2 = new API2;
    o2.getName(console.log).setName('Meow').getName(console.log);
    // Displays 'Hello world' and then 'Meow'.
    
    

    应更正为:

    // Accessor without function callbacks: returning requested data in accessors.
    window.API = window.API || function(){};
    API.prototype = function() {
      var name = 'Hello world';
    return {
    // Privileged mutator method. setName: function(newName) { name = newName; return this; }, // Privileged accessor method. getName: function() { return name; }
    }

    }(); // Implementation code. var o = new API; console.log(o.getName()); // Displays 'Hello world'. console.log(o.setName('Meow').getName()); // Displays 'Meow'. // Accessor with function callbacks. window.API2 = window.API2 || function(){}; API2.prototype = function() { var name = 'Hello world'; return {// Privileged mutator method. setName: function(newName) { name = newName; return this; }, // Privileged accessor method. getName: function(callback) { callback.call(this, name); return this; }
    }
    }(); // Implementation code. var o2 = new API2; o2.getName(console.log).setName('Meow').getName(console.log); // Displays 'Hello world' and then 'Meow'.

    这个问题是http://www.apress.com/9781590599082/上有人提出的。

    4. P.100: Chapter 7: The Factory Pattern > XHR Factory  错误类型:印刷错误?结构错误?

    原代码为:

    /* SimpleHandler class. */
    var SimpleHandler = function() {}; // implements AjaxHandler
    SimpleHandler.prototype = {
      request: function(method, url, callback, postVars) {
      ...
      },
      createXhrObject: function() { // Factory method.
        var methods = [
          function() { return new XMLHttpRequest(); },
          function() { return new ActiveXObject('Msxml2.XMLHTTP'); },
          function() { return new ActiveXObject('Microsoft.XMLHTTP'); }
        ];
        
        for(var i = 0, len = methods.length; i < len; i++) {
          try {
            methods[i]();
          }
          catch(e) {
            continue;
          }
          // If we reach this point, method[i] worked.
          this.createXhrObject = methods[i]; // Memoize the method.
          return methods[i];
        }    
        // If we reach this point, none of the methods worked.
        throw new Error('SimpleHandler: Could not create an XHR object.');
      } 
    };
    

    应更正为:

    /* SimpleHandler class. */
    var SimpleHandler = function() {}; // implements AjaxHandler
    SimpleHandler.prototype = {
      request: function(method, url, callback, postVars) {
      ...
      },
      createXhrObject: function() { // Factory method.
        var methods = [
          function() { return new XMLHttpRequest(); },
          function() { return new ActiveXObject('Msxml2.XMLHTTP'); },
          function() { return new ActiveXObject('Microsoft.XMLHTTP'); }
        ];
        
        for(var i = 0, len = methods.length; i < len; i++) {
          try {
            methods[i]();
          }
          catch(e) {
            continue;
          }
          // If we reach this point, method[i] worked.
          this.createXhrObject = methods[i]; // Memoize the method.
          return methods[i]();
        }    
        // If we reach this point, none of the methods worked.
        throw new Error('SimpleHandler: Could not create an XHR object.');
      } 
    };
    

    这一错误很可能是作者没有测试代码,照书中所述,createXhrObject要在第一次运行之后记住当前的运行环境中能够使用的HttpRequest对象,methods数组中的对象为函数,因此要用一个括号执行后才能得到真正的对象。

    5. P.130: Chapter 9: The Composite Pattern > Form Validation  错误类型:印刷错误

    原代码为:

    /* Field class, abstract. */
    
    var Field = function(id) { // implements Composite, FormItem
      this.id = id;
      this.element;
    };
    ...
    Field.prototype.save = function() {
      setCookie(this.id, this.getValue);
    };
    

    应更正为:

    /* Field class, abstract. */
    var Field = function(id) { // implements Composite, FormItem
      this.id = id;
      this.element;
    };
    ...
    Field.prototype.save = function() {
      setCookie(this.id, this.getValue());
    };
    

    6. P.155: Chapter 11: The Adapter Pattern > Adapting an Email API  错误类型:印刷错误

    原代码为:

    // dedMail application interface.
            var dedMail = (function() {
              function request(id, type, callback) {
                  ...
              }
              return {
                  ...
                formatMessage: function(e) {
                  var e = e || window.event;
                  try {
                    e.preventDefault();
                  } 
                  catch(ex) {
                    e.returnValue = false;
                  }
                  var targetEl = e.target || e.srcElement;
                  var id = targetEl.id.toString().split('-')[1];
                  dedMail.getMail(id, function(msgObject) {
                    var resp = eval('('+msgObject+')');
                    ...
                    messagePane.innerHTML = DED.util.substitute(details, resp);
                  }
              }; 
            })(); 
            
            // Set up mail implementation.
            addEvent(window, 'load', function() {
              var threads = getElementsByClass('thread', 'a');
              var messagePane = $('message-pane');
              for (var i=0, len=threads.length; formatMessage );
              }
            });
    
    

    应更正为:

    // dedMail application interface.
            var dedMail = (function() {
              function request(id, type, callback) {
                  ...
              }
              return {
                  ...
                formatMessage: function(e) {
                  var e = e || window.event;
                  try {
                    e.preventDefault();
                  } 
                  catch(ex) {
                    e.returnValue = false;
                  }
                  var targetEl = e.target || e.srcElement;
                  var id = targetEl.id.toString().split('-')[1];
                  dedMail.getMail(id, function(msgObject) {
                    var resp = eval('('+msgObject+')');
                    ...
                    messagePane.innerHTML = DED.util.substitute(details, resp);
                  })
                }
              }; 
            })(); 
            
            // Set up mail implementation.
            addEvent(window, 'load', function() {
              var threads = getElementsByClass('thread', 'a');
              var messagePane = $('message-pane');
              for (var i=0, len=threads.length; dedMail.formatMessage );
              }
            });
    
    

    7. P.161,162,165,166: Chapter 12: The Decorator Pattern > The Structure of the Decorator   错误类型:结构错误

    在多个页码处均为同一错误类型,仅举其中一处为例。P.161:

    原代码为:

    /* HeadlightDecorator class. */
    
    var HeadlightDecorator = function(bicycle) { // implements Bicycle
      this.superclass.constructor(bicycle); // Call the superclass's constructor.
    }
    extend(HeadlightDecorator, BicycleDecorator); // Extend the superclass.
    HeadlightDecorator.prototype.assemble = function() {
      return this.bicycle.assemble() + ' Attach headlight to handlebars.';
    };
    HeadlightDecorator.prototype.getPrice = function() {
      return this.bicycle.getPrice() + 15.00;
    };
    
    

    应更正为:

    /* HeadlightDecorator class. */
    
    var HeadlightDecorator = function(bicycle) { // implements Bicycle
      HeadlightDecorator.superclass.constructor.call(this, bicycle); // Call the superclass's constructor.
    }
    extend(HeadlightDecorator, BicycleDecorator); // Extend the superclass.
    HeadlightDecorator.prototype.assemble = function() {
      return this.bicycle.assemble() + ' Attach headlight to handlebars.';
    };
    HeadlightDecorator.prototype.getPrice = function() {
      return this.bicycle.getPrice() + 15.00;
    };
    
    

    8. P.191: Chapter 13: The Flyweight Pattern > Sotring Instances for Later Reuse   错误类型:结构错误

    原代码为:

    			var DialogBoxManager = (function() {
    				var created = [];
    
    				return {
    					displayDialogBox : function(id, header, body, footer) {
    						var inUse = this.numberInUse();
    						if (inUse > created.length) {
    							created.push(this.createDialogBox(id));
    						}
    						created[i].show(header, body, footer);
    					},
    
    					createDialogBox : function(id) {
    						return new DialogBox(id);
    					},
    
    					numberInUse : function() {
    						var inUse = 0;
    						for ( var i = 0; i < created.length; ++i) {
    							console.log(created[i].state());
    							if (created[i].state() == "visible") {
    								inUse++;
    							}
    						}
    						return inUse;
    					}
    				}
    			})();
    

    应更正为:

    			var DialogBoxManager = (function() {
    				var created = [];
    
    				return {
    					displayDialogBox : function(header, body, footer) {
    						(this.getFirstHiddenDialogBox() || this.createDialogBox()).show(header, body, footer);
    					},
    
    					createDialogBox : function() {
    						var db = new DialogBox(this.numberInUse());
    						created.push(db);
    						return db;
    					},
    
    					getFirstHiddenDialogBox : function() {
    						for ( var i = 0; i < created.length; ++i) {
    							if (created[i].state() != "visible") {
    								return created[i];
    							}
    							continue;
    						}
    						return null;
    					},
    
    					numberInUse : function() {
    						var inUse = 0;					
    						for ( var i = 0; i < created.length; ++i) {
    							if (created[i].state() == "visible") {
    								inUse++;
    							}
    						}
    						return inUse;
    					}
    				}
    			})();
    

    原代码中inUse > created.length是显然行不通的,inUse永远也不可能大于created.length,其判断也就失去了意义。改进后的代码将能在调用自动displayDialogBox时判断是否有隐藏的已经建立的DialogBox,如果有即用之,如果没有即调用createDialogBox创建一个新的,numberInUse在createDialogBox函数中使用。

    9. P.198, P.248, P.252: Chapter 14: The Proxy Pattern > The Structure of the Proxy; Chapter 17: The Chain of Responsibility > The Structure of the Chain of Responsibility   错误类型:印刷错误

    两处文字中均少了book,导致程序运行出现错误。

    原代码为:

    PublicLibrary.prototype = {
    	findBooks : function(searchString) {
    		var results = [];
    		for ( var isbn in this.catalog) {
    			if (!this.catalog.hasOwnProperty(isbn)) {
    				continue;
    			}
    			if (this.catalog[isbn].getTitle().match(searchString)
    					|| this.catalog[isbn].getAuthor().match(searchString)) {
    				results.push(this.catalog[isbn]);
    			}
    		}
    		return results;
    	}
    ...
    	addBook : function(newBook) {
    		this.catalog[newBook.getIsbn()] = {
    			book : newBook,
    			available : true
    		};
    	}
    }
    

    应更正为:

    PublicLibrary.prototype = {
    	findBooks : function(searchString) {
    		var results = [];
    		for ( var isbn in this.catalog) {
    			if (!this.catalog.hasOwnProperty(isbn)) {
    				continue;
    			}
    			if (this.catalog[isbn].book.getTitle().match(searchString)
    					|| this.catalog[isbn].book.getAuthor().match(searchString)) {
    				results.push(this.catalog[isbn].book);
    			}
    		}
    		return results;
    	}
    ...
    	addBook : function(newBook) {
    		this.catalog[newBook.getIsbn()] = {
    			book : newBook,
    			available : true
    		};
    	}
    }
    

    10. P.250, P.254: Chapter 17: The Chain of Responsibility > The Structure of the Chain of Responsibility   错误类型:结构错误

    原代码为:

    var SciFiCatalog = function() {};// Implements Catalog
    extend(SciFiCatalog , GenreCatalog);
    

    应更正为:

    var SciFiCatalog = function() {// Implements Catalog
    SciFiCatalog.superclass.contructor.apply(this,arguments);
    };
    extend(SciFiCatalog , GenreCatalog);
    

    Why?因为作者在本书中一直在用的extend方法是不能继承“父类”的constructor中的属性的,所以必须在“子类”的constructor中调用一遍该函数,以便“子类”继承“父类”的这些属性。

    11. P.253: Chapter 17: The Chain of Responsibility > The Structure of the Chain of Responsibility   错误类型:印刷错误

    原代码为:

    if (found) {
    	outerloop: for ( var i = 0; i != this.catalog.length; ++i) {
    		var book = this.catalog[i];
    		if (book.getTitle().match(searchString)
    				|| book.getAuthor().match(searchString)) {
    			for ( var j = 0; j != request.results.length; ++j) {
    				if (request.results[j].getIsbn() === book.getIsbn()) {
    					continue outerloop;
    				}
    			}
    			request.results.push(book);
    		}
    	}
    }
    

    应更正为:

    if (found) {
    	outerloop: for ( var i = 0; i != this.catalog.length; ++i) {
    		var book = this.catalog[i];
    		if (book.getTitle().match( request.searchString)
    				|| book.getAuthor().match( request.searchString)) {
    			for ( var j = 0; j != request.results.length; ++j) {
    				if (request.results[j].getIsbn() === book.getIsbn()) {
    					continue outerloop;
    				}
    			}
    			request.results.push(book);
    		}
    	}
    }
    

    这里的searchString前面显然是少了request,不然就是一个未定义的变量。

    12. P.260: Chapter 17: The Chain of Responsibility > Adding Tags to Photos   错误类型:结构错误

    原代码为:

    DynamicGallery.prototype = {
      ...
      getAllLeaves: function() {
        var leaves = [];
        for(var node, i = 0; node = this.getChild(i); i++) {
          leaves.concat(node.getAllLeaves());
        }
        return leaves;
      },
    ...
        for(var results = [], node, i = 0; node = this.getChild(i); i++) {
          results.concat(node.getPhotosWithTag(tag));
        }
        return results;
      },
      ...
    };
    

    应更正为:

    DynamicGallery.prototype = {
      ...
      getAllLeaves: function() {
        var leaves = [];
        for(var node, i = 0; node = this.getChild(i); i++) {
          leaves=leaves.concat(node.getAllLeaves());
        }
        return leaves;
      },
    ...
        for(var results = [], node, i = 0; node = this.getChild(i); i++) {
          results=results.concat(node.getPhotosWithTag(tag));
        }
        return results;
      },
      ...
    };
    

    Javascript中的Array.concat是在不改变原数组的情况下返回一个新数组。

    本文来自pinocchioatbeijing(专注前端技术 追求至美生活 以文会友)在博客园的博客,文章URL:http://www.cnblogs.com/pinocchioatbeijing/archive/2012/02/01/2334126.html,转载请注明,并欢迎大家不吝赐教。

  • 相关阅读:
    js 回车调用后台事件
    获取下拉框选中的值:
    MVC 3.0 在各个版本IIS中的部署
    创建Windows域
    SQL Server 事务、异常和游标
    IIS配置PHP环境(快速最新版)
    js操作select下拉框
    如何清除访问远程网络时保存的密码
    免费Web服务
    Firefox不支持event解决方法
  • 原文地址:https://www.cnblogs.com/pinocchioatbeijing/p/2334126.html
Copyright © 2011-2022 走看看