创建对象
这些通过对象构造函数或对象文字创建单个对象的方法有明显的缺点:创建许多具有相同接口的对象会产生大量重复的代码。为了解决这个问题,工厂模式出现了。
工厂模式
考虑到类不能在es中创建(在ES6之前),开发人员发明了一个函数来封装创建具有特定接口的对象的细节。(它是通过在函数中创建一个对象,然后返回该对象来实现的。).
函数createPerson(姓名、年龄、职务){ var o=new Object();o.name=nameo.age=年龄;o.job=jobo . SayName=function(){ alert(this . name);};返回0;} var person 1=createPerson(' Nicholas ',29岁,'软件工程师');var person2=createPerson('Greg ',27,' Doctor ');构造函数模式
诸如对象和数组等本机构造函数将在运行时自动出现在执行环境中。此外,您还可以创建自定义构造函数来定义自定义对象类型的属性和方法。
功能人员(姓名、年龄、工作){ this.name=namethis.age=年龄;this.job=jobthis . SayName=function(){ alert(this . name);};}var person1=new Person(.);var person2=新人员(.);与工厂模式相比,它具有以下特点:
没有显式创建对象;属性和方法直接分配给该对象;没有退货单;要创建新实例,必须使用新运算符;(否则,属性和方法将被添加到窗口对象中。)您可以使用instanceof运算符来检测对象类型构造函数的问题:
构造函数内部的方法是重复创建的,不同实例中同名的函数不相等。这个问题可以通过将方法移出构造函数来解决,但是出现了一个新的问题:封装性差。
原型
我们创建的每个函数都有一个原型属性,它是一个指向对象的指针,这个对象的目的是包含特定类型的所有实例都可以共享的属性和方法。(prototype是通过调用构造函数创建的对象实例的原型对象。).使用原型对象的优点是所有对象实例可以共享它包含的属性和方法。换句话说,不需要在构造函数中定义对象实例的信息,但是可以直接添加到原型对象中。
函数Person(){ } Person . prototype . name=' Nicholas ';person . prototype . age=29;Person.prototype.job=' . ';person . prototype . SayName=function(){ 0.};var Person 1=new Person();person 1 . SayName();//‘Nicholas’更常见的是用包含所有属性和方法的对象文字重写整个原型对象,并重置构造函数属性。
function PeRsoN(){ } PeRsoN . prototype={ name : ' . ',年龄:29,工作: ' .SayName : FuncTion(){ 0.}};object . definepreproperty(person . prototype,‘constructor’,{ enumerable:false,value:Person,});原型对象的问题:
他省略了将初始化参数传递给构造函数的步骤,因此,默认情况下,所有实例都将获得相同的属性值。虽然这在一定程度上会带来一些不便,但并不是最大的问题,这是由他们的共享性质决定的。对于具有基本值的属性,可以通过在实例上添加同名属性来隐藏原型中的属性。然后,对于包含引用数据类型的值,它可能会导致问题。
将构造器模式和原型模式结合起来
这是创建自定义类型的最常见方式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性。因此,每个实例都有自己的实例属性副本,但同时共享对方法的引用,这最大限度地节省了内存。它还支持将参数传递给构造函数。
功能人员(姓名、年龄、工作){ this.name=namethis.age=年龄;this.job=jobthis.friends=['S ',' C '];} person . prototype={ constructor : person,say name : function(){ alert(this . name);}};var person1=新人员(.);动态原型模式
功能人员(姓名、年龄、工作){ this.name=namethis.age=年龄;this . job=jobif(type of this . say name!=' function '){ person。原型。说出name=function(){ alert(this。姓名);};}}这里只有sayName()不存在的情况下,才会将它添加到原型中,这段代码只会在初次调用构造函数时才执行。这里对原型所做的修改,能够立刻在所有实例中得到反映。
Object.create()
ES5定义了一个名为Object.create()的方法,它创建一个新对象,其中第一个参数是这个对象的原型,第二个参数对对象的属性进行进一步描述。
Object.create()介绍
Object.create(null)创建的对象是一个空对象,在该对象上没有继承对象。原型原型链上的属性或者方法,例如:toString(),hasOwnProperty()等方法
Object.create()方法接受两个参数:Object.create(obj,properties对象);
obj:一个对象,应该是新创建的对象的原型。
属性对象:可选。该参数对象是一组属性与值,该对象的属性名称将是新创建的对象的属性名称,值是属性描述符(这些属性描述符的结构与对象。定义属性()的第二个参数一样)。注意:该参数对象不能是未定义,另外只有该对象中自身拥有的可枚举的属性才有效,也就是说该对象的原型链上属性是无效的。
var o=对象。创建(对象。原型,{ //foo会成为所创建对象的数据属性foo: { writable:true,configurable:true,value: 'hello' },//bar会成为所创建对象的访问器属性bar : { configuration ble : false,get: function() { return 10 },set : function(value){ console。日志(“将o . bar设置为”值);} }});控制台。日志(o);//{ foo : ' hello ' } var test1=object。create(null);控制台。日志(测试1);//{}无属性因为在酒吧中设置了可配置的使用设置,获取方法默认都是不起作用,所以酒吧值无法赋值或者获取这里的o对象继承了对象。原型对象上的原型方法我们可以对象的__原型_ _属性,来获取对象原型链上的方法如:控制台。log(o . _ _ proto _ _);//{ _ _ defineGetter _ _ : u u u u u u u u u u u u u u u u u u u u u u u u u u u u u u u_ _ proto _ _);//未定义通过打印发现,将{}点开,显示的是没有属性,也就是在对象本身不存在属性跟方法,原型链上也不存在属性和方法,
新对象()
var test1={ x :1 };var test2=新对象(测试1);var test3=对象。create(test 1);控制台。日志(测试3);//{} //test3等价于测试5 var test4=function(){ }测试4。原型=测试1;var test5=new test4();控制台。日志(测试5);console.log(测试5 .__proto__===test3 ._ _ proto _ _);//真控制台。日志(测试2);//{ x :1 } var test1={ };var test2=新对象();var test3=对象。创建(对象。原型);var test4=对象. create(空);//console.log(test4 ._ _ proto _ _)=未定义没有继承原型属性和方法console.log(测试1 .__proto__===test2 ._ _ proto _ _);//trueconsole.log(test1 .__proto__===test3 ._ _ proto _ _);//trueconsole.log(test2 .__proto__===test3 ._ _ proto _ _);//trueconsole.log(test1 .__proto__===test4 ._ _ proto _ _);//falseconsole.log(test2 .__proto__===test4 ._ _ proto _ _);//falseconsole.log(test3 .__proto__===test4 ._ _ proto _ _);//false总结:使用Object.create()是将对象继承到__原型_ _属性上
var测试=对象。创建({ x :123,y :345 });console.log(测试);//{ }控制台。日志(测试。x);//123console.log(测试。__原型_ _。x);//3console.log(测试。__原型_ _。x===测试。x);//truevar test1=新对象({x:123,y :345 });控制台。日志(测试1);//{x:123,y :345 }控制台。日志(测试1。x);//123console.log(test1 .__原型_ _。x);//undefinedconsole.log(test1 .__原型_ _。x====test1。x);//falsevar test2={x:123,y :345 };控制台。日志(测试2);//{x:123,y :345 };控制台。日志(测试2。x);//123console.log(test2 .__原型_ _。x);//undefinedconsole.log(test2 .__原型_ _。x===测试2。x);//false继承
我在这里介绍一个,其余的可以在权威指南中看到
原型链
ECMAScript中描述了原型链的概念,并将原型链视为实现继承的主要方法。基本思想是通过使用原语使一个引用类型继承另一个引用类型的属性和方法。简要回顾构造函数、原型和实例之间的关系。每个构造函数都有一个原型对象,它包含一个指向构造函数的指针,而实例包含一个指向原型对象的内部指针。那么,如果我们让原型对象等于另一种类型的实例,会发生什么呢?显然,此时的原型对象将包含指向另一个原型的指针,相应地,另一个原型也包含指向另一个构造函数的指针。如果另一个原型是另一种类型的实例,那么上述关系仍然成立,真实例子和原型的链就是由这样的渐进步骤形成的。这是原型链的基本概念。
实现原型链有一个基本模式,其代码大致如下。
function SuperType(){ this . property=true;} SuperType . prototype . GetSuperVaLue=function(){ return this . property;};function SubType(){ this . subparty=false;}//继承的supertypesubtypeprototype=new super type();subtype . prototype . getsubvalue=function(){ return this . subproperty;};var实例=new SubLe();alert(instance . GetSuperVaLue());//true上面的代码定义了两种类型:SuperType和SubType。每种类型都有一个属性和一个方法。它们之间的主要区别是SubType继承SuperType,而继承是通过创建SuperType的实例并将其分配给SubType.prototype来实现的.实现的本质是重写原型对象,并用新类型的实例替换它。换句话说,原来存在于SuperType实例中的所有属性和方法现在都存在于SubType.prototype中,在建立继承关系后,我们给SubType.prototype增加了一个方法,从而在继承SuperType属性和方法的基础上增加了一个新的方法。这个例子中的例子以及构造函数和原型之间的关系如图6-4所示。
以上是边肖介绍的js创建对象的几种方法,以及它们的继承、详细说明和集成。希望对大家有帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!