js中常用模式

1. 工厂模式:函数里面返回单个对象

优点:解决了创建多个相似对象的问题
缺点:没有解决对象识别的问题,即不能识别一个对象属于哪个类型。(在下例中调用factory函数返回的都是object类型的对象,而不是factory类型)

function factory() {
        var args = arguments;
        //实例化对象   返回对象
        var obj = new Object();
        //封装属性以及方法
        obj.name = args[0];
        obj.sex = args[1];
        obj.age = args[2];
        obj.sleep = function () {
            return this.name + "会睡觉";
        }
        return obj;
    }
    var person = factory("毛豆""男"18)var person1 = factory("小黑","女"18);
    console.log(person instanceof factory );//false
2. 构造函数模式:构造函数中的this在未实例化前指代window,实例化之后指当前的对象。

优点:弥补工厂模式中不能识别对象类型的缺陷,可以将构造函数的实例标识为某种特定的类型。(在下例中,调用Person函数返回Person类型的对象)
缺点:构造函数中的每个方法都要在实例中重新创建一次;所有实例的函数和属性都不是共享的,而是独立的。

  function Person() {
        this.name = arguments[0];
        this.sex = arguments[1];
        this.age = arguments[2];
        this.eat = function () {
            return this.name + "会吃饭!";
        }
    }
     var son = new Person("毛豆", "男", 18);
    console.log(son instanceof Person);//true
3. 原型模式:构造函数不能传递参数,可以实现原型属性的共享

优点:解决了构造函数中的每个方法都要在实例上重新创建一遍以及属性和方法不可共享的问题
缺点:在原型中定义属性,将被所有实例共享。由于它的构造函数不可传递参数,故所有实例的属性在默认情况下都将取得相同的值。

function Person() {
}
Person.prototype.name = 'victor';
Person.prototype.age = 20;
Person.prototype.sayName = function(){
   alert(this.name);
};

var person1 = new Person();
person1.sayName(); //'victor'

var person2 = new Person();
person2.sayName(); //'victor'

alert(person1.sayName == person2.sayName); //true
4. 组合使用构造函数模式和原型模式:构造方法模式用于定义属性,而原型模式用于定义方法和共享的属性。

优点:每个实例都会有自己的一份实例属性的副本,但同时有共享着对方发的引用,最大限度地节省了内存。此外还可以向构造函数传递参数。这种模式是当前在EMCAScript中使用最为广泛、认同度最高的一种创建自定义类型的方法,也是一种用来定义引用类型的默认模式。

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.friends = ['Anglea', 'Mike', 'Jecy'];
}
Person.prototype = {
  constructor: Person,
  sayName: function(){
     alert(this.name);
  } 
}
var person1 = new Person('Victor', 20);
var person2 = new Person('Alex', 21);
person1.friends.push('Jack');
alert(person1.friends);//'Angela, Mike, Jecy, Jack'
alert(person2.friends);//'Angela, Mike, Jecy'
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true
5. 动态原型模式:把所有信息都封装在了一个构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型的优点。即可以通过检验某个应该存在的方法是否有效,来决定是否需要初始化原型。

注意:使用动态原型模式时,不能使用对象字面量重写原型。如果已经创建了实例的情况下重写原型,那么就会切断现有实例与新原型之间的联系。但是现有实例仍与重写前的原型有关联。仍可调用其中的方法,但是不可调用新原型中的新增方法,只有当重新创建一个新的实例时才能调用新原型的新增方法。
字面量可分为:字符串字面量、数组字面量、对象字面量、函数字面量

/*在实例后重写原型*/
function Person(name, age, job) {
        //属性
        this.name = name;
        this.age = age;
        this.job = job;
        // 方法
        if(typeof this.sayName != 'function') {
            console.log(111111111)//输出两次,即每次创建对象时都执行了
            Person.prototype.sayName =  function(){
                alert(this.name);
            }
        }
    }
    var friend = new Person('Nicholas', 29, 'Software Engineer');
    Person.prototype = {
        constructor:Person,
        sleep:function (){
            return "会睡觉"
        }
    }//此时friend实例与新原型的联系已被切断。此时新原型中sayName==undefined
    console.log(friend.prototype.sayName);//undefined
    friend.sayName();//虽然friend实例与新原型的联系被切断,但是与旧原型还是有关联,故可以调用sayName方法,但是无法调用sleep方法,只有当再新创建一个实例时才可调用。
      var friend1 = new Person('Alic',30,'Alic')//可调用sleep方法
    console.log(friend1)
/*下面例子中,只有在第一次实例化Person时会给Person.prototype.sayName 赋值,而之后便不会满足if判断*/
 function Person(name, age, job) {
        //属性
        this.name = name;
        this.age = age;
        this.job = job;
        // 方法
        console.log(this.sayName)//第一次打印结果为undefind,第二次打印结果为函数
        if(typeof this.sayName != 'function') {
            Person.prototype.sayName =  function(){
               console.log(this.name)
            }
        }
    }
    var friend = new Person('Nicholas', 29, 'Software Engineer');
    var friend1 = new Person('1', 29, 'Software Engineer');
字面量:一般赋值的内容被称作字面量
var test="hello world!";//"hello world!"就是字符串字面量,test是变量名。
var obj = {
	"name":"zhang",
	"age":18
}//等式右边为字面量

6. 单例模式:一个类仅有一个实例,并且提供一个访问它的全局访问点

在下面示例中:getInstance 方法为Singleton类的静态方法,当想要获得Singleton实例时,可调用该方法。由于单例模式的特点,故无论多少次获得实例,得到的对象都是相同的

优点:(1) 由于单例模式在内存中只有一个实例,减少内存开支,特别是一个对象需要频繁地创建销毁时,而且创建或销毁时性能又无法优化,单例模式就非常明显了
(2) 由于单例模式只生成一个实例,所以,减少系统的性能开销,当一个对象产生需要比较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
(3) 单例模式可以避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作
(4) 单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如,可以设计一个单例类,负责所有数据表的映射处理。
缺点:单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。

var Singleton = function(name) {
        this.name = name;
    }
    Singleton.getInstance = (function(name){
        var instance;
        return function(name) {
            if (!instance) {
                instance = new Singleton(name);
            }
            return instance
        }
    })();

    var a = Singleton.getInstance('seven1');
    var b = Singleton.getInstance('seven2');
    console.log(a===b);//true
7. 模块模式:模块模式是一种解决软件中私有和公有的封装问题的方法。通过这种模式,我们不仅可以解决公有/私有变量和方法封装的问题,还可以大大降低命名冲突的概率。
var myNameSpace = (function() {
	// 私有变量
	var privateVar = 0
	// 私有方法
	var privateMethod = function(foo) {
		console.log(foo)
	}
	return {
		// 公有变量
		publicVar: 'foo',
		// 公有方法
		publicMethod: function(bar) {
			// 修改私有变量
			privateVar++
			// 调用私有方法
			privateMethod(bar)
		}
	}
})()

// 使用
console.log(myNameSpace.publicVar)
myNameSpace.publicMethod('bar')

参考文章

  1. https://blog.csdn.net/lijizhi19950123/article/details/78150213/
  2. https://blog.csdn.net/itpinpai/article/details/71254371
  3. http://ife.baidu.com/note/detail/id/3159
  4. https://blog.csdn.net/userkang/article/details/86681320
发布了72 篇原创文章 · 获赞 72 · 访问量 6340

猜你喜欢

转载自blog.csdn.net/weixin_43314846/article/details/100528860