在 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. Node.js入门笔记(5):案例两则

    案例分析:前端自动化 1. 实现一个自动创建前端项目文件的js 通过node.js自动创建前端项目目录,包括js目录,js目录css目录,index.html和对应的内容. 初步的代码如下: var ...

  2. Python之路【第二十篇】Tornado框架

    Tornado Tornado是使用Python编写的一个强大的.可扩展的Web服务器.它在处理严峻的网络流量时表现得足够强健,但却在创建和编写时有着足够的轻量级,并能够被用在大量的应用和工具中. 我 ...

  3. 获取APP最新版本的接口案例

    思路: 开发初期.安卓的应用可能没有上传到应用市场,可以把应用apk放到服务器上,供用户下载.把对应用的版本信息整理成为一个XML文件,放到服务器上,通过接口读取xml文件,获取有版本信息,然后安卓端 ...

  4. Json.Net 数据解析

    参考资料: 随笔分类 - Json.Net系列

  5. tyvj1096 数字组合

    描述 在N个数中找出其和为M的若干个数.先读入正整数N(1<N<100)和M(1<M<10000), 再读入N个正数(可以有相同的数字,每个数字均在1000以内), 在这N个数 ...

  6. R语言——七月

    这两个月没有写什么代码.也没做什么大项目,基本就是对以前写的那个用ggplot2可视化数据的项目做一些增增补补,大部分技术难关都在ggplot2和R语言EXCEL处理这里解决并总结了.然后业余帮人修改 ...

  7. Flex Builder快捷键

    Flex几个最重要的快捷键 代码助手:Ctrl+Space(简体中文操作系统是Alt+/) 快速修正:Ctrl+1 单词补全:Alt+/ 打开外部Java文档:Shift+F2 显示搜索对话框:Ctr ...

  8. 【转】8G内存下MySQL的优化详细方案

    对于任何一个数据库管理系统来说,内存的分配使用绝对可以算的上是其核心之一了,所以很多希望更为深入了解某数据库管理系统的人,都会希望一窥究竟,我也不例外. 这里给出方案 按照下面的设置试试看: key_ ...

  9. PHP 5.4 已废弃 magic_quotes_gpc,PHP安全转义函数详解(addslashes 、htmlspecialchars、htmlentities、mysql_real_escape_string、strip_tags)

    1. addslashes() addslashes()对SQL语句中的特殊字符进行转义操作,包括(‘), (“), (), (NUL)四个字符,此函数在DBMS没有自己的转义函数时候使用,但是如果D ...

  10. 【Python基础学习四】字符串(string)

    Python 字符串 字符串是 Python 中最常用的数据类型.可以使用引号('或")来创建字符串. 创建字符串很简单,只要为变量分配一个值即可.例如: var1 = 'hello' va ...