zoukankan      html  css  js  c++  java
  • 《JavaScript设计模式》Stoyan Stefanov-读书笔记

    第一章  简介

    一、三种类型模式

      设计模式、编码模式、反模式

    二、JavaScript基本概念

    1、面向对象

      五种基本类型:数字、字符串、布尔、undefine、null

      函数也是对象,也有属性和方法

      对象有两种类型:1、原生的 ECMAScript  2、主机的,在主机环境中定义,如浏览器

      原生包括:内置对象和用户自定义对象

      主机包括:window对象和所有DOM对象

    2、原型

      原型是个对象,每个都会自动获取一个Prototypes属性,该属性指向一个新的空对象

      

    3、JSLint

      javascript是一门解析语言没有静态编译时检查,JSLint是检查JavaScript代码质量的工具

    第二章  基本技巧

      本章讨论一些高质量代码的核心方法、模式和习惯,如避免全局变量、使用单个变量var的声明、循环中缓存长度变量length和符合代码的约定.

    一、编写可维护代码

    1、减少全局变量

      全局对象可以在函数外部使用this访问

      mylobal = "hello";    // 全局变量

      console.log(mylobal);

      console.log(window.mylobal);

      console.log(window["mylobal"]);

      全局变量的问题:1、第三方Javascript库  2、广告合作伙伴的脚本 

      释放变量:使用var 创建的变量不能删除,不使用var创建的隐含全局变量可以删除,隐含变量不是真正的变量,而是全局对象的属性,可以通过delete删除

      // 定义三个全局变量

      var global_var = 1;

      global_noar = 2;

      (function(){

        global_fromfunc = 3;

      })

      delete  global_var;  // false

      delete  global_noar;  // true

      delete  global_fromfunc;   // true

    2、单一的var模式 

      用一个var在函数顶部进行变量的声明

      var a = 0,

          b = 1;

    3、for循环

      当遍历时存储长度,

      var oLi = document.getElementsByTagName("li");

      for(var i=0, len=oLi.length; i< len; i++){    ...   } 

    4、不在增加内置的原型

      就是别在内置的构造函数内增加新功能,

    5、switch模式

      提高switch的可读性和健壮性

      var inspect = 0, result = "";

      swith(inspect){

        case 0:

          result = "zero"; break;

        case 1:

          result = "one"; break;

        default:

          retult = "unknown";

      }

      如果不写break语句会接着向下执行

    6 、parseInt()的数值约定

      parseInt()从一个字符串中获取数值,第二个参数为进制,但如果字符串为0开头就必须写进制,如"08",parseInt("08", 10);否则在ie下会输出

      另一种写法可以:

      +"08";  或者   Number("08")    

    第三章  字面量和构造函数

    一、对象字面量

      // 定义一个空对象

      var dog = {};

      // 向对象加一个属性和方法

      dog.name = "benji";

      dog.getName = function(){

        return dog.name;

      }

    二、构造函灵敏

    1 var Person = function(name){
    2     this.name = name;
    3     this.say = function(){
    4         return this.name;
    5     }
    6 }

      构造函数原型prototyp的作用

      将say方法添加到this中,如果在任何时间调用new Person()时都会在内存中创建一个新的函数,会使效率低下,因为创建多个person实例时也会创建多个say方法,解决方法是将他们添加到原型中prototype

    第四章  函数

      函数的两个特点:1、函数是一类对象     2、函数可以提供一个作用域

    1、全局作用域:function foo(){}

    2、局部作用域:

    function local(){

      // 局部作用域

      function bar(){};

      return bar;

    }

    3、函数表达式  var bar = function(){  ...  }

    4、匿名函数  function(){ ... };  没有名称,在自动函数或赋给一个变量时使用

    5、即时执行函数  (function(){ ...  })();  

      即时函数的参数:

      (function(who, when){

        console.log("i met" + who);

      })("joe black", new Date())

      即时函数的返回值:

      var result = (function(){

        return 2 + 3;

      })();

    第五章  对象创建模式

    一、命名空间模式

      命名空间有助于减少全局变量的数量,并且避免合名冲突或过长的名字前缀

     1 <script>
     2     // 不安全代码,比如两个js文件中都有这会MYAPP的创建,这样第二个会覆盖掉第一个对象
     3     var MYAPP = {};
     4     
     5     // 更好的代码风格
     6     if(typeof MYAPP === "undefined"){
     7         var MYAPP = {};
     8     }
     9     
    10     // 或者使用
    11     var MYAPP = MYAPP || {};
    12 </script>

     

      检测代码需要太多的重复工作,如果想定义MYAPP.modeles.module就必须三次检查,每次都需要检查一次对象或属性,可以使用namespace()函数

     1 <script>
     2     MYAPP.namespace("MYAPP.modules.getName");
     3 
     4     // 相当于
     5     MYAPP.modules.getName = {}
     6 
     7 
     8     // 定义一个命名空间函数
     9     var MYAPP = MYAPP || {};
    10     MYAPP.namespace = function(sName, newObj){
    11         var parts = sName.split("."),
    12             argLen = arguments.length,
    13             parent = MYAPP;
    14 
    15         // 剥离最前面的全局变量
    16         if(parts[0] == "MYAPP"){
    17             parts = parts.slice(1);
    18         }
    19 
    20         if(argLen == 2 && (typeof newObj === "object" || typeof newObj === "function")){
    21             for(var i= 0,len = parts.length; i<len; i++){
    22                 if(i == len-1){
    23                     parent[parts[i]] = $.extend(newObj, parent[parts[i]]);  // 需要继承之前的对象
    24                 }
    25                 else{
    26                     // 如果不存在就创建一个新的属性
    27                     if(typeof parent[parts[i]] === "undefined"){
    28                         parent[parts[i]] = {};
    29                     }
    30                 }
    31                 parent = parent[parts[i]];
    32             }
    33         }
    34         else{
    35             for(var i= 0,len = parts.length; i<len; i++){
    36                 // 如果不存在就创建一个新的属性
    37                 if(typeof parent[parts[i]] === "undefined"){
    38                     parent[parts[i]] = {};
    39                 }
    40                 parent = parent[parts[i]];
    41             }
    42         }
    43 
    44         return parent;
    45     }
    46 
    47     // 1、创建一个命名空间,并初始化命名空间的对象
    48     var ssq = MYAPP.namespace("MYAPP.storage.getStorage", {
    49 
    50         init: function(){
    51             this.bindEvent();
    52         },
    53 
    54         bindEvent: function(){
    55             console.log("bind All");
    56         }
    57 
    58     });
    59 
    60     // 调用
    61     ssq.init();     // 结果 bind All
    62 
    63     // 2、创建一个命名空间,初始化时为函数,其实使用对象也完全可以做到,MYAPP.namespace("MYAPP.storage", {showFun: function(){ console.log("匿名函数"); }};
    64     var dlt = MYAPP.namespace("MYAPP.storage.showFun", function(){
    65         console.log("匿名函数");
    66     });
    67 
    68     // 调用
    69     dlt();
    70 </script>

    二、私有属性、方法

      js中没有私有成员的语法,可以通过闭包,或内部变量来实现这种功能。

     1 <script>
     2     function Gadget(){
     3         
     4         // 私有成员
     5         var name = "iPad";
     6         
     7         // 公有函数
     8         this.getName = function(){
     9             return name;
    10         }
    11     }
    12     
    13     var toy = new Gadget();
    14     console.log(toy.name);      // undefined
    15     console.log(toy.getName()); // iPad
    16 </script>

    三、特权方法

      就是通过公有方法来访问私有属性,这个方法可以叫做特权方法,上面的例子getName()就是个特权方法.

    四、模块模式

     1 <script>
     2     var myObj = (function(){
     3         
     4         // 私有成员
     5         var name = "my, oh my";
     6         
     7         // 实现公有部分
     8         return {
     9             getName: function(){
    10                 return name;
    11             }
    12         }
    13     })();
    14 </script>

    1、构造函数的模块

     1 <script>
     2     var MYAPP = MYAPP || {};
     3 
     4     // 命名空间函数
     5     MYAPP.namespace = function(sName, newObj){
     6         var parts = sName.split("."),
     7                 argLen = arguments.length,
     8                 parent = MYAPP;
     9 
    10         // 剥离最前面的全局变量
    11         if(parts[0] == "MYAPP"){
    12             parts = parts.slice(1);
    13         }
    14 
    15         if(argLen == 2 && (typeof newObj === "object" || typeof newObj === "function")){
    16             for(var i= 0,len = parts.length; i<len; i++){
    17                 if(i == len-1){
    18                     parent[parts[i]] = $.extend(newObj, parent[parts[i]]);  // 需要继承之前的对象
    19                 }
    20                 else{
    21                     // 如果不存在就创建一个新的属性
    22                     if(typeof parent[parts[i]] === "undefined"){
    23                         parent[parts[i]] = {};
    24                     }
    25                 }
    26                 parent = parent[parts[i]];
    27             }
    28         }
    29         else{
    30             for(var i= 0,len = parts.length; i<len; i++){
    31                 // 如果不存在就创建一个新的属性
    32                 if(typeof parent[parts[i]] === "undefined"){
    33                     parent[parts[i]] = {};
    34                 }
    35                 parent = parent[parts[i]];
    36             }
    37         }
    38 
    39         return parent;
    40     }
    41 
    42     MYAPP.namespace("MYAPP.util");      // 创建一个命名空间
    43     MYAPP.util =  (function(){
    44 
    45         // 依赖
    46         var oLib = MYAPP.lib;
    47         
    48         // 创建构造函数
    49         function Constr(){
    50             this.elements = "siguang";
    51         }
    52 
    53         Constr.prototype.version = "2.0";
    54         Constr.prototype.showMessage = function(){
    55             console.log(this.version, this.elements);
    56         }
    57 
    58         var oConstr = new Constr();
    59 
    60         return oConstr;
    61     }());
    62 
    63     console.log(MYAPP);
    64 
    65     // 调用
    66     MYAPP.util.showMessage();        //
    67 </script>

    2、将全局变量导入到模块中

    1 <script>
    2     MYAPP.utilities.module = (function(app, global){
    3         // 引用全局对象
    4         // 可以转成局部变量
    5         // 全局应用程序命名空间对象
    6     })(MYAPP, this)
    7 </script>

    第五章  对象创建

    一、包装对象

      什么是包装对象

      var str = "ssssssss";   

      str.charAt(3);

      str.substring(2);

      一般方法是调用的是对象,而str是字符串,这就是用到了包装对象,基本类型都有自己的包装对象

      例如:字符串包装类型是String     数字是Number    布尔是Boolean,为什么str可以调用字符串的方法,看下面的例子

    1 <script>
    2     var str = new String("haha");   // 将字符串到String对象
    3     
    4     // String的对象的方法
    5     String.prototype.charAt = function(n){
    6         // ....
    7     }
    8 </script>

    var str = "haha";    // 这句正常定义变量

    str.charAt(2);      // 这里基本类型str会找到对应包装对象的方法,将属性及方法赋给基本类型,然后包装对象消失

    第六章  代码复用模式

    一、类式继承

      类式继承的几种写法:

    1、默认模式 

     1 <script>
     2 
     3     // 父构造函数
     4     function Parent(name){
     5         this.name = name || "siguang";
     6         this.age = "30";
     7         this.setGame = function(){
     8             console.log(this.age);
     9         }
    10     }
    11 
    12     // 向该原型添加功能
    13     Parent.prototype.say = function(){
    14         return this.name;
    15     }
    16 
    17     // 空构造函数
    18     function Child(name, age){
    19         this.age = age;
    20         Parent.call(this, name);        // 改变父类的属性,否则调用的就是父类的属性
    21     }
    22 
    23     // 继承方法,封装了一个
    24     inherit(Child, Parent);
    25 
    26     function inherit(C, P){
    27         C.prototype = new P();    // 继承方法
    28     }
    29 
    30     var oC = new Child("lulu", 28);   
    31     console.log(oC.say());      // lulu
    32     oC.setGame();               // 30
    33 </script>

      类式继承继承父类的属性和方法,如果改变其属性需要将改变指针Parent.call(this, name);

      此模式的缺点:同时继承两个对象的属性,将子类传入age时this.age = age 输出的并不是预期的28而还是父类的30,这也就是第二种模式

    2、共享原型

      修改了inherit方法

    function inherit(C, P){
      C.prototype = P.prototype;    // 缺点:在继承链的某一个子对象或孙对象修改了原型,会影响到父对象和祖先对象.
    }

    3、临时构造函数

  • 相关阅读:
    WPF中的Command事件绑定
    WPF的EventAggregator的发布和订阅
    IE浏览器如何调试Asp.net的 js代码
    MVVM模式用依赖注入的方式配置ViewModel并注册消息
    SQL处理数组,字符串转换为数组
    C#在函数内部获取函数的参数
    JS判断字符串长度(中文长度为2,英文长度为1)
    .net一般处理程序(httphandler)实现文件下载功能
    SQL分页获取数据
    URI编码解码
  • 原文地址:https://www.cnblogs.com/couxiaozi1983/p/4083966.html
Copyright © 2011-2022 走看看