js创建对象的几种方式(工厂模式、构造函数模式、原型模式)

普通方法创建对象

var obj = {
name:"猪八戒",
sayname:function () {
alert(this.name);
}
}

var obj1 = {
name:"沙和尚",
sayname:function () {
alert(this.name);
}
}

var obj2 = {
name:"孙悟空",
sayname:function () {
alert(this.name);
}
}
obj.sayname()
obj1.sayname()
obj2.sayname()

使用工厂方法创建一个对象

通过该方法可以大批量创建新对象

函数ren(name,gender)能够根据接受的参数来构建一个包含所有必要信息的 Person 对象。可以无数次地调用这个函数,而每次它都会返回一个包含三个属性一个方法的对象。工厂模式虽然解决了创建\多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。 

  主要好处就是可以消除对象间的耦合,通过使用工程方法而不是new关键字。将所有实例化的代码集中在一个位置防止代码重复。

  工厂模式解决了重复实例化的问题 ,但还有一个问题,那就是识别问题,因为根本无法 搞清楚他们到底是哪个对象的实例

function ren(name,gender) {
var dx = new Object();
dx.name = name,
dx.gender = gender,
dx.sayname = function(){
console.log(this.name)
};00                          
return dx;
}
var a = ren("悟空","")
a.sayname()

构造函数

创建一个Person构造函数
在person构造函数中,为每一个对象都添加一个sayname的方法
目前我们的方法是在构造函内部创建的每执行一次就会创建一个新的方法
也就是说构造函数每执行一次就会创建一个新的sayname方法
也是所有实例都是唯一的,这样就导致了构造函数每执行一次就会创建一个新的方法
执行一千次就会创建一千个新的方法这是完全没有必要的,完全可以使用同一个方法

function Person(name){
this.name = name,
this.sayname = fun    
}
function fun(){
console.log(this.name);
}
var per = new Person("旺财");
var per1 = new Person("王竹");
var per2 = new Person("理想");
console.log(per.sayname == per2.sayname);//返回true

原型

将sayname方法在全局作用域中定义
将函数定义在全局作用域中就会污染了全局作用域的命名空间,而且定义在全局作用域中也很不安全
我们所创建每一个函数我们的解析器都会响函数中添加一个属性prototype
这个属性对应这一个对象,这个对象就是我们所谓的原型对象
如果函数作为普通函数调用prototype没有任何作用,当函数通过构造函数调用时他所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象中
我们可以通过__proto__来访问该属性
原型对象相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象
我们可以将对象中共有的内容,统一设置到原型对象之中,当我们访问对象的一个属性时,他会在对象自身中寻找有的话直接使用,没有的话去原型里面找
以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中
这样就不用分别为每一个对象,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了

//            创建一个构造函数
            function MyClass(){                                
                }
            MyClass.prototype.a = "我是原型中的名字";
            var mc = new MyClass();
            mc.a = "我是对象中的名字"
//            使用in检查对象中含有某个属性时,如果对象中没有但是原型中有,也会返回true
            console.log("a" in mc);
            
//            可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性值
//            使用该方法时只有当对象自身中含有该方法时返回true
            console.log(mc.hasOwnProperty("name"))//返回false
            console.log(mc.hasOwnProperty("hasOwnProperty"));
//            原型也是对象.所以他也有原型
//                当我们使用一个对象的属性时或方法时,会在自身中寻找,自身中有,直接使用,如果没有去原型的原型中寻找
            console.log(mc.hasOwnProperty);
            console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));
//            原型的原型中的原型会返回null
//            如果没有就去原型中的原型寻找直到找到object的原型,obj对象的原型没有原型,如果在obj中依然没有找到,则返回undefined
            console.log(mc.__proto__.__proto__.__proto__);
            console.log(mc.__proto__);

 

原型图例

 

 

 

 

构造函数原型toString();方法

function Person(name ,age , gender) {    this.name = name;
this.age = age;
this.gender = gender;    
}
//    创建一个Person实例
var per = new Person("宁缺",18,"");
var per2 = new Person("佩奇",56,"");
Person.prototype.toString = function() {
return "Person[姓名:"+this.name+"年龄:"+this.age+"性别:"+this.gender+"]";

}
//    当我们直接在页面中打印一个对象时,实际上是输出对象的toString()方法的返回值
//    var result = per.toString(); 
//    console.log("result = " + result);
console.log(per);
console.log(per2);
//    per对象自己本身没有toString的方法,只有per原型中的原型会有这个方法,但是返回的值就是"[object Object]"
//    console.log(per.__proto__.__proto__.hasOwnProperty("toString"));//返回true
//    那么我们想查看per中的值就要给per的原型添加一个方法用来覆盖掉原型中的原型返回值

 

posted @ 2019-12-08 21:16  牛耀民  阅读(784)  评论(0编辑  收藏  举报