美文网首页前端之美
新手看JS中的面向对象

新手看JS中的面向对象

作者: E微客 | 来源:发表于2018-08-29 17:24 被阅读104次

面向对象

  面向对象是一种程序设计的思想,与面向过程不同,它引入了类的概念,将性质相似的一类物体抽象出来,作为设计图一般的存在,以实体的方式描述业务,重心放在了参与事务的对象身上,而不是逐步分离的步骤上。
  面向对象有三个特征:封装、继承、多态,关于继承,可以在读完本文后,去看看我的另一片文章,新手看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面向对象与其中创建方法基本结束了,如文章有问题,欢迎指正!!!

相关文章

  • 新手看JS中的面向对象

    面向对象   面向对象是一种程序设计的思想,与面向过程不同,它引入了类的概念,将性质相似的一类物体抽象出来,作为设...

  • JS面向对象精要(二)_函数

    JS面向对象精要(一)_原始类型和引用类型JS面向对象精要(二)_函数JS面向对象精要(三)_理解对象JS面向对象...

  • JS面向对象精要(三)_理解对象

    JS面向对象精要(一)_原始类型和引用类型JS面向对象精要(二)_函数JS面向对象精要(三)_理解对象JS面向对象...

  • JS面向对象精要(四)_构造函数和原型对象

    JS面向对象精要(一)_原始类型和引用类型JS面向对象精要(二)_函数JS面向对象精要(三)_理解对象JS面向对象...

  • JS面向对象精要(五)_继承

    JS面向对象精要(一)_原始类型和引用类型JS面向对象精要(二)_函数JS面向对象精要(三)_理解对象JS面向对象...

  • 2018-01-18

    js中的面向对象核心 js是基于对象的编程语言,在后面的学习中我们通过一种模式使其转化成为面向对象的语言。js面向...

  • 浅谈JS中的面向对象

    浅谈JS中的面向对象 本文主要说说本人在JS中对面向对象的理解。 计算机编程语言主要分为面向过程式编程和面向对象式...

  • 面向对象OOP--JS

    作者:烨竹 JS面向对象简介 JS名言:万物皆对象 JS面向对象比PHP简单很多;因为JS中没有class关键字,...

  • 在nodejs中面向对象:Bearcat

    JS中的面向对象 最最最开始,我们先来说说JS中的面向对象。 原型链 参考文章:图解Javascript原型链 J...

  • 面试题的总结与解答

    1,js中this指向的理解 在js面向对象编程里我们避免不了使用this,所以理解this指向对于在面向对象编程...

网友评论

本文标题:新手看JS中的面向对象

本文链接:https://www.haomeiwen.com/subject/brofwftx.html