在 js 中,对象由特性(attribute)构成,特性可以是原始值,也可以是引用值。如果特性存放的是函数,它将被看作对象的方法(method),否则该特性被看作对象的属性(property)。在js中创建对象一般有以下几种方法:

一.工厂模式

 1 function person(name,age){
2 var o={};
3 o.name=name;
4 o.age=age;
5 o.sayHello=function(){
6 alert('hi,I am '+this.name)
7 };
8 return o;
9 }
10 var liLei=person('liLei',25);
11 var hanHei=person('hanHei',22);
12 liLei.sayHello(); //hi,I am liLei
13 hanHei.sayHello(); //hi,I am hanHei
console.log(liLei.sayHello==hanHei.sayHello)   //false

我们创建了一个person函数,并传递了name和age两个参数,最后返回一个object。每次只需调用person函数我们便可以生成一个具有name,age属性及sayHello方法的对象,这种方法有个问题,就是每次通过调用person方法创建对象的时候都会新创建一个sayHello方法,而事实上,我们所创建的实例都共享一个方法,所以我们可以修改如下,将sayHello方法定义在函数外面,这样每次创建对象所引用的sayHello都为同一个方法;

// JavaScript Document
function sayHello(){
alert('hi,I am '+this.name)
}
function person(name,age){
var o={};
o.name=name;
o.age=age;
o.sayHello=sayHello;
return o;
}
var liLei=person('liLei',25);
var hanHei=person('hanHei',22);
liLei.sayHello(); //hi,I am liLei
hanHei.sayHello(); //hi,I am hanHei
console.log(liLei.sayHello==hanHei.sayHello) //true
console.log(liLei.prototype==hanHei.prototype) //false

工厂模式有一个问题,就是创建的实例之间没有联系,于是又有了构造函数模式。

二.构造函数模式

 function Person(name,age){
this.name=name;
this.age=age;
this.sayHello=function(){
alert('hi,I am'+this.name)
};
}
var liLei=new Person('liLei',25);
var hanHei=new Person('hanHei',22);
liLei.sayHello(); //hi,I amliLei
hanHei.sayHello(); //hi,I amhanHei
console.log(liLei.constructor==hanHei.constructor) //true

我们习惯将构造函数的首字母大写,当然我们也可以像上面那样,将sayHello方法定义到外面。在构造函数模式调用时,必须加new,否则就会发生错误,因为如果不调用new的话,函数内的this将指向window,为了避免这种问题,我们可以改进一下上述方法。

 function Person(name,age){
if(this instanceof Person){
this.name=name;
this.age=age;
this.sayHello=function(){
alert('hi,I am'+this.name)
};
}else{
return new Person(name,age)
}
}
var liLei=Person('liLei',25);
var hanHei=new Person('hanHei',22);
liLei.sayHello(); //hi,I amliLei
hanHei.sayHello(); //hi,I amhanHei

在函数内部我们新增了一个判断,如果调用函数时没加new,则当前this值为window,并不是Person的实例,因此我们返回一个新的实例。

当然构造函数除了像上面将方法定义在外面并没有解决实例方法重复的问题。以此就有了原型。

三.原型对象

关于原型对象;

在js中,在我们创建一个函数时,就会有一个默认的prototype指针指向一个对象,我们称之为原型对象,该对象的所有属性和方法都可以被实例所继承。

function Person(){

 }
Person.prototype.name='liLei';
Person.prototype.age=25
Person.prototype.sayHello=function(){
alert(1)
}
var liLei=new Person();
var hanHei=new Person();
liLei.sayHello();
hanHei.sayHello()
alert(liLei.name+'---'+hanHei.name)

我们看到,实例对象都继承了原型对象的属性和方法,当然我们也可以为实例添加与原型对象相同名称的属性,这样我们访问该属性的时候就会返回实例属性而非原型属性。实例属性会屏蔽掉原型对象,但是不能通过实例属性修改原型属性。访问属性顺序大概为  实例属性---》原型属性,如下:

  function Person(){

  }
