js中创建对象的几种方式
创建对象指创建一个object并给这个对象添加属性和方法,有以下几个方式:
最基本的:
var Person={};
Person.name='tom';
Person.age='20';
Person.sayname=function(){
alert(this.name);
};
创建了一个Person对象,并添加了name,age属性,还有一个sayname方法。
下面是用构造函数方式创建:
function Person(name,age){
this.name=name;
this.age=age;
this.sayname=function(){
alert(this.name);
};
}
var p1=new Person('yom',0);
var p2=new Person('tom',99);
alert(p1.name); //yom
alert(p2.name); //tom
alert(p1.constructor==p2.constructor);//true
alert(p1 instanceof Person);//true
alert(p2 instanceof Person);//true
注意:此时实例化的两个实例p1和p2都源自Person,这两个实例都含有constructor属性,该属性指向其构造函数,alert(p1.constructor==p2.constructor);//true可证明,这种方法的不足之处在于两个实例间相互独立,倘如有大量实例,造成很大内存浪费。
下面用原型方式可以解决实例间的属性不能共享的问题:
function Person(){}
Person.prototype.name='tom';
Person.prototype.age=20;
Person.prototype.sayname=function(){
alert(this.name);
};
var p1=new Person(); alert(p1.name);//tom
alert(p2.name);//tom
alert(p1.name==p2.name);//true
上述代码中p1和p2共享Person对象原型中的属性,但,此时并不能通过实例来重写原型中的属性,因为一旦在实例中重新定义属性后就会屏蔽原型中的属性,
因为此时会优先使用实例中的属性,如果实例中没有该属性,那就上找到原型,下面代码中p1使用的是实例中的name属性,p2使用的是原型中的属性:
function Person(){}
Person.prototype.name='tom';
Person.prototype.age=20;
Person.prototype.sayname=function(){
alert(this.name);
};
var p1=new Person(); alert(p1.name);//tom
alert(p2.name);//tom
alert(p1.name==p2.name);//true
p1.name='jim';//通过实例p1来重新定义name属性,屏蔽了原型中的name(只屏蔽,不修改)
alert(p1.name);//jim
alert(p2.name);//依然是tom
上面每添加一个属性都要Person.prototype.XX=XX; 很麻烦,可以用字面量的方式一次性定义,但要注意一个问题,那会重写默认的prorotype,使constructor不再指向Person
function Person(){}
Person.prototype={
name:'tom',
age:20,
sayname:function(){
alert(this.name);
}
};
var p1=new Person();
var p2=new Person();
alert(p1.name);//tom
alert(p2.name);//tom
alert(p1.name==p2.name);//true
p1.name='jim';//通过实例p1来重新定义name属性,屏蔽了原型中的name(只屏蔽,不修改)
alert(p1.name);//jim
alert(p2.name);//依然是tom
alert(p1.constructor==Person);//重写了prototype,constructor不再指向Person,但可手动调整
要想手动调整在prototype里添加一句就好:
Person.prototype={
constructor:Person,//手动更改
name:'tom',
age:20,
sayname:function(){
alert(this.name);
}
};
手动更改好后:alert(p1.constructor==Person);为true
上面提到,通过p1来重新定义name属性不会影响p2中的name,因为p1重新定义name属性后该属性属于p1这个实例中的属性,p2依然适用原型中的属性,所以不受影响。这里最核心的原因是因为name属性的属性值是js的基本数据类型(alert(typeof Person.name);为string),不是引用类型,倘若是引用型数据,那改动p1,p2就有影响了,这也是原型方式的不足之处:
function Person(){}
Person.prototype={
constructor:Person,
name:['tom','cat'],//name不再是基本数据类型,而是引用型Array
age:20,
sayname:function(){
alert(this.name);
}
};
var p1=new Person();
var p2=new Person();
alert(p1.name);//tom
alert(p2.name);//tom
p1.name.push('newname');//通过实例p1来修改引用型name属性
alert(p1.name);//'tom','cat','newname'
alert(p2.name);//p2也改变:'tom','cat','newname'
造成p1,p2都会改变的原因是两者都指向同一数组。
下面就是相对来说最‘完美’,最常见的创建对象的方式:构造函数模式与原型模式并用。其优点是把共有的属性和方法定义在原型中,把实例属性定义在构造函数中,这样,对于不同的实例来说,该共享的共享,该独立的独立。把引用型数值的属性定义到构造函数中,也就解决了上述原型模式中的不足之处:
function Person(name,age){
this.name=name;
this.age=age;
this.money=[10,100,1000];//这是个引用型,要定义在构造函数中
}
Person.prototype={
constructor:Person,
sayname:function(){
alert(this.name);
}
};
var p1 = new Person('tom',20);
var p2=new Person('cat',30);
alert(p1.money);//10,100,1000
alert(p2.money);//10,100,1000
p1.money.push(10000); //p1存入10000元
alert(p1.money); //10,100,1000,10000
alert(p2.money); //p2的money依然不变,还是10,100,1000。此时不再受p1的影响
还有一种更加“智能”的方式:动态原型模式
function Person(name,age){
this.name=name;
this.age=age;
this.money=[10,100,1000];//这是个引用型,要定义在构造函数中
if(typeof this.sayname!='function')
{
Person.prototype.sayname=function(){ //注意:此处不能用字面量的方式重写prototype,否则切断实例与新原型的关系
alert(this.name);
};
}
} var p1 = new Person('tom',20);
var p2=new Person('cat',30);
alert(p1.money);//10,100,1000
alert(p2.money);//10,100,1000
p1.money.push(10000); //p1存入10000元
alert(p1.money); //10,100,1000,10000
alert(p2.money); //p2的money依然不变,还是10,100,1000。此时不再受p1的影响
p1.sayname();//tom
p2.sayname();//cat
除此之外还有寄生构造函数模式和工厂模式,两者的区别是实例化实例的方式不同,其余全部一样:
所谓寄生就是在function里创建对象,并给对象添加属性后从function中返回该对象
function Person(name,age){
var o=new Object();//在函数里创建对象
o.name=name;
o.age=age;
o.sayname=function(){
alert(this.name);
};
return o; //添加完属性后返回o
}
//寄生构造函数模式用new
var p1 = new Person('tom',20);//寄生构造函数模式
//工厂模式直接调用Person函数
var p2=Person('cat',30); //工厂模式
alert(p1.age);//20
alert(p2.age);//30
p1.sayname();//tom
p2.sayname();//cat
注意:如果用此文的第一种构造函数模式创建对象,用new和直接调用这两种方式的区别在于this上,另写一篇文章介绍。此文的叙述方式可能存在很多不足或错误,本人还是菜鸟阶段,欢迎批评指正。
js中创建对象的几种方式的更多相关文章
- js中创建对象的三种方式
1. 对象字面量 var obj={ name:"小小", age:3, car:{ brand:"baoma", } }; } 2.使用内置构造函数 var ...
- 比较js中创建对象的几种方式
1.工厂模式 function createObj(name, sex){ var obj = new Object(); obj.name = name; obj.sex = sex; obj.sa ...
- Java中创建对象的几种方式
Java中创建对象的五种方式: 作为java开发者,我们每天创建很多对象,但是我们通常使用依赖注入的方式管理系统,比如:Spring去创建对象,然而这里有很多创建对象的方法:使用New关键字.使用Cl ...
- Java中创建对象的五种方式
我们总是讨论没有对象就去new一个对象,创建对象的方式在我这里变成了根深蒂固的new方式创建,但是其实创建对象的方式还是有很多种的,不单单有new方式创建对象,还有使用反射机制创建对象,使用clone ...
- 【转】Java中创建对象的5种方式
Java中创建对象的5种方式 作为Java开发者,我们每天创建很多对象,但我们通常使用依赖管理系统,比如Spring去创建对象.然而这里有很多创建对象的方法,我们会在这篇文章中学到. Java中有 ...
- JavaScript中创建对象的三种方式!
JavaScript中创建对象的三种方式! 第一种 利用对象字面量! // 创建对象的三种方式! // 1 对象字面量. var obj = { // 对象的属性和方法! name: 'lvhang' ...
- JS 面向对象 ~ 创建对象的 9 种方式
一.创建对象的几种方式 1.通过字面量创建 var obj = {}; 这种写法相当于: var obj = new Object(); 缺点:使用同一个接口创建很多单个对象,会产生大量重复代码 2. ...
- Javascirpt中创建对象的几种方式
js是一种动态语言,即js的对象创建好之后可以随意修改,因此JS对象的面向对象编程部分更可以说是通过JS的怪异特性来模拟Java这类的面向对象编程的.下面首先讨论几种创建对象的方式: 1. 工厂模式创 ...
- Java中创建对象的5种方式
作为Java开发者,我们每天创建很多对象,但我们通常使用依赖管理系统,比如Spring去创建对象.然而这里有很多创建对象的方法,我们会在这篇文章中学到. Java中有5种创建对象的方式,下面给出它们的 ...
随机推荐
- STM32 程序所占用空间计算 && FLASH存储的起始地址计算
程序编译完成,会乘车program size .. 对STM32容量选型或者 计算FLASH 充当EEPROM起始地址时会用到此参数. 按照下面截图 程序空间 = (16700+732+4580)/ ...
- sass调试--页面看到sass文件而不是css文件问题
在浏览器页面有时看到sass文件而不是css文件问题,其主要由于sass开启了source-map(调试)功能,问题如下图: sass调试 sass调试需要开启编译时输出调试信息和浏览器调试功能,两者 ...
- 使用ELK(Elasticsearch + Logstash + Kibana) 搭建日志集中分析平台实践--转载
原文地址:https://wsgzao.github.io/post/elk/ 另外可以参考:https://www.digitalocean.com/community/tutorials/how- ...
- webapp开发之需要知道的css细节
引言 首先说明一下,本文分享对象是涉世未深的移动开发者,至于有经验的开发者可以自行绕道. 说来惭愧,做了几年pc端的前端开发,很少接触到webapp的移动端开发.如今有机会参与webapp的开发,发现 ...
- 性能调优:理解Set Statistics Time输出
在性能调优:理解Set Statistics IO输出我们讨论了Set Statistics IO,还有如何帮助我们进行性能调优.这篇文章会讨论下Set Statistics Time,它会告诉我们执 ...
- 基于HTML5技术的电力3D监控应用(三)
继(一)和(二)之后不少,不少网友问我移动终端的使用问题,因为我们项目这次采用Android平板终端,所以我对这方面有点肤浅的研究,这篇分享些项目经验总结,希望对大家有所帮助. 电力3D项目去年底刚立 ...
- CMD魔法堂:CMD进入指定目录
一.前言 每次打开cmd默认目录总是当前用户目录,然后是一大轮cd命令才进入工作目录,哎,怎一个烦自了得.幸好我们可以通过批处理文件来进入指定目录,省心多了. 二.cmd命令介绍 CMD [/A ...
- chrome开发者工具浅析--timeline
一.概述 ...
- 正则表达式:re--python核心编程(3),chapter 1
最近听吴老的电台,收获颇多,给人映像最深的就是:学会编程 和 坚持学习:作为一名测试员,要从一名手工测试转化成 测试开发 或者资深的测试工程师,编码水平是必须具备的基本素质:吴老所说,撸1W到2W行代 ...
- Ext.NET 4.1 最新版本破解
Ext.NET 4.1 最新版本破解 今天在将Ext.NET 4.1版本的程序发布到公网时居然要license(localhost和127.0.0.1不收费),而且一年$4999,突然间觉得这是什么鬼 ...