js创建对象的几种方法

时间:2021-06-28 22:44:07

1、对象字面量创建单个对象

  这个方式有明显的优缺点:目的是简化创建包含大量属性的对象,但是每个对象的值都是固定的.为了解决这个问题,出现了工厂模式。


//字面量创建
var people=
{
 name:'许涛',
 age:'12'
}
//使用Object.create()创建对象,该方法非常有用,因为它允许你为创建的对象选择其原型对象,而不用定义一个构造函数。
//语法:Object.create(proto, [propertiesObject])
const me=Object.create(people);
console.log(me.name);

proto:新创建对象的原型对象;

propertiesObject:要添加到新创建对象的可枚举属性对象的属性描述符以及相应的属性名称

如果 proto 参数不是 null 或一个对象值,则抛出一个 TypeError 异常。

2、工厂模式

  在ECMAScript中无法创建类(ES6前),开发人员发明了一种函数,用函数来封装创建对象的细节。(实现起来是在一个函数内创建好对象,然后把对象返回)。


function Person(name,age){
   var o=new Object();
   o.name=name;
   o.age=age;
   o.sayName=function(){
       alert(this.name);
  };
   return 0;
}

var p1=Person("海燕",29);
var p2=Person("涛",27);

  函数Person()能够根据接受的参数来构建一个包含所有必要信息的Person对象。工厂模式虽然解决了创建多个相似对象的问题,但却没有解决具体是那个对象的问题,也就是这个对象的类型。随着JS发展,又一个模式出现了。

3、构造函数模式

  像Object和Array这样的原生构造函数,在运行时会自动出现在执行环境。此外,也可以创建自定义的构造函数,从而自定义对象类型的属性和方法。

function Person(name,age){
   this.name=name;
   this.age=age;
   this.sayName=function(){
       console.log(this.name);
  };
}

var p1=new Person();
var p2=new Person();
console.log(p1 instanceof Person)//检测p1是否在Person的原型链上;

与工厂模式相比,具有以下特点:

  1. 工厂函数需要创建对象,以及必须有返回值

  2. 直接将属性和方法赋给了this对象;

  3. 工厂函数针对的都是Object的对象模型,而构造函数可以匹配自定义的对象模型

    即前者不论创建什么都只有一个xx instanceof Object

  4. 要创建新实例,必须使用new操作符;(否则属性和方法将会被添加到window对象)

  5. 可以使用instanceof操作符检测对象类型


//判断是否是他的父类;
function Person(){};
function Student(){};
var p =new Person();
Student.prototype=p;//继承原型
var s=new Student();
console.log(s instanceof Student);//true
console.log(s instanceof Person);//true

  构造函数弊端 :

1.如果在全局中定义相同的局部变量,容易造成全局污染,因为this.xx如果在局部获取不到,就会去全局中获取 .

2.构造函数内部的方法会被重复创建,不同实例内的同名函数是不相等的。可通过将方法移到构造函数外部解决这一问题,但面临新问题:封装性不好。(原型函数就来咯)

3.构造函数可以重写,可以在全局中添加新属性和方法Person.prototype = {},但工厂函数只能在局部添加

Person.prototype.sayHello=function(){
   console.log("hello");
}//使用原型prototype创建对象

适用场合:

  构造函数:适应用于大型项目,属性以及方法时常变换的项目

  工厂函数:适应用于小型项目,或者正在制作过程还没有成型的项目

4、原型模式创建对象

  当我们创建了一个函数,就会为这个函数创建一个prototype(原型)属性,这个属性指向函数的原型对象 ,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。(prototype就是通过调用构造函数而创建的那个对象实例的原型对象)。

当调用构造函数创建一个实例后,这个实例包含一个指针,指针指向函数的原型对象。这个指针叫[[prototype]]

  使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。换句话说,不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。

function Person(){
}

Person.prototype.name="海燕";
Person.prototype.age=23;
Person.prototype.sayName=function(){
   console.log(this.name);
};
var p1=new Person();
p1.sayName();

  更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象,并重设constructor属性。

