在JavaScript中创建对象的方法有很多种。也可以通过对象构造函数或对象字面量创建单个对象。很明显,这两种方式都会产生大量的重复代码,不适合批量化。生产。接下来,我们将介绍七种非常经典的对象创建方式,每一种方式都各有优缺点。工厂模式functioncreatePerson(name,job){varo=newObject()o.name=nameo.job=jobo.sayName=function(){console.log(this.name)}returno}varperson1=createPerson('蒋','student')varperson2=createPerson('X','Doctor')可以无数次调用这个工厂函数,每次都会返回一个包含两个属性和一个方法的对象。工厂模式虽然解决了创建多个相似对象的问题,但是没有解决对象识别的问题,即你无法知道一个对象的类型。构造函数模式functionPerson(name,job){this.name=namethis.job=jobthis.sayName=function(){console.log(this.name)}}varperson1=newPerson('Jiang','student')varperson2=newPerson('X','Doctor')没有创建对象显示,使用new调用这个构造函数,使用new之后会自动执行下面的操作来创建一个新对象这个新对象会被执行[[prototype]]linkThisnewobjectwillbeboundtothethisofthefunctioncalltoreturnthisobject使用此方法创建对象可以检测到对象类型person1instanceofObject//trueperson1instanceofPerson//true但是使用构造函数创建对象,每次每次方法必须在每个实例上重新创建原型模式}varperson1=newPerson()直接向原型对象添加信息。使用原型的好处是所有实例对象都可以共享它包含的属性和方法,而不必在构造函数中定义对象实例信息。原型是一个非常重要的概念。在一篇了解proto和prototype的关系和区别的文章中,讲的很详细,也比较简单。functionPerson(){}Person.prototype={name:'jiang',job:'student',sayName:function(){console.log(this.name)}}varperson1=newPerson()设置Person.prototype等于一个作为对象文字创建的对象,但导致.constructor不再指向Person。这样就完全重写了默认的Person.prototype对象,所以这里不会存在.constructorPerson.prototype.constructor===Person//false如果需要这个属性,可以手动添加functionPerson(){}Person。prototype={constructor:Personname:'jiang',job:'student',sayName:function(){console.log(this.name)}}不过这个方法不够好,应该是因为constructor属性是默认禁用enumerable,所以直接设置,就可以enumerable了。所以在可能的情况下,Object.defineProperty方法Object.defineProperty(Person.prototype,'constructor',{enumerable:false,value:Person})有使用原型的缺点,所有属性都会共享。这是一个很大的优点,同样也会带来一些缺点。原型中的所有属性实例由许多实例共享。这个分享很适合做函数。那些包含基本值的属性也几乎不可能。毕竟实例属性可以屏蔽原型属性。但是引用类型值,就会有问题.friends.push('Van')console.log(person1.friends)//["Shelby","Court","Van"]console.log(person2.friends)//["Shelby","Court","Van"]console.log(person1.friends===person2.friends)//truefriends存在于原型中,实例person1和person2指向同一个原型,person1修改了引用的数组,同样会体现在实例person2的组合使用构造函数模式和原型模式这是使用最广泛和最受认可的创建自定义类型的方法。它可以解决上述模式的不足。使用这种模式允许每个实例都有自己的实例属性副本,但同时共享对方法的引用。这样的话,即使实例属性修改了引用类型的值,也不会影响其他实例的属性值functionPerson(name){this.name=namethis.friends=['Shelby','Court']}Person.prototype.sayName=function(){console.log(this.name)}varperson1=newPerson()varperson2=newPerson()person1.friends.push('Van')console.log(person1.friends)//["Shelby","Court","Van"]console.log(person2.friends)//["Shelby","Court"]console.log(person1.friends===person2.friends)//伪动态原型mode动态原型模式,封装了构造函数中的所有信息。初始化的时候,通过检测一个应该存在的方法来决定是否初始化原型函数Person(name,job){//propertythis.name=namethis.job=job//methodif(typeofthis.sayName!=='function'){Person.prototype.sayName=function(){console.log(this.name)}}}varperson1=newPerson('Jiang','Student')person1.sayName()只会在sayName方法不存在将其添加到原型中。这段代码只会在第一次调用构造函数时执行。至此,原型已经初始化完毕,无需修改。此处对原型所做的修改可以立即反映在所有实例中。其次,if语句可以在初始化后检查任何应该存在的属性或方法,所以没必要用一大堆if语句检查每一个属性和方法,只要检查一个就可以了。寄生构造函数模式的基本思想是创建一个函数,只封装创建对象的代码,然后返回新创建的对象。functionPerson(name,job){varo=newObject()o.name=nameo.job=jobo.sayName=function(){console.log(this.name)}returno}varperson1=newPerson('蒋','学生')person1.sayName()模式,除了使用new操作符和调用wrapper函数作为构造函数外,其他几乎和工厂模式一样。如果构造函数不返回对象,则默认返回一个新对象。通过在构造函数的末尾添加return语句,可以重写调用构造函数时的返回值。安全构造函数模式首先理解安全对象不引用公共属性,它们的方法不引用this。安全对象最适合在某些安全环境中使用(这些环境禁止使用this和new),或者防止数据被其他应用程序更改。secureconstructor模式与parasitic模式类似,有两点不同:一是创建对象实例的方法不引用this,而是不使用new运算符调用构造函数functionPerson(name,job){varo=newObject()o.name=nameo.job=jobo.sayName=function(){console.log(name)}return}varperson1=Person('江','student')person1.sayName()同理作为寄生构造函数模式,所以创建的对象和构造函数之间没有关系,instanceof操作符对它们没有意义
