在 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. Bash 什么时候会给 HOME 赋初始值

    今天无意发现下面这个表现: $  env -i bash -c cd bash: line 0: cd: HOME not set $ env -i bash -c 'echo $HOME' 这表明了 ...

  2. js制作烟花效果

    <html> <head> <link type="text/css" rel="stylesheet" href="c ...

  3. TCP/IP 协议

    网站: http://blog.csdn.net/goodboy1881/article/category/204448

  4. 用Canvas写桌球游戏!!!

    声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢! 昨天上班的时候闲着无事,就用Canvas写了个桌球游戏来玩玩....所以就拿这游戏上来水一发.或许对一些刚学canvas的人有帮助. 话说 ...

  5. java8

    1:Scanner的使用(了解) (1)在JDK5以后出现的用于键盘录入数据的类. (2)构造方法: A:讲解了System.in这个东西. 它其实是标准的输入流,对应于键盘录入 B:构造方法 Inp ...

  6. SQLServer2008设置 开启远程连接

    SQLServer2008设置 开启远程连接 前一段时间,学生分组做项目,使用SVN工具,要求功能使用存储过程,在数据库这块出现这么一个问题: A学生在他的数据库上添加了存储过程,需要其他的B,C,D ...

  7. 【python】引用其他目录文件

    假设有 目录/A(a.py), 目录/B(b.py), 括号里是目录中的文件 在目录/A中编写a2.py,里面可以import a,但是不能import b 解决方法 import sys sys.p ...

  8. 根据字符长度动态确定UIlabel宽高

    iOS7中用以下方法 - (CGSize)sizeWithAttributes:(NSDictionary *)attrs; 替代过时的iOS6中的- (CGSize)sizeWithFont:(UI ...

  9. WdatePicker.js开始日期和结束日期比较

    jQuery.validator.addMethod("endDate",       function(value, element) {           var start ...

  10. Laravel Homestead安装笔记

    引言: 最近开始学习laravel框架,了解到有个laravel homestead的box,开发起来非常方便快捷,于是就准备开始配置homestead虚拟开发环境了 什么是Homestead 要想学 ...