在 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. [Maven] 变态问题收集

    1.新换的系统,eclipse运行起来之后,一直报错Missing artifact 折腾了好久,没法了,把服务器上的仓库直接压缩,传到本地计算机上,覆盖本地仓库,完美解决这个问题! 2.tomcat ...

  2. mysql order by 优化 |order by 索引的应用

    在某些场景,在不做额外的排序情况下,MySQL 可以使用索引来满足 ORDER BY 子句的优化.虽然 ORDER BY并不完全精确地匹配索引,但是索引还是会被使用,只要在WHERE子句中,所有未被使 ...

  3. Spring BeanNameAutoProxyCreator 与 ProxyFactoryBean区别

    一般我们可以使用ProxyBeanFactory,并配置proxyInterfaces,target和interceptorNames实现,但如果需要代理的bean很多,无疑会对spring配置文件的 ...

  4. 深入理解javascript原型和闭包(11)——执行上下文栈

    继续上文的内容. 执行全局代码时,会产生一个执行上下文环境,每次调用函数都又会产生执行上下文环境.当函数调用完成时,这个上下文环境以及其中的数据都会被消除,再重新回到全局上下文环境.处于活动状态的执行 ...

  5. Java_Array数组1

    package org.array.demo; /** * 数组可以看成一组相同属性的元素的集合 * 1.静态声明 * 静态声明的格式: * 数组类型[] 标识 = new 数组类型[数组长度]; * ...

  6. maven项目打包成可执行的jar

    编写功能类: package com.hpay.FileToZkUtil; import java.io.File; import java.io.FileInputStream; import ja ...

  7. map set区别

    STL中的容器有顺序容器 (vector,list,deque),关联容器(map,set)还有一些其他容器.根据不同的场合选择不同的容器,会有意想不到的收获. Map是单词mapping(映射)的缩 ...

  8. nginx实现本地图片生成缩略图

    nginx可以实现图片的缩略图效果,很多网站为了前端静态资源相应的性能会给大图自动生成一个小图,比如我们经常会在网上看到bd_64x64.png这种格式,淘宝上的小图经常会看到xxx.jpg_100x ...

  9. MySQL5.6 PERFORMANCE_SCHEMA 说明

    背景: MySQL 5.5开始新增一个数据库:PERFORMANCE_SCHEMA,主要用于收集数据库服务器性能参数.并且库里表的存储引擎均为PERFORMANCE_SCHEMA,而用户是不能创建存储 ...

  10. laravel 输出sql

    $queries = DB::getQueryLog(); $a = end($queries); $tmp = str_replace('?', '"'.'%s'.'"', $a ...