组织Javascript创建对象的八种方法
1。使用对象构造函数创建对象
下面的代码创建一个人对象,并用两种方式打印出该名称的属性值。
var =新对象();
凯文;
人,年龄= 31岁;
警报(人名);
警报(人{name )
上述写作的另一种形式是使用对象的文字量创建对象。{ 5 }是合法的,不要感到惊讶。另外,使用这个括号的方法,字段之间有空格,比如人{我的年龄}…
无功的人=
{
姓名:凯文
年龄:31岁,
5:测试
};
警报(人名);
警报(人员{ 5 );
虽然对象构造器或对象文字卷可以用来创建单个对象,但这些方法有着明显的缺点:使用同一接口创建许多对象会产生大量重复代码。
2。工厂模式
工厂模式是软件工程领域中一种著名的设计模式。这个模型抽象创建具体对象的过程中,不能在ECMAscript考虑创建一个类,开发人员已经创建了一个晴朗的日子与函数,函数封装在一个特定的接口来创建对象,如下面的示例所示。
功能createperson(姓名、年龄、工作){
新对象();
o.name =名称;
o.age =年龄;
o.job =工作;
o.sayname =函数(){
警报(这个名字);
};
回来啊;
}
甲= createperson VaR(尼古拉斯
var 2 = createperson(格雷戈
工厂模式解决了创建多个相似对象的问题,但它没有解决对象识别问题(即如何知道对象的类型)。
出现了一种新的模式。
三.构造函数模式
构造函数如对象和数组将在运行时自动执行环境中出现。此外,还可以创建一个自定义的构造函数定义自定义对象类型的属性和方法。例如,你可以使用构造函数模式重写前面的例子如下。 U3000
功能人(姓名,年龄,工作){
this.name =名称;
this.age =年龄;
this.job =工作;
this.sayname =函数(){
警报(这个名字);
};
}
VaR甲=新的人(尼古拉斯
var 2 =新的人(格雷戈
在这个例子中,这个人()函数的createperson地点()函数。我们注意到,在人的代码()有以下除了相同的部分差异,在createperson():
1。没有明确的对象创建。
2。直接将属性和方法分配给该对象。
三.没有返回语句。
要创建一个新的实例,您必须使用新的操作符。这样,构造函数的调用将实际执行以下4个步骤:
(1)创建一个新对象;
(2)构造函数的范围被分配给新对象(因此指向新对象);
(3)在构造函数中执行代码(为这个新对象添加属性);
(4)返回到新对象。
在前面的例子,甲和2拯救的人,不同的情况分别。两对象有一个构造函数(constructor)属性指向的人,如下图所示。
警报(person1.constructor = =人); / /真的
警报(person2.constructor = =人); / /真的
对象的构造函数属性原本是用来识别对象的类型。但是,它提到的对象的类型更可靠,或instanceof运算符,我们在这个例子中创建对象实例的对象,以及实例的人,可以通过instanceof运算符验证。
警报(甲实例对象); / /真的
警报(甲是人); / /真的
警报(2实例对象); / /真的
警报(2是人); / /真的
创建一个自定义的构造函数,意味着它可以识别它的实例作为未来的一个特定的类型,这就是构造函数模式优于工厂模式。在这个例子中,甲和2是对象的一个实例,同时由于从对象继承的所有对象。
构造函数问题
尽管构造函数的结构很好,但它并不是没有缺点,使用构造函数的主要问题是每种方法都要在每个实例上重新创建。
ECMAscript是一个函数对象,所以每个定义一个函数是一个对象的实例化。从逻辑上看,此时的构造函数也可以这样定义。
功能人(姓名,年龄,工作){
this.name =名称;
this.age =年龄;
this.job =工作;
this.sayname =新功能(警报(这个名字)); / /语句和函数是等价的逻辑
}
从这一点来看,构造函数是容易理解的,每个人的情况都包含了一个不同的函数实例的本质(显示名称属性)。这表明该方法创建功能可以导致不同的范围链和标识符解析,但创建新的函数实例的机制仍然是相同的。因此在不同的情况下,相同名称的函数是不平等的,和下面的代码可以证明。
警报(person1.sayname = = 2。sayname); / /假
然而,没有必要创建两个实现相同任务的函数实例;此外,还有一些对象在执行代码之前不将函数绑定到特定对象,因此,可以通过将函数定义传递到构造函数的外部来解决这个问题。
功能人(姓名,年龄,工作){
this.name =名称;
this.age =年龄;
this.job =工作;
this.sayname = sayname;
}
功能sayname(){
警报(这个名字);
}
VaR甲=新的人(尼古拉斯
var 2 =新的人(格雷戈
如果对象需要定义许多方法,我们必须定义许多全局函数,所以我们的自定义引用类型根本就没有封装,幸运的是,这些问题可以通过原型模型来解决。
4,原型模型
功能人(){
}
person.prototype.name = 尼古拉斯;
person.prototype.age = 29;
person.prototype.job =软件工程师;
person.prototype.sayname =函数(){
警报(这个名字);
};
VaR甲=新的人();
(甲。sayname); / /尼古拉斯
var 2 =新的人();
(2。sayname); / /尼古拉斯
警报(person1.sayname = = 2。sayname); / /真的
为了理解原型对象,我可以看到另一个:Javascript原型
在前面的例子中,每增加一个属性和方法将打翻的person.prototype.in为了减少不必要的输入和视觉封装原型功能,更常见的做法是重写整个原型对象与一个包含所有的属性和方法的对象字面量,如下面的示例所示。
功能人(){
}
person.prototype = { {
姓名:尼古拉斯
年龄:29岁,
工作:软件工程师
sayname:函数(){
警报(这个名字);
}
};
在上面的代码中,我们设置person.prototype等于在文字对象的形式创造了一个新的对象,最终的结果是一样的,但有一个例外:构造函数属性不再指向人。如前所述,每创造一个功能将同时创建原型对象,和对象自动获得构造函数属性。我们在这里使用的语法基本上重写默认构造函数的原型对象,所以属性成为新的对象的构造函数属性(指向对象的构造函数),不再指向人的功能。在这一点上,虽然instanceof操作符可以返回正确的结果,它是不可能确定的类型构造函数,如下图所示。
朋友=新人();
警报(朋友是对象); / /真的
警报(朋友是人); / /真的
警报(friend.constructor = =人); / /假
警报(friend.constructor = =对象); / /真的
在这里,测试对象和人用instanceof运算符还是回归到真实,但构造函数属性等于物体和不平等的人。如果构造函数的值是非常重要的,你可以将它设置到合适的值如下。
功能人(){
}
person.prototype = { {
构造函数:人,
姓名:尼古拉斯
年龄:29岁,
工作:软件工程师
sayname:函数(){
警报(这个名字);
}
};
需要注意的是,实例中的指针只指向原型,而不指向构造函数。
原型对象的问题:原型模型是不是没有缺点。首先,它省略了,通过构造函数初始化参数的链接,和所有实例的默认会得到相同的属性值。虽然这会带来一些不便,在某种程度上,它不是原型样机的最大问题。模型的最大问题是它的共享性。
功能人(){
}
person.prototype = { {
构造函数:人,
姓名:尼古拉斯
年龄:29岁,
工作:软件工程师
好友:{谢尔比
sayname:函数(){
警报(这个名字);
}
};
VaR甲=新的人();
var 2 =新的人();
person1.friends.push(车);
警报(甲。朋友); / /谢尔比,法庭上,范
警报(2。朋友); / /谢尔比,法庭上,范
警报(person1.friends = 2。朋友); / /真的
5。构造函数和原型模式的组合使用(最常用的)
创建自定义的类型,最常见的方式是将构造函数模式和原型模式。构造函数模式是用来定义实例的属性,和原型模式是用来定义方法和共享的属性。因此,每个实例都有自己的一个实例属性的复制,但同时它股票的一个参考方法,节省了内存的最大值。此外,这种混合模式也支持参数传递给构造函数;它可以被描述为两模式集的长度。
功能人(姓名,年龄,工作){
this.name =名称;
this.age =年龄;
this.job =工作;
this.friends = {谢尔比
}
person.prototype = { {
构造函数:人,
sayname:函数(){
警报(这个名字);
}
}
VaR甲=新的人(尼古拉斯
var 2 =新的人(格雷戈
person1.friends.push(车);
警报(甲。朋友); / /谢尔比、计数、范
警报(2。朋友); / /谢尔比,计数
警报(person1.friends = 2。朋友); / /假
警报(person1.sayname = 2。sayname); / /真的
6。动态原型模式
与其它面向对象语言经验的开发者可能会很困惑,看到独立的构造函数和原型时,动态原型模型致力于解决这个问题,所有的信息都封装在构造函数,并在构造函数初始化原型(如果必要),和维护使用构造函数和原型的优点。换句话说,有可能确定样机是否需要检查一个方法应该存在有效初始化。看一个例子。
功能人(姓名,年龄,工作){
属性
this.name =名称;
this.age =年龄;
this.job =工作;
方法
---------------------------------------------
如果(typeof this.sayname!=函数{){
person.prototype.sayname =函数(){
警报(这个名字);
};
}
中国
}
var =新朋友(尼古拉斯)
Friend.sayName();
7,寄生构造函数模式
通常,当前面几个模式不适用时,可以使用寄生构造函数模式。这种模式的基本思想是创建一个函数,该函数只封装创建对象的代码,然后返回到新创建的对象。但从表面上看,这个函数与典型构造函数非常相似。
功能人(姓名,年龄,工作){
新对象();
o.name =名称;
o.age =年龄;
o.job =工作;
o.sayname =函数(){
警报(这个名字);
};
回来啊;
}
var =新朋友(尼古拉斯)
(朋友sayname); / /尼古拉斯
在这个例子中,函数创建一个新对象的人,并与相应的属性和方法来初始化对象,并返回该对象。除了新的算子和包装作为构造函数的使用,这种模式是完全一样的工厂模式。构造函数返回新的对象实例默认没有返回值。
8,稳定的构造函数模型
所谓的安全对象是指没有公共财产,其方法不是指这个对象,一个安全的对象是最适合一些安全的环境,这将禁止这种新的在这些环境中的使用,或以防止数据被其他应用程序的改变,如混搭程序的稳定。构造函数遵循这种模式类似于寄生构造函数,但有两点不同:第一,新创建对象的实例方法不是指这个;二是使用new运算符来调用构造函数。按照一个稳定的构造要求,以前的人构造函数可以改写如下。
功能人(姓名,年龄,工作){
要返回的对象创建
新对象();
可以在这里定义私有变量和函数。
添加
o.sayname =函数(){
警报(名称);
};
返回对象
回来啊;
}