function Person(){
}

Person.prototype={
   name:"海燕",
   age:23,
   sayName:function(){
       console.log(this.name);
  }
};

Object.defineProperty(Person.prototype,"constructor",{
   enumerable:false,
   value:Person,
});

  原型对象的问题

1.但是原型模式也有自己缺点,他省略了为构造函数传递参数这个环节。结果所有实例默认情况下取得相同的属性值。

2.最大的问题还是共享引起。如果原型中一个属性包含引用类型值。例如一个数组,当通过一个实例往数组里添加一个元素时,就会影响所有的实例。这就是共享导致的。

  这些问题导致很少单独使用原型模式。

5、组合使用构造函数模式和原型模式

  这是创建自定义类型的最常见的方式。

  构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。所以每个实例都会有自己的一份实例属性的副本,但同时共享着对方法的引用,最大限度的节省了内存。同时支持向构造函数传递参数。

function Person(name,age){//构造函数模式,定义实例属性.
   this.name=name;
   this.age=age;
}
Person.prototype={//原型模式定义方法和共享属性.
   constructor:Person,
   sayName:function(){
       alert(this.name);
  }
};

var p1=new Person("海燕",12);

6、动态原型模式

function Person(name,age){
   this.name=name;
   this.age=age;

   if(typeof this.sayName!="function"){
       Person.prototype.sayName=function(){
           alert(this.name);
      };
  }
}

  这里只有sayName()不存在的情况下,才会将它添加到原型中,这段代码只会在初次调用构造函数时才执行。这里对原型所做的修改,能够立刻在所有实例中得到反映。

7、Object.create()

参考第一个模式;

  ES5定义了一个名为Object.create()的方法,它创建一个新对象,其中第一个参数是这个对象的原型,第二个参数对对象的属性进行进一步描述。

8.寄生构造函数:

寄生构造函数和工厂模式的区别:没有本质上的区别,通过new操作符的就是寄生构造模式,直接调用的是工厂模式


function Person(name,age){
   var o=new Object();
   o.name=name;
   o.age=age;
   
   o.getnum=function(){
       console.log(this.name);
  }
   return o;
}
var p1=new Person();//加一个new就是寄生构造函数,直接调用就是工厂

寄生构造函数使用场景:

我们定义一个array的引用类型:


var person=new Array("name","age",salary);
alert("person");
//打印结果是,隔开.如果我不想用他隔开可以使用join()方法,但是每个都要使用join()就比较麻烦,可以改变Array数组的默认定义输出方式.
//类似Object,Array,Date等等的拥有原生构造函数的引用类型并不能直接修改其原生构造函数,那么此时寄生构造函数就派上用场了。
function SpacialArray(){
   //创建数组
   var array=new Array();
   //添加值
   array.push.apply(values,arguments);
   //添加方法
   array.toPipedString=function(){
       return this.join(".")
  }
   //返回数组
   return array;
}
var a=new SpacialArray("海燕","杨涛");
alert(a.toPipedString());

 综上所述,其实寄生构造函数就是在原生构造函数上的一个扩展,也就是你可以利用寄生构造函数来自定义一种引用类型,实现自己想要达到的效果。

9.稳妥构造函数模式:

首先明白稳妥对象指的是没有公共属性,而且其方法也不引用this。稳妥对象最适合在一些安全环境中(这些环境会禁止使用this和new),或防止数据被其他应用程序改动时使用稳妥构造函数模式和寄生模式类似,有两点不同:一是创建对象的实例方法不引用this,而是不使用new操作符调用构造函数


function Person(name,age){
   var o=new Object();
   o.name=name;
   o.age=age;
   o.sayhello=function(){
       console.log("hello")
  }
   return o;
}
var p1=new Person("海燕",23);
p1.sayhello();

转载:https://www.cnblogs.com/zczhangcui/p/6389023.html;