javascript 中常见的创建对象的几种方式:
1. 使用Object构造函数创建;
使用Object构造函数来创建一个对象,下面代码创建了一个person对象,并用两种方式打印出了Name的属性值。
var person = new Object(); person.name="kevin"; person.age=31; alert(person.name); alert(person["name"])
2. 使用对象字面量创建一个对象;
var person ={name:"Kevin",age:31,5:"Test" }; alert(person.name); alert(person["5"]);
3. 使用工厂模式创建对象;
返回带有属性和方法的person对象。
function createPerson(name, age,job){var o = new Object();o.name=name;o.age=31;o.sayName=function(){alert(this.name);};return o; } createPerson("kevin",31,"se").sayName();
用函数来封装以特定接口创建对象的细节,解决了创建多个相似对象的问题,但是没有解决对象识别的问题(怎么知道一个对象的类型)。
4. 使用自定义构造函数模式创建对象;
这里注意命名规范,作为构造函数的函数首字母要大写,以区别其它函数。这种方式有个缺陷是sayName这个方法,它的每个实例都是指向不同的函数实例,而不是同一个。构造函数模式,构造函数添加属性和方法,使用的时候new一个自定义的对象
function Person(name,age,job) {this.name=name;this.age=age;this.job=job;this.sayName=function(){alert(this.name);}; }var person = new Person("kevin",31,"SE"); person.sayName();
new一个构造函数的内部操作步骤:
1)、创建一个新对象;
2)、将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
3)、执行构造函数中的代码;
4)、返回新对象。
使用构造函数创建的实例,都会有一个constructor属性,指向构造函数。
创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型。这正是胜过工厂模式的地方。
与普通函数的区别在于new调用,不用new来调用,与普通函数无差。
不使用new调用的时候,就相当于window调用了构造函数,属性和方法都被添加到了window对象上去。
也可以这样使用:(call就是为了改变上下文环境而生)
var o = new Object(); Person.call(o,"Dadaoshenyi",25,"Enginner"); o.sayName();//"Dadaoshenyi"
构造函数创建对象的问题:每个方法都要在实例上重写一遍。由于函数也是对象,因此每次定义一个函数,也就实例化了一个对象。
5. 使用原型模式创建对象;
解决了方法4中提到的缺陷,使不同的对象的函数(如sayFriends)指向了同一个函数。
但它本身也有缺陷,就是实例共享了引用类型friends,从下面的代码执行结果可以看到,两个实例的friends的值是一样的,这可能不是我们所期望的。原型模式,定义构造函数,构造函数原型上添加属性和方法。
function Person(){}Person.prototype = {constructor : Person,name:"kevin",age:31,job:"SE",friends:["Jams","Martin"],sayFriends:function(){alert(this.friends);} }; var person1 = new Person(); person1.friends.push("Joe"); person1.sayFriends();//Jams,Martin,Joe var person2 = new Person(); person2.sayFriends();//James,Martin,Joe
构造函数的原型||对象实例的内部指针([[Prototype(__proto__)]]指向Person.prototype)。
实例对象的内部指针指向构造函数的原型。
原型模式的优点:自定义的构造函数,可以让所有的对象实例共享原型对象所包含的属性和方法。原生的引用类型也是采用这种模式。
问题在于:1、省略了构造函数传递参数的步骤。2、所有实例共享方法和属性,这样,实例修改原来的属性或者方法,将会在所有的实例上表现出来。被捆绑到了一起。只是一个引用,不是一个副本。
6. 组合使用原型模式和构造函数创建对象;
解决了方法5中提到的缺陷,而且这也是使用最广泛、认同度最高的创建对象的方法。组合使用构造函数模式和原型模式,最常用的一种模式。
function Person(name,age,job) {this.name=name;this.age=age;this.job=job;
this.friends=["Jams","Martin"]; } Person.prototype.sayFriends=function() {alert(this.friends); };
var person1 = new Person("kevin",31,"SE"); var person2 = new Person("Tom",30,"SE"); person1.friends.push("Joe"); person1.sayFriends();//Jams,Martin,Joe person2.sayFriends();//Jams,Martin
优点:使用构造函数来创建实例属性,且可以修改设定的值。使用原型创建共享方法和共享的属性。最大限度的节省了内存。
7. 动态原型模式;
这个模式的好处在于看起来更像传统的面向对象编程,具有更好的封装性,因为在构造函数里完成了对原型创建。这也是一个推荐的创建对象的方法。动态原型模式,将上面的对象原型方法||属性的创建方法哦了构造函数里面完成。具有更好的封装性。结果是一样的。
function Person(name,age,job) {//属性this.name=name;this.age=age;this.job=job;this.friends=["Jams","Martin"];//方法if(typeof this.sayName != "function"){Person.prototype.sayName=function(){alert(this.name);};Person.prototype.sayFriends=function(){alert(this.friends);};} }var person = new Person("kevin",31,"SE"); person.sayName(); person.sayFriends();
另外还有两个创建对象的方法,寄生构造函数模式和稳妥构造函数模式。由于这两个函数不是特别常用,这里就不给出具体代码了。
写了这么多创建对象的方法,其实真正推荐用的也就是方法6和方法7。当然在真正开发中要根据实际需要进行选择,也许创建的对象根本不需要方法,也就没必要一定要选择它们了。