JS是一种完全面向对象的程序设计语言,在面向对象处理方面,具有多种多样的实现方式,加之对象成员的动态性使得这门语言更加灵活;而js对象成员动态性也是创建和扩展对象的有力方式。

1 对象成员动态性

属性动态性:对于没有该成员属性的对象,可以直接采用赋值操作增加属性,

方法动态性:与属性动态性一样

比如:var obj=new Object();

属性动态性:obj.name='ffs';

方法动态性:obj.myThoed=function(){console.log('我是动态扩展的方法')};obj.myThoed();

js就是这样灵活;

2 创建对象

由于从语法层面没有类这种概念,与C#,Java这种语言不同,所以js里面采用函数来模拟类创建对象;

2.1 字面量创建对象

var obj={};这也是一个对象,常常临时封装一些成员而构成对象;

2.2 构造函数创建对象

var obj=new Object();这样通过Object构造函数也创建一个对象;与字面量均常常适用于临时封装一堆成员;不具有代码重用,也不具有对象类型。

2.3 工厂模式创建对象

工厂模式:通过一个函数模板创建一个对象的方式;

function Person(name,sex,age){

  var o=new Object(){};

  o.name=name;

  o.sex=sex;

  o.age=age;

  o.say=function(){console.log('说中国话')};

  return o;  

};

var p=Person('zhangsan','男',28);通过人的一些属性传入工厂函数创建人这个对象;这个工厂方法就像模板一样,我给你什么东西你给我创建什么;

特点:通过参数初始化要创建的对象,但是该对象没有具体的类型,只能创建一些简单的对象;

实用:常常用于一些简单对象的创建模板,这些对象不具有复杂的逻辑处理,比如坐标点point;

2.4 构造函数模式创建对象

构造函数创建对象在java,c#强类型语言中创建对象唯一方法,而在js中却只是创建对象的方法之一,你说js是不是很灵活;

如:function Person(name,sex,age){

  this.name=name;

  this.sex=sex;

  this.age=age;

  this.say=function(){console.log('说中国话')}; 

};

var p=new Person('zhangsan','男',28);与工厂模式不同的是使用new关键字创建对象,其本质过程其实是跟工厂模式一致的,只不过使用new关键字,这些细节过程被js引擎自动做了,那么其具体过程是怎样呢?

一样的 先构建一个对象var o=new Object();将this指向o,然后在最后加上return o;语句,只是这些被js引擎遮蔽了;

特点:构造函数创建的对象具有构造函数一说,如p的构造函数为Person,即 p.constructor=Person,而Person又是一个函数指针,也具有函数的特性;

实用:构造函数适用于那些需要对象类型的对象创建,且创建的对象复杂性比工厂模式要强,可以创建复杂逻辑的对象,代码重用性高;

对于typeof p来说这里既可以是Object 也可以是与Person相等;

函数特性:我们知道Person也是一个函数,那么也可以像函数一样调用,

如:var o=new Object();Person.call(o,'zhangsan','男',28);这样对象o的成员得到了扩展,而Person本身并不会有返回值,所以这里也仅仅是对象o的成员扩展,且o对象没有构造函数,这里充分体现了对象动态特性;

2.5 原型模式创建对象

在函数学习中我们知道函数包括2个重要成员,argument,length,prototype(原型对象),也就是说原型其本质上也是一个对象{};且原型属于函数,也属于函数创建的对象;

这么一说,Object也具有一个原型对象,我们所有的对象直接或间接继承自Object,其实也直接间接的拥有了Object的原型对象,就好比一棵树,或者说父子关系,一级一级的向下传递,上层不能访问下层的成员;

原型与对象,与函数相互引用;即Person.prototype,pertotype.constructor又指向Person;

创建对象:

function Person(){

   Person.prototype.name=name;

  Person.prototype.sex=sex;

  Person.prototype.age=age;

  Person.prototype.say=function(){console.log('说中国话')}; 

}

在原型对象上扩展的属性和方法又叫做原型属性,原型方法,或者说静态属性,静态方法;一个类型的原型对象只会存在一份,即便是该类型的对象,子对象都共同引用这个原型对象,对于原型属性来说任何一个对象修改,那么其他对象查看也会随机修改;

1)对象成员搜索机制:在访问一个对象是否具有某个成员时,其搜索顺序为,先查找是否存在实例成员,如果有则直接返回,没有则继续在原型上查找,对于原型连继承的继续向原型连上层查找,直到Object顶层

如:var p=new Person();p.name;name属性存在于原型属性中,这里需要2次遍历;

2)对象成员set机制:比如说查找Person的对象p的name属性,如果进行赋值,会将name属性变为实例属性(因为对象成员动态性),而对外暴露来说就遮蔽了原型对象中name原型属性。如果使用delete删除实例属性,自然下次又能继续访问该原型属性了。

如:var p=new Person();p.name='张三';nam就成了实例属性,进而遮蔽了原型属性name,如果delete p.name,下次也能访问p.name只不过现在又回到原型属性了;

