说说创建对象实例。尽管可以使用对象构造函数和对象字面量来创建单个对象,但这些方法有一个明显的缺点。创建多个对象时,会生成大量的对象。代码重复,造成代码冗余。//对象字面量varperson1={name:'123'}//对象构造函数varperson2=newObject()person2.name='123'最直观的函数可以用一次声明多个调用来解决代码冗余另外,工厂模式主要是通过Object构造函数或者对象字面量在函数体中创建一个对象,为对象赋属性,最后返回新创建的对象。工厂模式的缺点是没有对象识别,即无法知道新创建的对象的类型。函数createPerson(名字){varo={};o.name=名称;o.sayName=function(){alert(this.name)};returno;}varperson1=createPerson('JACK');constructor模式是JS中创建特定类型对象的方式。它具有很强的类型识别。它主要使用new关键字来完成一个构造函数对象的创建。函数Person(name){this.name=name;this.constructor=人;this.sayName=function(){alert(this.name)};}varperson2=newPerson('JACK')但构造函数的声明每次调用时都必须在每个实例上重新创建该方法。不同实例下的同名函数不相等。本质是Function类创建不同的实例,导致额外的冗余。functionPerson(name){this.sayName=newFunction("alert(this.name)");}可以将函数的定义转移到构造函数外部,指向构造函数内部的外部函数,形成创建对象构造函数的优化版本。函数Person(name){this.name=name;this.getName=getName;}functiongetName(){console.log(this.name);}varperson1=newPerson('kevin');这样做确实解决了两个函数做同一件事的问题,但是新的问题又出现了。定义在全局范围内的函数实际上只能被一个对象调用,这使得全局范围有点名不副实。如果对象需要定义很多方法,那么就必须定义很多全局函数,所以这个自定义引用类型根本就没有封装。函数放在构造函数内部还是构造函数外部都不是一个好的解决方案,那为什么不创建一个对象,把实例的公共方法和属性放在一起,实例会自动索引到这样的公共属性和属性方法,这是原型模式。在JS中声明一个函数对象时,会生成一个原型属性——原型对象。构造函数生成的每个实例的隐式原型__proto__都指向原型对象,因此每个实例都可以实现访问公共属性和方法。functionPerson(){}Person.prototype.name='123'Person.prototype.sayName=function(){alert(this.name)}varperson3=newPerson()person3.sayName()//'123'应该注意,如果重写Person.prototype对象,相当于切断了构造函数与其原型之间的联系。functionPerson(){}Person.prototype={name:'123',sayName:function(){alert(this.name)}}varperson=newPerson();person.sayName()//123vara=Person.prototype.constuctor===Person//false根据前面创建的一个函数,会同时创建它的原型对象,这个对象会自动获取constructor属性。改写Person.prototype对象后,constructor属性也会被销毁,但继续从原型链上查找。从上图可以看出找到了对象,可以让构造函数重新指向Person。functionPerson(){}varfriend=newPerson();Person.prototype={constructor:Person,name:'123'sayName:function(){alert(this.name)}}friend.sayName()原型模式解决它解决了实例方法放在哪里的问题,但它也会包含公共属性。如果这些属性是引用类型,并且允许在实例中修改原型上的数据,那么任何实例中的数据都会变得不可靠。一旦修改将反映在所有其他实例上。因此,JS中创建对象的原则是实例一般都拥有自己的所有属性,而方法可以由原型对象委托访问。回过头来看,构造函数可以通过this携带自己的属性,所以应该使用构造函数模式和原型模式相结合的方式。而下面的代码:functionPerson(name){this.name=name}Person.prototype={constructor:Person,sayName:function(){alert{this.name}}}合理的解决了放新对象属性的问题Where,把方法放在哪里——在构造函数中定义属性,在原型对象上定义方法。因此,每个实例都会有自己的实例属性副本,但同时共享对方法的引用,这是一种常用的创建对象的方式。唯一美中不足的是它们是分开的。通过检查构造函数原型上是否存在函数方法名,可以将声明在原型上的方法写在构造函数内部。一起写的模式也叫动态原型模式。功能人(姓名,年龄,工作){this.name=name;if(typeofthis.sayName!="function"){Person.prototype.sayName=function(){alert(this.name)}}}还有一个模式,用在特殊场景,其他模式不用应用,您可以使用寄生构造函数模式。即在一个具有原型继承的实例对象的基础上,通过其他构造函数(原型链继承)对其进行修改,并返回修改后的对象。functionPerson(name){varo=newObject();o.name=名称;o.sayName=function(){alert(this.name);}returno;}除了使用new操作符和包装used函数调用构造函数之外,这个模式其实和工厂模式是一模一样的。在特殊情况下可以使用此模式来为对象创建构造函数。假设我们想创建一个带有额外方法的特殊数组。由于不能直接修改Array构造函数,所以可以采用这种模式,这也是new操作符的原理。函数objFactory(obj,Constructor,args){obj=obj||newObject(),obj.__proto__=Constructor.prototype;让ret=Constructor.apply(obj,args);返回类型ret==='对象'?ret:obj;};varo=objFactory(Person,'Yadang')o.sayName()//我叫YadangES6中的对象创建方式是模仿传统的面向对象class.classPerson{constructor(name){this.name=name}sayName(){console.log("Mynameis"+this.name)}}varman=newPerson('Yadang')man.sayName()//我叫Yadangand它的babel本质是构造函数模式和原型模式相结合的实现,删掉的代码如下。function_defineProperties(target,props){for(vari=0;i
