单例模式

单例模式:
是一种项目开发中经常使用的模式,因为项目中我们可以使用单例模式来进行我们的"模块开发"

"模块化开发":
对于一个相对来说比较大的项目,需要多人协作的开发,我们一般情况下会根据当前项目的需求划分为几个功能板块,每个人负责一部分,同时开发,最后把每个人的代码进行合并

比如:

  • 公共模块
var utils = {
    select: function(){
    
    }
}
  • 页卡模块中的change->实现选项卡切换
var tabRender = {
    change: function(){
        utils.select(); // 在自己的名命空间下调用其他名命空间的方法
    }
}

+搜索模块change->搜索内容变化处理的

var searchRender = {
    change: function (){
        this..clickEven(); // 在自己的名命空间下调用自己名命空间的方法
    }
    clickEvent: function(){
    
    }
}

工厂模式

单例模式虽然解决了分组的作用,但是不能实现批量的生产,属于手工作业模式
函数的封装:
把实现同一件事情的相同的代码放到一个函数中,以后如果在想实现这个功能,不需要从新的编写这些代码了,只需要执行当前的函数即可
低耦合高内聚:
减少页面中冗余代码,提高代码的重复利用率

function createJsPerson(name, age){
    var obj = {};
    obj.name = name;
    obj.age = age;
    obj.writeJS = function(){
        console.log("my name is " + this.name + ", i can                write js ~~")
    }
    return obj;
}

var p1 = createJsPerson("lemon1", 21)
var p2 = createJsPerson("lemon2", 22)

js中不存在重载,方法名一样的话,后面的会把前面的覆盖掉,最后只保留一个

function sum(num){
    if(typeof num === "undefined"){
        return 0; 
    }
    return num;
} 
sum(100);
sum(0)

构造函数模式

构造函数模式的目的就是为了创建一个自定义类,并且创建这个类的实例

function CreateJsPerson(name, age){
    this.name = name;
    this.age = age;
    this.writeJS = function(){
        console.log("my name is " + this.name + ", i can                write js ~~")
    }
}

var p1 = new CreateJsPerson("lemon1", 21)
var p2 = new CreateJsPerson("lemon2", 22)

构造函数和工厂模式的区别
执行的时候

  • 普通函数执行->createJsPerson()
  • 构造函数模式->new CreateJsPerson(), 通过new执行后,createJsPerson就是一个类了,而函数执行的返回值(p1)就是CreateJsPerson这个类的一个实例)

在函数代码执行的时候

  • 相同:都是形成一个私有的作用域,然后形参赋值->解释->代码从上到下执行
  • 不同:在代码执行之前,不用自己手动创建对象了,浏览器会默认创建一个对象的数据类型的值,这个对象其实就是我们当前类的一个实例
    接下来,代码从上到下执行,以当前的实例为执行的主体,this代表的就是当前的实例
    最后浏览器会默认的把创建的实例返回

JS中所有的类都是函数数据类型的,它通过new执行变成了一个类,但是它本身也是一个普通的函数

JS中所有的实例都死对象数据类型的

p1和p2都是CreateJsPerson这个类的实例,所以都拥有writeJs这个方法,但是不同实例之间的方法是不一样的
在类中给实例增加的属性(this.xxx = xxx)属于当前实例的私有的属性,实例和实例之间单独的个体,所以私有的属性之间是不相等的

console.log(p1.writeJs === p2.writeJs); 

->false


this问题

var name = ""
var res = CreateJsPerson('-lemon', -22);
console.log(name);
console.log(age)

-> '-lemon'
-> -22

这样写不是构造函数模式执行而是普通的函数执行,由于没有写return所以res = undefined, 并且CreateJsPerson这个方法中的this是window

构造函数模式(扩展)

function Fn(){
    this.x = 100;
    this.getX = function(){
        console.log(this.x)
    }
}
var f1 = new Fn;
f1.getX(); // 方法中的this是f1 100
var ss = f1.getX;
ss(); // 方法中的this是window undefined
  • 在构造函数模式中new Fn()执行, 如果Fn不需要传递参数的话, 后面的小括号可以省略
  • this的问题:在类中出现的this.xxx = xxx 中的this都是当前类的实例,而某一个属性值(方法),方法中的this需要看方法执行的时候,前面是否有"."才能知道this是谁
  • 类有普通函数的一面,当函数执行的时候, var num其实只是当前形成的私有作用域中的私有变量而已, 它和f1这个实例没有任何关系.只有this.xxx = xxx才相当于给f1这个实例增加私有的属性和方法,才和我们的f1有关系
function Fn(){
    var num = 10;
    this.x = 100;
    this.getX = function(){
        console.log(this.x)
    }
}
var f1 = new Fn;
console.log(f1.num); // -> undefined
  • 在构造函数模式中,浏览器会默认的把我们的实例返回(返回的是一个对象数据类型的值),如果我们自己手动写了return返回:

返回的是一个基本数据类型的值,当前实例是不变的,例如: return 100;

返回的是一个引用数据类型的值,当前的实例会被自己返回的值替换掉,例如: return {name: 'lemon'}, 我们的f1就不在是Fn的实例了,而是对象 {name: 'lemon'}

function Fn(){
    var num = 10;
    this.x = 100;
    this.getX = function(){
        console.log(this.x)
    }
    return {name: 'lemon', age: 22};
}
var f1 = new Fn;
console.log(f1); //  {name: 'lemon', age: 22}
function Fn(){
    var num = 10;
    this.x = 100;
    this.getX = function(){
        console.log(this.x)
    }
    return 100;
}
var f1 = new Fn;
console.log(f1); // 不变

检测属性

  • 检测某一个实例是否属于这个类
console.log(f1 instanceof Fn); // -> true
console.log(f1 instanceof Array); // -> true
  • f1和f2都是Fn这个类的一个实例,都拥有x和getX两个属性,但是这两个属性都是各自都属性,所以
console.log(f1.getX === f2.getX); // -> false
  • in 检测某一个属性是否属于这个对象(attr in object), 不管是私有的属性还是公有的属性, 只要存在, 用in来检测都是true
console.log("getX" in f1); // -> true
  • hasOwnProperty: 用来检测某一个属性是否为这个对象的"私有属性",这个方法只能检测私有的属性
console.log(f1.hasOwnProperty("getX")); // -> true
  • isPrototypeOf: 用来判断指定对象object1是否存在于另一个对象object2的原型链中,是则返回true,否则返回false
object1.isPrototypeOf(object2);

如果object2的原型链中包含object1,那么isPrototypeOf方法返回true
如果object2不是一个对象或者object1没有出现在object2中的原型链中,isPrototypeOf方法将返回false.