这里引入一个属性检测方法:hasOwnerProperty();检测对象是否拥有实例属性,如p.hasOwnerProperty('name'):为false,如果p.name='zhangsan';这时候就为true了

hasPrototypeProperty():用于检测是否具有原型成员,如:p.hasPrototyPeroperty('name'),为true;如果p.name='zhangsan';这时候就为false了

in:用于检测对象是否能够访问到该成员,而不在乎该成员是否是实例还是原型成员,如:'name' in p 始终为true;

for in:用于对象所有可枚举的属性,而不在乎属性是否为实例还是原型属性,比如:for(var o in p){if(o=='name'){//----}}

Object.keys(对象):用于获取原型对象可以枚举的属性,其实就是获取对象所有可枚举的属性,同样的道理也可以使用数组下标运算符访问属性

如:Object,keys(Person.prototype);结果为['name','sex','age'],也可以使用[]访问你属性:p['name']结果为张三;

原型对象的问题:由于原型相当于静态成员被所有实例对象共享,那么就共享的属性修改就会存在同步问题,但是呢,原型优势又在于共享对象,节约了内存空间;

还有就是没有构造删除哪样通过传参来初始化对象。

2.6 组合使用构造原型模式创建对象

组合模式吸纳了构造和原型的有点,使得这种模式可以创建高度负责逻辑的对象,就像c#中的类一样,具体怎么做呢?

一般我们将对象属性放在实例属性中定义,而对象的方法我们放在原型对象中;

如:function Person(name){

    this.name=name;

    Person.pertotype.say=function(){

      console.log('说话');

    }

  }

特性:属性=》实例属性而不是定义为原型属性;方法=》通通放在原型中

实用:常常用于向c#哪有定义一个类,而真正创建多个对象;用于创建复杂逻辑的对象;而不是像构造或者原型他们那样,因为web页面常常是spa模式,一个类型对象一般只会有一个实例,因而使用简单方式创建对象

2.7 动态原型模式

所谓的动态原型是指在定义原型方法之前先判断一次,是否能够访问到该方法如果不存在再将该方法定义在原型中

如:function Person(name){

    this.name=name;

    Person.pertotype.say=function(){

      console.log('说话');

    }

    //先判断,再定义===》动态原型模式也

    if(typeof this.go!='function'){

      Person.prototype.go=function(){console.log('走路')};

    }

  }

2.8 稳妥构造模式

构造模式一般是这样

function Person(name,sex,age){

  this.name=name;

  this.sex=sex;

  this.age=age;

  this.say=function(){console.log('说中国话')}; 

};

但是如果在this并不安全的环境中使用这种构造,会造成一些问题,那么这样呢

function Person(name,sex,age){

  var o=new Object(){};  o.name=name;

  o.sex=sex;

  o.age=age;

  o.say=function(){rerturn name;};

  return o;  

};

这里除了say方法没有其他方法可以访问name变量,这样name暴露的入口仅有一个而已就会显得很安全,很稳妥,所就叫稳妥构造模式,哎这种概念这蛋疼

2.9 寄生构造模式

function Person(name,sex,age){

  var o=new Object(){};

  o.name=name;

  o.sex=sex;

  o.age=age;

  o.say=function(){console.log('说中国话')};

  return o;  

};

var p=Person('zhangsan','man','29');这样使用我们叫工厂模式,工厂模式并不具有构造模式的构造函数特性

var p=new Person('zhangsan','man','29');这样使用我们叫寄生构造模式,这样就具有工厂模式不具有的构造函数特性

总结:

js中由于SPA原因很多对象只会存在一份实例,且对象的逻辑不会很复杂,又加之对象成员动态性使得创建对象有很多方法方式,他们的共同基础都是对象动态特性

字面量,工厂,构造,原型,组合构造原型,寄生,稳妥,动态原型等等方式创建对象都有在某些场景下使用那种方式创建对象,且创建的对象所具有的特性也不一样,当然最重要的还是要数原型模式,原型对象

在js面向对象中既复杂又强大,又很重要,因此原型是必须掌握的,同样的组合构造原型模式也是创建对象最高级形式也是非常重要的。这些细节很多很多需要多实践才能掌握和熟练使用。

重操JS旧业第七弹:面向对象与对象创建的更多相关文章

  1. 重操JS旧业第十一弹:BOM对象

    BOM对象即浏览器内置对象,现今流行的浏览器内核有Safri,Firefox,Chrome,Opera,IE其中IE的兼容性是最蛋疼的在10及其过后还好点,但是现在IE基本上淘汰,而国内像360这种垃 ...

  2. 重操JS旧业第八弹:面向对象与继承

    js里面没有语言语法层面的继承机制,但这并不意味着js就不能实现继承,利用js属性和方法动态性来模拟实现继承,通过总结大概有如下方法实现: 1 原型链继承 我们知道原型在对象中扮演着重要的角色,函数本 ...

  3. 重操JS旧业第五弹:函数

    函数在任何编程语言中起着非常重要的位置,因为他是功能的最小单元,在js中函数是一种类型 Function 1 申明与定义 显示声明:function cc(){};函数名其实是函数的一个指针,函数名某 ...

  4. 重操JS旧业第十弹:闭包

    闭包是js最难理解,也是最蛋疼的一个名词,仿佛只可意会不可言传一样,有人说闭包说白了就是函数嵌套,也有人说闭包就是函数能够访问函数外部的变量,而内部的外部访问不了: 貌似都非常有道理,其实仔细想来只不 ...

  5. 重操JS旧业第六弹:基本类型包装

    在前面已经知道js中的类型有boolean,string,number,undefined,function,object,其中boolean,number,string为值类型.所谓的基本类型包装, ...

  6. 重操JS旧业第四弹:Date与Global对象

    1 Date原理 Date类型表示时间,js中采用UTC国际协调时间,以1971年1月1日0分0秒0微秒开始,经过的毫秒数来表示时间,比如一年的时间计算 1分:1000*60: 1小时:1000(毫秒 ...

  7. 重操JS旧业第三弹:Array

    数组在任何编程语言中都是非常重要的,因为函数在最大程度上代表了要实现的功能,而数组则是这些函数所要操作的内存一部分. 1 构建数组 js与其他非脚本语言的灵活之处在于要实现一个目标它可能具有多种方式, ...

  8. 重操JS旧业第九弹:函数表达式

    函数表达式,什么概念,表达式中的函数表达式. 1 函数申明 function 函数名([函数参数]){ //函数体 } js中无论像这样的显示函数什么放在调用之前还是调用之后,都不影响使用,因为js解 ...

  9. 重操JS旧业第二弹:数据类型与类型转换

    一 数据类型 1 js中的数据类型 1.1 数据类型列举 1)number类型 2)boolean类型 3)string类型 4)对象类型 5)函数类型 6)undefined类型 1.2 数据类型获 ...

