网站首页 » 前端开发 » JavaScript » JavaScript 面向对象编程详解
上一篇:
下一篇:

JavaScript 面向对象编程详解

前言

JavaScript 面向对象编程估计你平时也看到了不少,只不过你可能不知道它就是 JavaScript 面向对象编程,这也就是为什么你会来到这里的原因。话不多说,我们马上开始面向对象之旅。

什么是面向对象编程

面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)简单的说就是用对象的思想去编程,也就是创造一个对象,然后往这个对象身上添加若干属性和方法。

面向对象编程特点

1.封装:对象里面有一系列的属性和方法,但只能通过这个对象来访问这些属性和方法。

2.继承:从已有的对象上继承新的对象。

3.抽象:把一些共性的东西抽出来。

4.多态:多对象的不同形态,如果学过Java 的朋友应该知道多态是什么。

系统对象

下面这个写法估计你也许有见过或者用过:

var arr = new Array();

上面的Array()就是系统自带的对象,它里面就封装一很多方法及属性,比如:

arr.sort() // 给数组排序
arr.push() // 在数组末尾添加一个或者多个元素,并返回数组长度。
arr.shift() // 删除数组的第一个元素,返回删除的值
arr.unshift() // 在数组前添加元素,返回数组长度
arr.pop() // 删除数组最后一个元素,返回删除的值
arr.concat- // 把两个数组拼接起来,并返回结果
arr.reverse- // 将数组反序
arr.toString() // 将数组转换为字符串,并返回结果
arr.splice() // 删除元素,并向数组中添加新元素
arr.length // 数组元素个数
arr.constructor // 返回创建此对象的数组函数的引用

虽然像这样的系统对象有很多,但有时候也未必能满足我们的需求。为了解决这个问题,我们必需得自己来封装一个可以满足自己项目需要的对象。现在我们来创建一个面向对象的程序。

首先我们必需得知道面向对象的基本写法及组成,对旬的组成包括两样东西:属性(对象下的变量,比如上面的:length、constructor)和方法(对象下的函数,比如上面的:shift()、pop())。

自定义对象

下面我们来看一个简单的面向对象编程的例子:

function Person(name){
    console.log(this); // 这里打印出来的 this 为 window 对象。
    var obj = new Object();
    obj.name = name;
    obj.say = function(){
        alert("大家好,我是" + this.name);
    };
    return obj;
}

var p1 = Person("小白");
p1.say();

var p2 = Person("小云");
p2.say();

但是我们会发现,系统自带的对象是通过 new 关键字来创建实例的。但我们自己封装的对象显然不是,而是对象内部创建对象。这会造成我们创建的对象内部 this 指向 window 而不是我们创建的对象本身(p1、p2)。现在我们不妨按照系统的格式来创建对象实例。于是我们可以把上面的代码作如下修改:

function Person(name){
    console.log(this); // 此时打印出来的就是 Person 的实例
    this.name = name;
    this.say = function(){
        alert("大家好,我是" + this.name);
    };
}

var p1 = new Person("小白");
p1.say();

var p2 =  new Person("小云");
p2.say();

console.log(p1.say==p2.say); // false

像上面这样写后,Person 对象里就不用返回对象了,用 new 的方法创建实现时,系统会默认返回当前对象实例(隐式返回),而 new 后面的函数叫做构造函数。但是这还没完,当你尝试比较p1 、 p2 (console.log( p1.say == p2.say ))时你会发现返回的是 false 。为什么是 false 呢?这里就涉及到变量的赋值问题了,对于基本类型来说赋值的时候只是值复制,而对象类型则是址传递。至于它们之间的区别你可以搜索相关资料作进一步了解,在这里就不展开了。

这也就从侧面说明了,我每创建一个对象实例时都会创建一个这样的方法。如果创建的对象实例比较少那就凑合着用也就算了,但有时候我们会创建很多个对象实例,此时就会创建了很多个 say 方法,这也不算什么,重点是创建了这么多个重复的方法影响性能,这个是不可容忍的。那有什么办法呢?我们可以通过 prototype (原型:重写对象方法,让相同的方法在内存中只存在一份以提高性能)来给对象添加共用的方法,如果属性也是共用的,那么也可以通过  prototype 来添加。我们还是来看看代码是如何实现的吧。

function Person(name){
    this.name = name;
}

Person.prototype.say = function(){
    alert("大家好,我是" + this.name);
}

var p1 = new Person("小白");
p1.say();

var p2 =  new Person("小云");
p2.say();

console.log(p1.say==p2.say); // true

注意:为了与系统对象统一,我们在做面向对象编程时应该对自己有点要求:

1.对象名首字母要大写

