新手看JS中的面向对象

面向对象

  面向对象是一种程序设计的思想,与面向过程不同,它引入了类的概念,将性质相似的一类物体抽象出来,作为设计图一般的存在,以实体的方式描述业务,重心放在了参与事务的对象身上,而不是逐步分离的步骤上。
  面向对象有三个特征:封装、继承、多态,关于继承,可以在读完本文后,去看看我的另一片文章,新手看JS的六张继承方式,这里暂且先不多做解释。

与面向过程的区别

  这里借用一下百度知道上某位仁兄的解释:
  例如五子棋游戏,面向过程的设计思路就是首先分析问题的步骤:
  1、开始游戏,
  2、黑子先走,
  3、绘制画面,
  4、判断输赢,
  5、轮到白子,
  6、绘制画面,
  7、判断输赢,
  8、返回步骤2,
  9、输出最后结果。

  把上面每个步骤用分别的函数来实现,问题就解决了。

  而面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为 :
  1、黑白双方,这两方的行为是一模一样的,
  2、棋盘系统,负责绘制画面,
  3、规则系统,负责判定诸如犯规、输赢等。

  第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的i变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。
  以上,两种模式的区别,由此可见一斑。

JS中的对象

  JS是解释性的脚本语言,对于类的概念并没有JAVA那般严谨和规范,且拥有自己的特性和方法。
  创建对象的过程,便是画一份设计图,JS一共提供了 7 种创建的方式(来自高程三),包括:
  1.工厂模式
  2.构造函数模式
  3.原型模式
  4.组合使用构造函数模式和原型模式
  5.动态原型模式
  6.寄生构造函数模式
  7.稳妥构造函数模式
  其中使用最广泛、认同度最高的方式是第四种:组合使用构造函数模式和原型模式,下面对每种方式进行粗略的描述。

创建对象

1.工厂模式

function createPerson(name,age){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.sayName = function(){
        alert(this.name)
    };
    return o;
}
var person = createPerson("亚当",99);

  接收两个参数,在函数内部创建一个对象,然后将参数绑定后再返回,可以实现封装一个类的功能,但缺点是所有的对象的都是Object,无法准确判断它们的类型,比如“人”类是Object,“动物”类也是Object。
  于是出现了构造函数模式。

2.构造函数模式

function Person(name,age){    //注意:首字母大写(惯例)
    this.name = name;
    this.age = age;
    this.sayName = function(){
        alert(this.name)
    };
}
var person = new Person("亚当",99);

  不用return对象,将属性和方法直接给了this对象,这样便可以用alert(person instanceof Person);//ture来检测对象的类型,这意味着将来可以将Person标识为一种特定的类型,更利于类的概念。
  有了“类”的模板,就可以照着模子捏人了,使用构造函数创建对象,必须使用到new操作符,若是当做普通函数来使用,就相当是为全局对象添加了属性,最后会出现window.sayName();//打印出传入的name变量,而使用new来调用构造函数会经历一下四个步骤:
  1.创建一个新对象
  2.将构造函数的作用域赋给新对象
  3.执行构造函数中的代码(为新对象添加属性)
  4.返回这个新对象
  构造函数模式同样有其缺陷,比如上面的例子中,如果创建了两个“人”,就有两个同样的sayName()方法,可以实现同样的功能(打印名字),一个两个还好,如果我们有成百上千个Person实例的话,name就有千百个satName()方法,这在内存中的开销无疑是极大的,既然是同样的功能,那么让它们共同使用一个函数就足够了,因此可以将这个函数摘出来,这样写:

function Person(name,age){    //注意:首字母大写(惯例)
    this.name = name;
    this.age = age;
    this.sayName = sayName;
}
function sayName(){
    alert(this.name);
}

  将内部引用外部命名的函数,而将函数体放在外面,这样指向的就是同一个方法了,只是如此一来sayName这个方法相当于是放在了全局作用域中,但方法本身却只想让Person的对象使用,大炮打蚊子,有点小尴尬,同时类的封装性也遭到了破坏,由此问题,便引出了第三种创建方法——原型模式。

3.原型模式

  每个构造函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途,便是容纳同一类下所有实例公有的方法和属性,写法如下。

function Person(){
}
Person.prototype.name = "亚当";
Person.prototype.age = "99";
Person.prototype.sayName= function(){
    alert(this.name)
};
var person = new Person();

  或者写的更简洁一些:

