最近发现了一种新的学习方式(或者写笔记的方式),感觉很方便。
在 html 中记录,主要是方便写 js 代码,然后以注释的方式写知识点。
因为会有很多同名函数和变量,所以测试代码文件另写另测试。
这样可以一边记录,一边有针对性的测试。测试不会打断记录,测试中,测试一个注释一个。后面回顾的时候,只看记录的 html 即可。
下面就整理下我读 张容铭 的 《JavaScript 设计模式》的笔记吧,只是第一章的内容。
这本书最大的特点就是从工作实际需求出发吧,不会干讲理论,理论结合实践,也是我喜欢的方式。
《JavaScript 设计模式》阅读笔记之第一章:灵活的js
这章主要是以一个简单的登录验证做需求,不断优化代码实现。
优化路径如下:
全局函数=》局部变量函数=》对象=》类=》原型定义=》链式定义和调用
<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>