2.共用的属性和方法可以写在原型上

总结

新手写面向对象编程的一般套路:先写出一般函数,然后再改成面向对象写法。

普通方法变形

1.尽量不要出现函数嵌套函数

2.全局变量就是对象属性

3.把onload中不是赋值的语句放到单独的函数中

改成面向对象

1.全局变量就是属性

2.函数就是方法

3.onload 中创建对象

4.修改 this 指向问题

下面是一个完整的演变例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>面向对象编程-云库网</title>
    <meta name="description" content="面向对象编程详解" />
    <meta name="keywords" content="面向对象编程" />
    <style>
        #circle{
            position: absolute;
            width: 100px;
            height: 100px;
            background: #ccc;
            border-radius: 50%;
            line-height: 100px;
            text-align: center;
            cursor: pointer;
        }
    </style>
</head>
<body>
<div id="circle">拽我</div>
<script>
/* ----- 普通写法 ----- */
window.onload = function(){
    var disX = 0;
    var disY = 0;
    var iCircle = document.getElementById("circle");
    iCircle.onmousedown = function(ev){
        var ev = ev || window.event; 
        disX = ev.clientX - iCircle.offsetLeft;
        disY = ev.clientY - iCircle.offsetTop;

        document.onmousemove = function(ev){
            var ev = ev || window.ev;
            iCircle.style.left = ev.clientX - disX + "px";
            iCircle.style.top = ev.clientY - disY + "px";
        }
        document.onmouseup = function(ev){
            document.onmousemove = null;
            document.onmouseup = null;
        }
        return false;
    }
}
/* ----- 普通写法 END ----- */


/* ----- 普通方法变形 ----- */
var disX = 0;
var disY = 0;
var iCircle = null;
window.onload = function(){
    iCircle = document.getElementById("circle");
    init();

    function init(){
        iCircle.onmousedown = iDown;
    }

    function iDown(ev){
        var ev = ev || window.event; 
        disX = ev.clientX - iCircle.offsetLeft;
        disY = ev.clientY - iCircle.offsetTop;
        document.onmousemove = iMove;
        document.onmouseup = iUp;
        return false;
    };

    function iMove(ev){
        var ev = ev || window.ev;
        iCircle.style.left = ev.clientX - disX + "px";
        iCircle.style.top = ev.clientY - disY + "px";
    }

    function iUp(ev){
        document.onmousemove = null;
        document.onmouseup = null;
    }
}
/* ----- 普通方法变形 END  ----- */


/* ----- 改成面向对象  ----- */
window.onload = function(){
    var drag = new Drag("circle");
    drag.init();
}

function Drag(id){
    this.disX = 0;
    this.disY = 0;
    this.iCircle = document.getElementById(id);
}

Drag.prototype.init = function(){
    var _this = this;
    this.iCircle.onmousedown = function(ev){
        var ev = ev || window.event; 
        _this.iDown(ev);
        return false;
    }
}
        
Drag.prototype.iDown = function(ev){
    var _this = this;
    this.disX = ev.clientX - this.iCircle.offsetLeft;
    this.disY = ev.clientY - this.iCircle.offsetTop;
    document.onmousemove = function(ev){
        var ev = ev || window.event;
        _this.iMove(ev);
    }
    document.onmouseup = function(ev){
        _this.iUp(ev);
    }
}

Drag.prototype.iMove = function(ev){
    this.iCircle.style.left = ev.clientX - this.disX + "px";
    this.iCircle.style.top = ev.clientY - this.disY + "px";
}

Drag.prototype.iUp = function(ev){
    document.onmousemove = null;
    document.onmouseup = null;
}
/* ----- 改成面向对象 END ----- */

</script>
</body>
</html>

DEMO 演示:http://yunkus.com/demo/javascript-object-oriented-programming/

注意:当我们通过原型来给对象添加方法时,尽量不要修改系统对象原型中的方法。比如:

Array.prototype.push = function(){......}

这样会很容易造成系统对象被修改过的方法功能失效。而如果你重写这个方法时把这个方法原本的功能保留下来,可以像下面这样重写 push() 方法:

var arr = [1,2,3];
Array.prototype.push = function(){
    for(var i=0;i<arguments.length;i++){
        this[this.length] = arguments[i];
    }
    return this.length;
}
arr.push(4,5,6);

如果想给push 方法添加更多的功能,就可以往下面的代码里追加功能代码。

到此,我想你已经对面向对象的编程有所了解,但这估计也不你想要的,因为你想要的是面向对象编程的思想,那行动就是你座右铭。

 

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/javascript-object-oriented-programming/

发表评论

电子邮件地址不会被公开。 必填项已用*标注

评论 END