Person.prototype.name='liLei';
Person.prototype.age=25
Person.prototype.sayHello=function(){
alert(1)
}
var liLei=new Person();
alert(liLei.name); //liLei
liLei.name='name';
alert(liLei.name); //name
delete liLei.name;
alert(liLei.name) //liLei

我们经常见到这样一种写法

function Person(){

}
Person.prototype={
name:'lilei',
age:,
sayHello:function(){ }
}
Person.prototype.constructor=Person

在对象字面量的写法中,我们在下面紧接着加了一句,原型对象的constructor属性指向Person。这是因为在js中,我们创建函数即Person时,就会有一个prototype属性指向该函数的原型对象,当我们使用对象字面量为原型对象赋值时,本质上等于完全重写了默认的prototype对象,因此constructor属性也就变成了新对象的constructor属性(指向object构造函数),因此为了指向的正确,我们一般都会在后面通过手动设置constructor属性来使指向正确。

通过原型对象创建的实例都有共同的属性prototype,可以通过isPrototype()方法来验证,但是原型对象也有一个问题,当遇到属性值为引用类型值时,会出现共享

  function Person(){

  }
Person.prototype.color=['red','blue'];
Person.prototype.age=25
Person.prototype.sayHello=function(){
alert(1)
}
var person1=new Person();
var person2=new Person();
person1.color.push('green');
alert(person1.color); //red,blue,green
alert(person2.color); //red,blue,green

上面的代码中,属性 color为原型属性,是引用类型,当person1对color push一个新值时,结果会反映到person2中,这显然不是我们想要的结果。

四.组合模式

最常用的方法时结合构造函数及原型模式:

  function Person(name,age,color){
this.name=name;
this.age=age;
this.color=['red','blue']
}
Person.prototype.sayHello=function(){
alert(1)
}
var person1=new Person('li',25);
var person2=new Person('han',22);
person1.color.push('green');
alert(person1.color); //red,blue,green
alert(person2.color) //red,blue

所有的非函数属性都在构造函数中创建,意味着又能够用构造函数的参数赋予属性默认值了。修改一个实例对象中的引用类型不会影响到另一个实例对象,所有实例对象都引用原型对象的方法。

五.动态原型模式

  function Person(name,age,color){
this.name=name;
this.age=age;
this.color=['red','blue'];
if(!typeof this.sayHello=='function'){
Person.prototype.sayHello=function(){
alert(1)
}
}
}
var person1=new Person('li',25);
var person2=new Person('han',22);
person1.color.push('green');
alert(person1.color); //red,blue,green
alert(person2.color) //red,blue

