"JavaScript Design Patterns" Reading Notes Chapter 1: Flexible js

I recently discovered a new way of learning (or a way of writing notes), which feels very convenient.

Record in html, mainly to facilitate writing js code, and then write knowledge points in the form of comments.

Because there will be many functions and variables with the same name, the test code file is written and tested separately.

In this way, you can record and perform targeted tests. The test will not interrupt the recording. During the test, annotate each test one by one. When reviewing later, just look at the recorded html.

 

Let’s sort out my notes on reading Zhang Rongming’s "JavaScript Design Patterns", just the content of the first chapter.

The most important feature of this book is to start from the actual needs of the work. I don't know how to talk about theory. It is also my favorite way to combine theory with practice.

 

"JavaScript Design Patterns" Reading Notes Chapter 1: Flexible js

This chapter is mainly based on a simple login verification as the requirements, and continuously optimizes the code implementation.

The optimization path is as follows:

Global function="local variable function="object="class="prototype definition="chained definition and call

<script>
  //登录的需求
  //1.1 定义函数实现,导致新创建3个全局变量
  function checkName(){
    console.log("验证姓名")
  }

  function checkEmail(){
    console.log("验证邮箱")
  }

  function checkPassword(){
    console.log("验证密码")
  }

  //1.2 函数的另一种形式
  //优化:局部变量代替全局变量(函数也是变量),避免全局同名方法覆盖。
  var checkName=function(){
    console.log("验证姓名")
  }

  var checkEmail=function(){
    console.log("验证邮箱")
  }

  var checkPassword=function(){
    console.log("验证密码")
  }

  //1.3用对象收编变量
  //减少覆盖或被覆盖的风险,一旦被覆盖,所有功能都会失效,出错现象比较明显,方便错误定位。
  var checkObject={
    checkName:function(){
      console.log("验证姓名")
    },

    checkEmail:function(){
      console.log("验证邮箱")
    },

    checkPassword:function(){
      console.log("验证密码")
    }
  }

  //对象使用
  checkObject.checkName()

  //1.4对象的另一种形式
  //函数也是对象,给对象添加方法。下面这种方式 checkObject 在使用 new 关键字创建新对象时,新创建的对象不能继承 checkName 这些方法。即对象不能复用。
  //var newFn=new checkObject()
  //newFn.checkName() //newFn.checkName is not a function

  var checkObject=function(){}

  checkObject.checkName=function(){
    console.log("验证姓名")
  }

  checkObject.checkEmail=function(){
    console.log("验证邮箱")
  }

  checkObject.checkPassword=function(){
    console.log("验证密码")
  }

  //函数使用
  checkObject.checkName()

  //1.5真假对象
  //对象复用 将方法放在一个函数对象中,每次调用返回一个新对象,互不影响。
  var checkObject=function(){
    return{
      checkName:function(val){
        console.log("验证姓名")
        console.log(val)
      },

      checkEmail:function(){
        console.log("验证邮箱")
      },

      checkPassword:function(){
        console.log("验证密码")
      }
    }
  }

  //使用
  var a=checkObject()
  a.checkName(val);

  //1.6类也可以
  // ES 5 没有 class 关键字,所以使用函数来模拟类。生成实例的时候,使用new关键字。类的属性和方法,还可以定义在构造函数的prototype对象之上。

  //构造函数使用全局作用域
  var scope = "global";
  function constructFun(){
      var scope = "local";
      //构造函数可以是匿名的,可以传入任意数量的字符串实参,最后一个实参是函数体。
      return new Function("return scope");//无法捕捉局部作用域
  }

  var rel = constructFun()();
  console.log(rel);//global 全局没有定义scope,则返回scope is not defined

  // ES 6 中的类,使用class关键字,是原型继承的一种语法糖。

  var checkObject=function(){
    this.checkName=function(){
      console.log("验证姓名")
    }

    this.checkEmail=function(){
      console.log("验证邮箱")
    }

    this.checkPassword=function(){
      console.log("验证密码")
    }
  }

  //使用
  //用关键字 new 创建类
  var a= new checkObject()
  a.checkName();

  //1.7 一个检测类
  //通过 this 定义函数内部的方法,使用new新创建的对象都会对类上的this上的属性进行复制,所以新创建的对象都有自己的一套方法。
  //这么做比较消耗,可以优化,将方法绑定在 checkObject 对象的原型上,这样,新创建的对象所拥有的方法就都是一个了,因为它们都依赖 prototype 原型依次寻找,找到的方法都是同一个。
  var checkObject=function(){}

  //写法一

  checkObject.prototype.checkName=function(){
      console.log("验证姓名")
  }

  checkObject.prototype.checkEmail=function(){
      console.log("验证邮箱")
  }

  checkObject.prototype.checkPassword=function(){
      console.log("验证密码")
  }

  //写法优化
  //写法二

  checkObject.prototype={
    checkName:function(){
      console.log("验证姓名")
    },

    checkEmail:function(){
      console.log("验证邮箱")
    },

    checkPassword:function(){
      console.log("验证密码")
    }
  }

  //注意:以上两种方式不能混写
  //如下混写:后定义的 checkObject.prototype 会整个覆盖先定义的 checkObject.prototype
  var checkObject=function(){}

  checkObject.prototype.checkName=function(){
      console.log("验证姓名 先定义")
  }

  checkObject.prototype.checkEmail=function(){
      console.log("验证邮箱 先定义")
  }

  checkObject.prototype={
    checkEmail:function(){
      console.log("验证邮箱 后定义")
    },

    checkPassword:function(){
      console.log("验证密码")
    }
  }

  //测试
  var a =new checkObject();
  a.checkName();//a.checkName is not a function
  a.checkEmail();//验证邮箱 后定义
  a.checkPassword();

  //使用
  var a =new checkObject();
  a.checkName();
  a.checkEmail();
  a.checkPassword();

  //1.8方法还可以这样用
  //以上使用方法,调用了3个方法,对象a书写了3遍。
  //优化:每个方法的末尾,返回当前对象 this ,这样可以使用链式调用。

  //优化对象
  var checkObject={
    checkName:function(){
      console.log("验证姓名")
      return this
    },

    checkEmail:function(){
      console.log("验证邮箱")
      return this
    },

    checkPassword:function(){
      console.log("验证密码")
      return this
    }
  }

  //使用
  checkObject.checkName().checkEmail().checkPassword()

  //优化类
  var checkObject=function(){}

  checkObject.prototype={
    checkName:function(){
      console.log("验证姓名")
      return this
    },

    checkEmail:function(){
      console.log("验证邮箱")
      return this
    },

    checkPassword:function(){
      console.log("验证密码")
      return this
    }
  }

  //使用类 需要先创建一下
  var a =new checkObject();
  a.checkName().checkEmail().checkPassword();

  //1.9函数的祖先
  //prototype.js 
  //扩展原生对象 
  Function.prototype.checkEmail=function(){
    console.log("验证邮箱")
  }

  //使用
  //函数形式
  var f=function(){}
  f.checkEmail();

  //类的形式
  var f=new Function()
  f.checkEmail();

  //这样做会污染原生对象 Function
  //优化:抽象出一个统一添加方法的功能
  Function.prototype.addMethod=function(name,fn){
    this[name]=fn;
  }

  //使用
  var methods=function(){};
  //或
  var methods=new Function();

  methods.addMethod('checkName',function(){console.log("验证姓名")})
  methods.addMethod('checkEmail',function(){console.log("验证邮箱")})

  methods.checkName();
  methods.checkEmail();

  //1.10链式添加和调用
  //函数式调用
  Function.prototype.addMethod=function(name,fn){
    //注意
    this[name]=fn;
    return this;
  }

  //使用 
  var methods=function(){};

  methods.addMethod('checkName',function(){
    console.log("验证姓名")
    return this;
  }).addMethod('checkEmail',function(){
    console.log("验证邮箱")
    return this;
  })

  //函数式调用
  methods.checkName().checkEmail();

  //1.11换一种方式使用方法
  //为了类式调用改造方法
  Function.prototype.addMethod=function(name,fn){
    //注意
    this.prototype[name]=fn;
    return this;
  }

  //使用
  var methods=function(){};

  methods.addMethod('checkName',function(){
    console.log("验证姓名")
    return this;
  }).addMethod('checkEmail',function(){
    console.log("验证邮箱")
    return this;
  })

  //类式调用
  var m=new methods();
  m.checkName().checkEmail();

  //课后作业
  //1、真假对象(1.5)中如何实现方法的链式调用

  var checkObject=function(){
    return{
      checkName:function(){
        console.log("验证姓名")
        //undo:为什么这里的this指 checkName 的父级对象,而不是 checkName 本身。
        return this
      },

      checkEmail:function(){
        console.log("验证邮箱")
        return this
      },

      checkPassword:function(){
        console.log("验证密码")
        return this
      }
    }
  }

  //使用
  var a=checkObject()
  a.checkName().checkEmail().checkPassword();

  //2、定义一个可以为函数添加多个方法的 addMethod 方法

  var arr=[
    {
      name:'checkName',
      fn:function(){
        console.log("验证姓名")
        return this;
      }
    },
    {
      name:'checkEmail',
      fn:function(){
        console.log("验证邮箱")
        return this;
      }
    }
  ];

  Function.prototype.addMethod=function(arr){
    arr.forEach(item => {
      this[item.name]=item.fn;
    });
    return this;
  }

  //使用 
  var methods=function(){};

  methods.addMethod(arr)

  //函数式调用
  methods.checkName().checkEmail();


  //3、定义一个既可以为函数原型添加方法,又可以为其自身添加方法的 addMethod 方法
  var arr=[
    {
      name:'checkName',
      isPrototype:true,
      fn:function(){
        console.log("验证姓名")
        return this;
      }
    },
    {
      name:'checkEmail',
      isPrototype:false,
      fn:function(){
        console.log("验证邮箱")
        return this;
      }
    }
  ];

  //为了方便测试,引入fn2参数,实际使用去掉即可。
  Function.prototype.addMethod=function(arr,fn1,fn2){
    arr.forEach(item => {
      if(item.isPrototype){
        //为函数原型添加方法
        this[item.name]=item.fn;
      }else{
        //为其自身添加方法
        fn1[item.name]=item.fn;
      }
    })
  }

  //使用 
  var fn1=function(){};
  var fn2=function(){};

  fn1.addMethod(arr,fn1,fn2);
  fn2.addMethod(arr,fn1,fn2);

  //函数式调用
  fn1.checkName().checkEmail();
  fn2.checkName();
  fn2.checkEmail();//fn2.checkEmail is not a function
</script>

 

Guess you like

Origin blog.csdn.net/Irene1991/article/details/115381059