Person.prototype = {
    name : "亚当",
    age : "99",
    sayName : function(){
        alert(this.name);
    }
}

  好处很明显,同一类下所有对象可以共享属性和方法,当然,缺点一样明显,创建对象的时候无法传入自定义参数,除非设置如person1.name = "夏娃";才会覆盖掉原来的名字,更为严重的是,如果Person的原型中包含了一个数组(引用类型),如果一个对象修改了这个数组,其他对象的数组都会发生变化,因为引用类型的变量指向的是同一块内存地址,这样事情就变得很麻烦了。
  构造函数模式无法设置共享的属性,而原型模式无法自定义属性,那如果将两者优点结合起来,那不是天下无敌了吗!?
  所以,我们有了第四种方式——组合使用构造函数模式和原型模式。

4.组合使用构造函数模式和原型模式

  不多说,直接上代码:

function Person(name,age){
    this.name = name;
    this.age = age;
}
Person.prototype = {
    constructor : Person,    //确保实例的构造函数指向Person
    sayName : function(){
        alert(this.name);
    }
}
var person = new Person("亚当",99);

  可以自定义的属性(包括引用类型)都放在构造函数里,随便修改都不会影响其他实例,而公共的方法则放在原型对象中,避免资源浪费。
  OJBK,万事大吉!这种模式也是目前在ECMAScript中使用最广泛、认同度最高的一种创建自定义的方法。
  至此,基本的几种已经介绍完了,后面三种会简单介绍一下,不想继续深入的小伙伴们可以在这里搬小板凳撤了


5.动态原型模式

  当我们为对象定义一个方法时,有时可能存在冲突,必要的情况下,我们可以检查某个应该存在的方法是否有效,如果有效,看一眼走人,如果无效,我们再初始化原型。

function Person(name,age){
    this.name = name;
    this.age = age;
}
//方法
if(typeof this.sayName != "function"){    //如果sayName不是函数
    Person.prototype.sayName= function(){
        alert(this.name)
    }
};

  如上述代码,仅当sayName方法不存在的情况下,才会在原型中添加此方法,而且只会在初次调用构造函数的时候才会执行这条语句,一旦定义后,由于是定义在原型上的方法,所有对象之后都可以直接调用了。
  这种方法的缺陷,同样是不能重写原型,否则会切断现有实例与心源性之间的联系。

6.寄生构造函数模式

  唔...在前面几种模式都不适用的情况下(应该不会遇到吧...),可以使用寄生构造函数模式创建对象,基本思想是:创建一个函数,其作用仅仅只是封装创建对象的代码,然后再返回新创建的对象。

function Person(name,age){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.sayName = function(){
        alert(this.name)
    };
    return o;
}
var person = new Person("亚当",99);

  除了用new操作符以外,其余写法和工厂模式一模一样,一般会在特殊情况下使用它,例如要创建一个数组对象(Array),但在这个对象中要添加新的方法,直接修改Array的构造函数的话,程序里所有的数组都变了,GG,所以可以使用这个模式。代码如下:

function specialArray(){
    var arr = new Array();
    arr.newFunction = function(){
        alert("我叫数组的新方法")
    }
    balabalabala...  //其他要添加的新方法或操作
    return arr;
}
var list = new specialArray();
list.newFunction();  //我叫数组的新方法 

  要注意,返回的对象与构造函数之间没有关系,不能使用instanceof来确定对象类型,这一点与工厂模式相同,因此建议尽可能不要使用这种方法。

7.稳妥构造函数模式

  稳妥对象,指的是没有公共属性,也不引用this对象,这种模式适合在禁止使用 this 和 new 的环境中,或者在防止数据被其他应用程序(如Mashup程序)改动时使用,除了不使用 this 和 new 以外,和寄生构造函数模式类似,代码如下:

function Person(name,age){
    var o = new Object();
    //可以在这里定义私有变量和属性
    o.sayName = function(){
        alert(name)
    };
    return o;
}
var person = Person("亚当",99);
person.sayName();    //亚当

  除了使用sayName() 方法外,没有其他办法访问 name 的值,方法中定义的私有变量和属性也无法影响传入的 name 值,安全性杠杠的!
  当然,与寄生构造函数模式、工厂模式相同,它也不能使用 instanceof 检测其类型。

总结

  至此,JS面向对象与其中创建方法基本结束了,如文章有问题,欢迎指正!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  •   面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意...
    霜天晓阅读 2,092评论 0 6
  • 博客内容:什么是面向对象为什么要面向对象面向对象编程的特性和原则理解对象属性创建对象继承 什么是面向对象 面向对象...
    _Dot912阅读 1,398评论 3 12
  • 面向对象的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。ECMAScr...
    DHFE阅读 960评论 0 4
  • 面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的慨念,而通过类可以创建任意多个...
    threetowns阅读 872评论 0 4
  • 我发小给我打电话,告诉我,艳子出车祸死了。 艳子是我高中同学,前两天我们还在同学群里讨论育儿的问题,这一大早的就接...
    艾彼撩人生阅读 201评论 0 0