在 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. apache启动出错原因举例

    这是我这两天频繁遇到的问题.Apache服务器还真是问题少年!任何点改动都可能导致它无法使用. 原因一:80端口占用例如IIS,另外就是迅雷.我的apache服务器就是被迅雷害得无法启用! 原因二:软 ...

  2. Schema

    Schema约束 1.namespace 相当于schema文件的id 2.targetNamespace属性 用来指定schema文件的namespace的值 3.xmlns属性 引入一个约束,它的 ...

  3. linux 根据文件大小查找文件

    inux下的find命令用来查找文件,通过man find就知道它是无所不能的.所以按照文件大小来查找文件就不在话下.从man find搜索size,可以看到如下信息: -size n[cwbkMG] ...

  4. python 学习 : 一个简单的秒表

      游戏说明:绿色数字(左边表示成功停止在整秒的次数,右边表示停止的总次数) 点击stop,如果小数点后为0,即你停止的时间是整秒数,右上方斜杠左边数字加一 把代码复制到这个网页code run he ...

  5. 7、I/O流

    一.流的概念:流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作.I/O就 ...

  6. linux常用命令-文件搜索命令-locate,which,whereis,grep

    locate 目录或文件名 -i 查找的时候不区分大小写 这个类似everything,速度比find快很多,因为这个命令搜索的是它维护的文件资料库,文件资料库是var/lib/mlocate/mlo ...

  7. Python全栈开发【基础一】

    Python全栈开发[第一篇] 本节内容: Python 的种类 Python 的环境 Python 入门(解释器.编码.变量.input输入.if流程控制与缩进.while循环) if流程控制与wh ...

  8. XSS攻击及防御

    XSS又称CSS,全称Cross SiteScript,跨站脚本攻击,是Web程序中常见的漏洞,XSS属于被动式且用于客户端的攻击方式,所以容易被忽略其危害性.其原理是攻击者向有XSS漏洞的网站中输入 ...

  9. iOS 4种开发者身份的官方说明

    https://developer.apple.com/support/compare-memberships/cn/ 为了防止链接失效,截图如下:

  10. 阿里云部署Java web项目初体验(转)

    林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文主要讲了如何在阿里云上安装JDK.Tomcat以及其配置过程.最后以一个实例来演示在 ...