js面向对象总结(一)的更多相关文章

  1. js面向对象学习 - 对象概念及创建对象

    原文地址:js面向对象学习笔记 一.对象概念 对象是什么?对象是“无序属性的集合,其属性可以包括基本值,对象或者函数”.也就是一组名值对的无序集合. 对象的特性(不可直接访问),也就是属性包含两种,数 ...

  2. 带你一分钟理解闭包--js面向对象编程

    上一篇<简单粗暴地理解js原型链--js面向对象编程>没想到能攒到这么多赞,实属意外.分享是个好事情,尤其是分享自己的学习感悟.所以网上关于原型链.闭包.作用域等文章多如牛毛,很多文章写得 ...

  3. JS面向对象(3) -- Object类,静态属性,闭包,私有属性, call和apply的使用,继承的三种实现方法

    相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...

  4. JS面向对象(2) -- this的使用,对象之间的赋值,for...in语句,delete使用,成员方法,json对象的使用,prototype的使用,原型继承与原型链

    相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...

  5. JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式

    相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...

  6. js面向对象的实现(example 二)

    //这个方法和上篇文章(js面向对象的实现(example 一))中的方法类似,但是更为简洁 //通过函数赋值的方式来构造对象 //同样通过闭包的方式来封装对象及内部变量 (function () { ...

  7. 浅谈JS面向对象之创建对象

    hello,everybody,今天要探讨的问题是JS面向对象,其实面向对象呢呢,一般是在大型项目上会采用,不过了解它对我们理解JS语言有很大的意义. 首先什么是面向对象编程(oop),就是用对象的思 ...

  8. js面向对象,有利于复用

    需求:在网页上添加个天气预报. 以前总是在需要执行js的地方,直接写function(){}.在需要同样功能的地方直接copy,或者稍微修改. 然后在网上看看有没有好点的方法,然后就看到js面向对象编 ...

  9. JavaScript基础精华02(函数声明,arguments对象,匿名函数,JS面向对象基础)

    函数声明 JavaScript中声明函数的方式:(无需声明返回值类型) function add(i1, i2) {             return i1 + i2;//如果不写return返回 ...

  10. 原生JS面向对象思想封装轮播图组件

    原生JS面向对象思想封装轮播图组件 在前端页面开发过程中,页面中的轮播图特效很常见,因此我就想封装一个自己的原生JS的轮播图组件.有了这个需求就开始着手准备了,代码当然是以简洁为目标,轮播图的各个功能 ...

随机推荐

  1. ARCGIS常用几种本地数据AE初始化

    1.Personal GDB 新建一个在E盘的名为test的mdb: IWorkspaceFactory workspaceFactory = new AccessWorkspaceFactoryCl ...

  2. 脑筋急转弯——Google 面试

    1. 村子里有100对夫妻,其中每个丈夫都瞒着自己的妻子偷情...村里的每个妻子都能立即发现除自己丈夫之外的其他男人是否偷情,唯独不知道她自己的丈夫到底有没有偷情.村里的规矩不容忍通奸.任何一个妻子, ...

  3. [Python & Machine Learning] 学习笔记之scikit-learn机器学习库

    1. scikit-learn介绍 scikit-learn是Python的一个开源机器学习模块,它建立在NumPy,SciPy和matplotlib模块之上.值得一提的是,scikit-learn最 ...

  4. Asp.Net Core--简单的授权

    翻译如下: 在MVC中授权通过控制AuthorizeAttribute属性及其各种参数.在最简单的应用AuthorizeAttribute属性控制器或行动限制访问控制器或操作任何身份验证的用户. 例如 ...

  5. java11

    1:对象数组(掌握) (1)数组既可以存储基本数据类型,也可以存储引用类型.它存储引用类型的时候的数组就叫对象数组. (2)案例: 用数组存储5个学生对象,并遍历数组. 2:集合(Collection ...

  6. JVM内存管理------垃圾搜集器精解(让你在垃圾搜集器的世界里耍的游刃有余)

    引言 在上一章我们已经探讨过hotspot上垃圾搜集器的实现,一共有六种实现六种组合.本次LZ与各位一起探讨下这六种搜集器各自的威力以及组合的威力如何. 为了方便各位的观看与对比,LZ决定采用当初写设 ...

  7. Android错误

    1. [2016-09-16 14:25:45 - X_Card] Found 2 versions of android-support-v4.jar in the dependency list, ...

  8. GNU/Linux下LVM配置管理以及快照卷、物理卷、卷组、逻辑卷的创建和删除

    LVM是Linux环境中对磁盘分区进行管理的一种机制,是建立在硬盘和分区之上.文件系统之下的一个逻辑层,可提高磁盘分区管理的灵活性.最大的优点是在不损伤数据的前提下调整存储空间的大小. 本篇主要讲述L ...

  9. 【pymongo】mongodb cursor id not valid error

    参考来源: http://stackoverflow.com/questions/10298354/mongodb-cursor-id-not-valid-error http://stackover ...

  10. mint17.3挂载u盘出现错误:mount:unknown filesystem type 'exfat'

    mint17.3挂载u盘出现错误:mount:unknown filesystem type 'exfat' 安装exfat-fuse: sudo apt-get install exfat-fuse