我理解中的JS面向对象

Author Avatar
Crown 7月 12, 2017
  • 在其它设备中阅读本文章

面向对象,已经成为日常编程过程中绕不过去的一道坎了.熟练的掌握面向对象相关知识,包括如何创建对象,工厂模式的使用,构造函数的产生,原型的出现,原型链的使用等一系列知识,对我们更好的编写组织我们的代码有着革命性的意义.

这里我想通过代码的演示,来向大家展示我理解中的JS面向对象相关知识.

Talk is cheap,show mew the code!

创建对象

假如现在需要我们来编写一个游戏,游戏里面的用兵单位是机器人,这时我们需要创建一个机器人对象.这里我们可以这样来创建我们的机器人对象.(伪码为主,别太认真)

// 用 new 的 方式
var robot = new Obeject();

// 用对象字面量的方式
var robot = {};

这里来看明显后面的方式看起来比较简洁,所以我们这里主要使用后者来创建我们的对象. 这时,我们需要给我们的 robot 赋予一些方法,例如他的代号code,他的生产序号number,他的攻击方式attackMode等属性,这时我们就可以这么来写.

// 第一种写法
var robot = {};
robot.code = 'r007';
robot.number = '666';
robot.attackMode = function (){
    // 拿小拳拳捶胸口
    ...
}

// 第二种写法
var robot = {
    code: 'r007',
    number: '666',
    attackMode: function(){
        // 拿小拳拳捶胸口
        ...
    }
}

这时我们访问我们的机器人对象属性时就可以通过以下两种方式来访问.

  • robot.code
  • robot['code']

但这时的我们肯定不会只满足制造一个机器人呀,这种机器人我们需要量产时,但是我们又不可能使用我们上面这种方法来制造多个机器人,这样写出来的代码量会有很多重复无用的代码,这时我们的工厂模式就应运而生.

// 这种方式太过于臃肿,你创建1000个机器人难道会像这样去声明1000个对象吗?
var robot = {
    code: 'r007',
    number: '666',
    attackMode: function(){
        // 拿小拳拳捶胸口
        ...
    }
}

var robotA = {
    code: 'r008',
    number: '777',
    attackMode: function(){
        // 拿小拳拳捶胸口
        ...
    }
}

工厂模式

工厂模式形象店来说就是我们自己创建一个模具,然后用这个模具来量产.

var createRobots = function(code,number){
    // 新建一个对象
    var robot = new Object();
    robot.code = code;
    robot.number = number;
    robot.attackMode = function (){
        // 拿小拳拳捶胸口
        ...
    }
    // 返回一个对象
    return robot;
}
// 示范的创建两个对象
var robotA = createRobots('r007','666');
var robotB = createRobots('r008','777');

这个时候看着很美好,但是渐渐地有些人发现了一些不同寻常的地方,那就是用工厂模式造出来的对象,我们没有办法去识别对象的类型,因为它们直接由 Object() 构造函数创建,原型链上只有 Object.prototype 对象.所以这里我们的构造函数也应运而生

构造函数

var Robot = function(code,number){
    this.code = code;
    this.number = number;
    this.attackMode = function(){
        // 拿小拳拳捶胸口
        ...
    }
}
var robotA = new Robot('r007','666');
var robotB = new Robot('r008','777');
// 用instanceof来识别对象的类型
console.log(robotA instanceof Robot);// true

使用构造函数虽然解决了我们类型判断的问题,但是,他还是一个对象的复制过程,跟上面的工厂模式还是有一定的相似之处,所以他也存在这工厂模式的另一个问题,就是我们的attackMode这个方法随着这个对象被声明1000个,这个方法也会因为属于不同的实例而在内存中重复声明1000次.在这里,就需要用到原型相关知识了.

这里如果还有对 new 的过程不是很了解的同学可以看下这里这篇文章

原型

当我们在创建我们的对象时,可以根据相应的需求,将一些属性或者方法挂载在我们原型对象的prototype上面,这样我们每一个new出来的实例,都有一个_proto_属性,该属性指向构造函数的原型对象,通过这个属性,可以让我们的实例对象也访问到原型上面的方法,这样我们就完美解决了上面我们所说的问题.具体代码看下面:

var Robot = function(code,number){
    this.code = code;
    this.number = number;
}
Robot.prototype.attackMode = function(){
    // 拿小拳拳捶胸口
    ...
}
var robotA = new Robot('r007','666');
var robotB = new Robot('r008','777');

但这里又出现了一个小问题,如果我们所有的原型上面的方法都像这样来写,那就成下面这个样子了?

Robot.prototype.attackMode = function(){
    // 拿小拳拳捶胸口
    ...
}
Robot.prototype.defendMode = function(){
    // 拿胸口给别人锤
    ...
}
....

这样的代码是不是看着不够优雅?所以这个时候我们可以采用下面这种写法来替代上面的.

var Robot = function(code,number){
    this.code = code;
    this.number = number;
}
Robot.prototype = {
    constructor: Robot,
    attackMode: function(){
        // 拿小拳拳捶胸口
        ...
    },
    defendMode: function(){
        // 那胸口给别人锤
        ...
    },
    ...
}

原型链

到上面为止,我们造机器人已经搞得差不多了,但现在又来了一个新的需求,就是要我们去造一批新的机器人SSS,他是在上一篇机器人的本质上升级过来的,要求我们继承上一个机器人对象,这时我们就需要根据原型链来优雅的实现这一功能了,代码如下:

var Robot = function(code,number){
    this.code = code;
    this.number = number;
}
Robot.prototype = {
    constructor: Robot,
    attackMode: function(){
        // 拿小拳拳捶胸口
        ...
    },
    defendMode: function(){
        // 那胸口给别人锤
        ...
    },
    ...
}

// 机器人SSS,构造函数的继承
var RobotSSS = function (code,number,size){
    Robot.call(this,code,number);
    this.size = size;
}
// 继承原型
RobotSSS.prototype = new Robot(code,number)
// 添加更多方法
RobotSSS.prototype.actingCute = function(){
    //拿大拳拳捶你胸口
    ...
}

这里如果大家有更好的方法,欢迎大家来交流探讨~~

到此,关于我理解的JS面向对象该讲的都已经将得差不多了,如果那里有错误的地方,欢迎来指正,谢谢!!!


随着我自己个人的技术水平的提高,我也会尽最大力量去原创一些有价值有内容的文章出来。在此期间我的文章会同步更新在以下地方,欢迎大家在自己长逛的网站中关注或者star我的Github来了解我的最新消息!!!

未经允许,不准转载