随机推荐

  1. hdu 1875 畅通project再续

    链接:hdu 1875 输入n个岛的坐标,已知修桥100元/米,若能n个岛连通.输出最小费用,否则输出"oh!" 限制条件:2个小岛之间的距离不能小于10米,也不能大于1000米 ...

  2. c++中的对象引用(object reference)与对象指针的区别

    ★ 相同点: 1. 都是地址的概念: 指针指向一块内存,它的内容是所指内存的地址:引用是某块内存的别名. ★ 区别: 1. 指针是一个实体,而引用仅是个别名: 2. 引用使用时无需解引用(*),指针需 ...

  3. BZOJ 3401: [Usaco2009 Mar]Look Up 仰望( 单调栈 )

    n <= 105 , 其实是10 ^ 5 ....坑...我一开始写了个模拟结果就 RE 了.. 发现这个后写了个单调栈就 A 了... ---------------------------- ...

  4. ZOJ 2856 Happy Life 暴力求解

    因为是Special Judge 的题目,只要输出正确答案即可,不唯一 暴力力求解, 只要每次改变 happiness 值为负的人的符号即可. 如果计算出当前人的 happiness 值为负,那么将其 ...

  5. ZOJ 2853 Evolution 【简单矩阵快速幂】

    这道题目第二次看的时候才彻底理解了是什么意思 把题目转化为数学模型分析后就是 有一个初始序列, 有一个进化率矩阵 求的是初始序列 与进化率矩阵进行 m 次运算后, 初始序列最后一位的答案 那么显然,可 ...

  6. IOS7修改Navigation Bar上的返回按钮文本颜色,箭头颜色以及导航栏按钮的颜色

    解决方法 1: 自从IOS7后UINavigationBar的一些属性的行为发生了变化.你可以在下图看到: 现在,如果你要修改它们的颜色,用下面的代码: 1 2 3 4 self.navigation ...

  7. 全球在一个 level 上思考的价值观和想法是一样的(转)

    近日,福布斯中文版总编辑周建工对话马云,谈到腾讯频繁的大笔收购,马云点评称腾讯收购的所有的案子,老百性都看得懂,这就错了.战略就像买股票一样,如果老太太都开始买股票了,一定有问题. 以下是对话内容,转 ...

  8. JMS和消息驱动Bean(MDB)

    一.说明 本示例使用的ActiveMQ作为消息中间件,服务器为Glassfish,使用JMS发送消息,在MDB接收到消息之后做打印输出. 二.ActiveMQ安装配置 1.安装console war包 ...

  9. hdu3483之二项式展开+矩阵快速幂

    A Very Simple Problem Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Ot ...

  10. Unity3d 网络编程(二)(Unity3d内建网络各项參数介绍)

    这里是全部Unity3d在网络中能用到相关的类及方法.纵观參数功能, Unity3d来写一个手游是不二的选择: RPC 能够传递的參数 int float string NetworkPlayer N ...