javascript面向对象分层思维

js本身不是面向对象语言,在我们实际开发中其实很少用到面向对象思想,以前一直以为当要复用的时候才封装成对象,然而随着现在做的项目都后期测试阶段发现面向对象的作用不仅仅只是复用,可能你们会说面向对象还有继承,多态的概念,但在javascript里面多态的概念是不存在,而继承由于web页面的必须先下载js在运行导致js的继承不能像后台那么灵活而且js没有重载以及重写不方便(而且js中重写的意义不是很大),所以在js中很少用到面向对象,可能在一些插件中会看到对象的写法,写js的都会有同样的感觉在写一个插件的时候一般是先用面相过程把插件功能写出来,然后在重构改成对象的方法.但在实际项目开发中要求时间进度和开发成本很少会有那么宽松的时间让你先用面向过程实现功能在重构.实际开发中我们基本都是用面相过程写完就直接提交了.

这种写法发现一个问题就是,当你把这个页面的写完了之后过一段时间突然这个页面的功能需求或是页面布局要调整,你在看这个页面的代码,一下很难快速的把整个页面的代码逻辑步骤梳理清楚,我相信很多写前端都要同感吧! 举个例子:我几年前写的放大镜插件,现在我在放出来发现我写的这个插件在谷歌浏览器第一次渲染的时候没有效果,代码如下:

  1 /// <reference path="../jquery11.js" />
  2 (function ($) {
  3     $.fn.extend({
  4         jqoom: function (potions) {
  5             var settings = {
  6                 width: 350,
  7                 height: 350,
  8                 position: "right"
  9             }
 10             if (potions) {
 11                 $.extend(settings, potions);
 12             }
 13             var ImgUrl = $("img", this).attr("src");
 14             var ImgMinWidth = $("img", this).width();
 15             var ImgMinHeigth = $("img", this).height();
 16             var ImgWidth = 0;
 17             var ImgHeight = 0;
 18             var de = true;
 19
 20             $(this).hover(function (e) {
 21             }, function () {
 22                 $("#jqoomz").remove();
 23                 $(document).unbind("mousemove");
 24                 $("#jqoomy").remove();
 25
 26                 de = true;
 27             });
 28             $("img", this).hover(function (e) {
 29                 var pagex = e.x || e.pageX;
 30                 var pagey = e.y || e.pageY;
 31                 var pagex1 = 0;
 32                 var pagey1 = 0;
 33                 var leftcha = 0;
 34                 var topcha = 0;
 35                 _this = $(this).parents("div");
 36                 if ($("#jqoomz").length == 0) {
 37                     _this.after("<div id=‘jqoomz‘></div>");
 38                     var obj = new Image();
 39                     obj.src = ImgUrl;
 40                     obj.onload = function () {
 41                         if (de && obj.height > 0) {
 42                             de = false;
 43                             ImgWidth = obj.width;
 44                             ImgHeight = obj.height;
 45                             finder.call(_this.find("img")[0]);
 46                         }
 47                     };
 48                     $("#jqoomz").width(settings.width).height(settings.height).offset({
 49                         left: $(_this).outerWidth() + $(_this).offset().left,
 50                         top: $(_this)[0].offsetTop
 51                     }).append($("<img></img>").attr("src", ImgUrl));
 52                     if (de && obj.height > 0) {
 53                         de = false;
 54                         ImgWidth = obj.width;
 55                         ImgHeight = obj.height;
 56                         finder.call(this);
 57                     }
 58                 }
 59                 function mover(event) {
 60                     var pagex2 = event.x || event.pageX;
 61                     var pagey2 = event.y || event.pageY;
 62                     if (parseInt(pagex2 + leftcha) <= parseInt($(_this).width() + $(_this).offset().left) && pagex2 >= leftcha + $(_this).offset().left) {
 63                         $(this).offset({left: pagex2 - leftcha});
 64                     } else {
 65                         if (parseInt(pagex2 + leftcha) > parseInt($(_this).width() + $(_this).offset().left) && pagex2)
 66                             $(this).offset({left: $(_this).width() + $(_this).offset().left - leftcha * 2});
 67                         else
 68                             $(this).offset({left: $(_this).offset().left});
 69                     }
 70                     if (parseInt(pagey2 + topcha) <= parseInt($(_this).height() + $(_this).offset().top) && pagey2 >= topcha + $(_this).offset().top) {
 71                         $(this).offset({top: (pagey2 - topcha)});
 72                         //document.getElementById("move").style.top = (pagey2 - (this.pagey - this.divtop)).toString() + "px";
 73                     } else {
 74                         if (parseInt(pagey2 + topcha) > parseInt($(_this).height() + $(_this).offset().top))
 75                             $(this).offset({top: ($(_this).height() + $(_this).offset().top - topcha * 2)});
 76                         //document.getElementById("move").style.top = (this.height - this.divHeight).toString() + "px";
 77                         else
 78                             $(this).offset({top: $(_this).offset().top});
 79                         //document.getElementById("move").style.top = "0px"
 80                     }
 81                     var bilx = ($(this).offset().left - $(_this).offset().left) / (ImgMinWidth / ImgWidth);
 82                     var bily = ($(this).offset().top - $(_this).offset().top) / (ImgMinHeigth / ImgHeight);
 83                     $("#jqoomz img").css({"margin-left": -bilx, "margin-top": -bily});
 84                 }
 85
 86                 function finder() {
 87                     if (parseFloat($(this).offset().top + $(this).height() - (ImgMinHeigth / ImgHeight * ImgMinHeigth)) >=
 88                         parseFloat(pagey - ImgMinHeigth / ImgHeight * ImgMinHeigth / 2) && parseFloat(pagey - ImgMinHeigth / ImgHeight * ImgMinHeigth / 2) >=
 89                         parseFloat($(this).offset().top)) {
 90                         pagey1 = (pagey - ImgMinHeigth / ImgHeight * ImgMinHeigth / 2);
 91                     } else {
 92                         if ((pagey - ImgMinHeigth / ImgHeight * ImgMinHeigth / 2) < $(this).offset().top) {
 93                             pagey1 = $(this).offset().top;
 94                         } else {
 95                             pagey1 = ($(this).offset().top + $(this).height() - (ImgMinHeigth / ImgHeight * ImgMinHeigth));
 96                         }
 97                     }
 98                     if (($(this).offset().left + $(this).width() - ImgMinWidth / ImgWidth * ImgMinWidth) >=
 99                         (pagex - ImgMinWidth / ImgWidth * ImgMinWidth / 2) && (pagex - ImgMinWidth / ImgWidth * ImgMinWidth / 2) >=
100                         $(this).offset().left) {
101                         pagex1 = (pagex - ImgMinWidth / ImgWidth * ImgMinWidth / 2);
102                     } else {
103                         if ((pagex - ImgMinWidth / ImgWidth * ImgMinWidth / 2) < $(this).offset().left) {
104                             pagex1 = $(this).offset().left;
105                         } else {
106                             pagex1 = ($(this).offset().left + $(this).width() - ImgMinWidth / ImgWidth * ImgMinWidth);
107                         }
108                     }
109                     leftcha = ImgMinWidth / ImgWidth * ImgMinWidth / 2;
110                     topcha = ImgMinHeigth / ImgHeight * ImgMinHeigth / 2;
111                     if ($("#jqoomy").length == 0) {
112                         $(this).after("<div id=‘jqoomy‘></div>")
113                             .siblings("#jqoomy")
114                             .addClass("jqoomy").show()
115                             .width((ImgMinWidth / ImgWidth * ImgMinWidth))
116                             .height((ImgMinHeigth / ImgHeight * ImgMinHeigth)).offset({
117                             top: pagey1,
118                             left: pagex1
119                         });
120                     }
121                     $(document).on("mousemove", $.proxy(mover, $("#jqoomy")));
122                 }
123             }, function () {
124             });
125         }
126     });
127 })(jQuery);

html:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <script src="jquery11.js"></script>
    <script src="OppJqoom.js"></script>
    <style type="text/css">
        .jqoom
        {
            width: 350px;
            height: 350px;
            border: solid 1px #DFDFDF;
            z-index: 10;
        }

            .jqoom img
            {
                cursor: pointer;
                z-index: 10;
                max-height: 350px;
                max-width: 350px;
            }

        .jqoomy
        {
            background-color: white;
            position: relative;
            z-index: 999;
            opacity: 0.5;
            cursor: pointer;
            border: solid 1px #DFDFDF;
        }

        #jqoomz
        {
            border: solid 1px #DFDFDF;
            position: absolute;
            overflow: hidden;
        }

        .lef
        {
            border: 1px solid #DFDFDF;
            display: block;
            height: 72px;
            line-height: 72px;
            text-align: center;
            text-decoration: none;
            width: 10px;
            background-color:#EBEBEB;
            float:left;
        }
            .lef:hover
            {
                color:red;
            }
        .jqooz
        {
            float:left;
            width:352px;
            margin-top:20px;
        }
            .jqooz ul
            {
                 float: left;
                 margin: 0;
                 padding: 0;
                 width:328px;
                 height:72px;
            }
                .jqooz ul li
                {
                    display: inline;
                    list-style: none outside none;
                    margin: 0 10px;
                }
                    .jqooz ul li img
                    {
                        border: 1px solid #DFDFDF;
                        max-height: 72px;
                        max-width: 120px;
                    }
                        .jqooz ul li img:hover
                        {
                            border: 1px solid #ff6600;
                        }
    </style>
    <script type="text/javascript">
        $(function () {
            $(".jqoom").jqoom();
        });

    </script>
</head>
<body>
    <div class="jqoom">
        <img src="b3.jpg" />
    </div>
    <div class="jqooz">
    <a href="javascript:void(0)" class="lef"><</a>
        <ul>
            <li><a>
                <img src="b3.jpg" /></a></li>
        </ul>
        <a href="javascript:void(0)" class="lef">></a>
        </div>
</body>
</html>

效果:

现在我要修改这个插件为什么在谷歌浏览器第一次加载的时候没有效果,那我要重新跟着代码来梳理放大镜里面的整个功能步骤,这个放大镜的功能还不是很复杂,在实际项目中各种函数回调嵌套,取数,数据处理,显示,页面的动态效果都交织在onload或是ready里面你要花几个小时甚至一整天来梳理你要修改页面的代码逻辑,而且还未必能梳理的全面,所以经常会有前端同事在隔了一段时间给之前写的页面添加注释的时候说我自己写代码都开始看不懂了.

本身javascript特点之一是事件监听函数回调,这是它优点,nodejs作者之所以选择js其中一个原因就是javascript的事件监听函数回调带来的优点,但函数回调同时也带来一个缺点就是经常出现return不出数据,典型的例子就是ajax,jQuery传统的ajax成功之后回调success方法,当你要把这个ajax的输出作为另一个ajax的输入的时候你就不得不要嵌套ajax,一旦嵌套多了这个代码的可读性和复杂度就增加了很多!后期的维护也自然增加了难度,Promise出来之后,jQuery、angular也都纷纷加了Promise。为什么javascript在后期维护要花这么大的时间去梳理逻辑?

我们在看看后台java或c#的语言是怎么做,典型的javaweb几乎都是springMVC框架,C#做web毋庸置疑是.net MVC,他们都有共同的特点是c层提供给前台页面ajax调用的方法都是按照所需要的数据一个一个拆分的,还有相对于的m层,mvc其实是两个维度的分层这是我个人观点,一个维度是单个细小的功能分为view,control,model,另一个维度是整个页面分成多个小的功能.所以你发现后台代码要修改其实很容易就把逻辑梳理,那前台javascript也能不能按照整个思路来取分层呢?

这个插件没有涉及到动态取数,所以分层的标准也不一样,在这里我分了两层,第一层是对鼠标移动后图片的一系列算法,第二层是事件绑定分的一系列dom的操作,代码如下:

/**
 * Created by  on 2016/11/2.
 */
(function ($) {
    //构造函数逻辑主线路
    var OppJqoom = function (_this, potions) {
        this._this = _this;
        this.ImgUrl = $("img", this._this).attr("src");
        this.ImgMinWidth = $("img", this._this).width();
        this.ImgMinHeigth = $("img", this._this).height();
        this.ImgWidth ,this.ImgHeight ,this.leftcha,this.topcha;
        var settings = {
            width: 350,
            height: 350,
            position: "right"
        }
        $.extend(this,settings);
        if (potions) {
            $.extend(this, potions);
        }
        this.domOperation.Jqoomhover.call(this);
        this.domOperation.imghover.call(this);

    };
    OppJqoom.prototype = {
        // 第一层 算法层
        basicOperation: {
           /* 获取遮罩层的top和left*/
            finder: function (that) {
                var pagey1, pagex1;
                if (parseFloat($(this).offset().top + $(this).height() - (that.ImgMinHeigth / that.ImgHeight * that.ImgMinHeigth)) >=
                    parseFloat(this.pagey - that.ImgMinHeigth / that.ImgHeight * that.ImgMinHeigth / 2) && parseFloat(this.pagey - that.ImgMinHeigth / that.ImgHeight * that.ImgMinHeigth / 2) >=
                    parseFloat($(this).offset().top)) {
                    pagey1 = (this.pagey - that.ImgMinHeigth / that.ImgHeight * that.ImgMinHeigth / 2);
                } else {
                    if ((this.pagey - that.ImgMinHeigth / that.ImgHeight * that.ImgMinHeigth / 2) < $(this).offset().top) {
                        pagey1 = $(this).offset().top;
                    } else {
                        pagey1 = ($(this).offset().top + $(this).height() - (that.ImgMinHeigth / that.ImgHeight * that.ImgMinHeigth));
                    }
                }
                if (($(this).offset().left + $(this).width() - that.ImgMinWidth / that.ImgWidth * that.ImgMinWidth) >=
                    (this.pagex - that.ImgMinWidth / that.ImgWidth * that.ImgMinWidth / 2) && (this.pagex - that.ImgMinWidth / that.ImgWidth * that.ImgMinWidth / 2) >=
                    $(this).offset().left) {
                    pagex1 = (this.pagex - that.ImgMinWidth / that.ImgWidth * that.ImgMinWidth / 2);
                } else {
                    if ((this.pagex - that.ImgMinWidth / that.ImgWidth * that.ImgMinWidth / 2) < $(this).offset().left) {
                        pagex1 = $(this).offset().left;
                    } else {
                        pagex1 = ($(this).offset().left + $(this).width() - that.ImgMinWidth / that.ImgWidth * that.ImgMinWidth);
                    }
                }
                that.leftcha = that.ImgMinWidth / that.ImgWidth * that.ImgMinWidth / 2;
                that.topcha = that.ImgMinHeigth / that.ImgHeight * that.ImgMinHeigth / 2;
                that.domOperation.docMousemove.call(that);
                return {top: pagey1, left: pagex1};

            },
            // 放大镜的图片的top和left
            mover: function (that) {
                if (parseInt(that.pagex2 + that.leftcha) <= parseInt(that._this.width() + that._this.offset().left) && that.pagex2 >= that.leftcha + that._this.offset().left) {
                    $(this).offset({left: that.pagex2 - that.leftcha});
                } else {
                    if (parseInt(that.pagex2 + that.leftcha) > parseInt(that._this.width() + that._this.offset().left) && that.pagex2)
                        $(this).offset({left: that._this.width() + that._this.offset().left - that.leftcha * 2});
                    else
                        $(this).offset({left: that._this.offset().left});
                }
                if (parseInt(that.pagey2 + that.topcha) <= parseInt(that._this.height() + that._this.offset().top) && that.pagey2 >= that.topcha + that._this.offset().top) {
                    $(this).offset({top: (that.pagey2 - that.topcha)});
                    //document.getElementById("move").style.top = (pagey2 - (this.pagey - this.divtop)).toString() + "px";
                } else {
                    if (parseInt(that.pagey2 + that.topcha) > parseInt(that._this.height() + that._this.offset().top))
                        $(this).offset({top: (that._this.height() + that._this.offset().top - that.topcha * 2)});
                    //document.getElementById("move").style.top = (this.height - this.divHeight).toString() + "px";
                    else
                        $(this).offset({top: that._this.offset().top});
                    //document.getElementById("move").style.top = "0px"
                }
                var bilx = ($(this).offset().left - that._this.offset().left) / (that.ImgMinWidth / that.ImgWidth);
                var bily = ($(this).offset().top - that._this.offset().top) / (that.ImgMinHeigth / that.ImgHeight);
                return{left:bilx,top:bily};
            }
        },
        // 第二层 事件绑定层
        domOperation: {
            // 鼠标移动到图片的一系列dom的操作
            imghover: function () {
                var that = this;
                $("img", this._this).hover(function (e) {
                    this.pagex = e.x || e.pageX;
                    this.pagey = e.y || e.pageY;
                    var offset;
                    var obj = new Image();
                    obj.src = that.ImgUrl;
                    obj.onload = function () {
                        if (obj.height > 0) {
                            that.ImgWidth = obj.width;
                            that.ImgHeight = obj.height;
                            if ($("#jqoomz").length == 0) {
                                that._this.after("<div id=‘jqoomz‘></div>");
                            }
                            offset = that.basicOperation.finder.call(that._this.find("img")[0],that);
                        }
                    };
                    if ($("#jqoomz").length == 0) {
                        that.ImgWidth = obj.width;
                        that.ImgHeight = obj.height;
                        that._this.after("<div id=‘jqoomz‘></div>");
                    }
                    offset = that.basicOperation.finder.call(this,that);
                    if ($("#jqoomy").length == 0) {
                        $(this).after("<div id=‘jqoomy‘></div>")
                            .siblings("#jqoomy")
                            .addClass("jqoomy")
                            .show()
                            .width((that.ImgMinWidth / that.ImgWidth * that.ImgMinWidth))
                            .height((that.ImgMinHeigth / that.ImgHeight * that.ImgMinHeigth))
                            .offset({
                                top: offset.top,
                                left: offset.left
                            });
                    }
                    $("#jqoomz").width(that.width).height(that.height).offset({
                        left: that._this.outerWidth() + that._this.offset().left,
                        top: that._this[0].offsetTop
                    }).append($("<img></img>").attr("src", that.ImgUrl));
                },function () {});
            },
            //鼠标在图片上滑动的一系列dom操作
            docMousemove: function () {
                var that=this;
                $(document).on("mousemove", function (event) {
                    that.pagex2 = event.x || event.pageX;
                    that.pagey2 = event.y || event.pageY;
                    var offset=that.basicOperation.mover.call($("#jqoomy"),that);
                    $("#jqoomz img").css({"margin-left": -offset.left, "margin-top": -offset.top});
                });
            },
            //鼠标移除图片的一系列dom操作
            Jqoomhover:function () {
                this._this.hover(function (e) {
                }, function () {
                    console.log(111);
                    $("#jqoomz").remove();
                    $(document).unbind("mousemove");
                    $("#jqoomy").remove();
                });
            }
        }
    };
    $.fn.extend({
        jqoom: function (potions) {
            return new OppJqoom(this, potions);
        }
    })
})(jQuery);

然后加上简单的注释感觉页面的逻辑步骤就很清晰了,当然这种写法一种比较麻烦的就是this的用法,对象中嵌套对象调用里面的方法this是指向自己的对象.

在实际开发中我们可以分为数据读取层,数据处理层,以及dom动态效果层,如果业务比较繁杂也可以在分个数据展现层.

当然这是我个人的理解,可能有很多方面没考虑到,只是提供了一些思路!

时间: 2024-10-06 07:25:45

javascript面向对象分层思维的相关文章

再谈javascript面向对象编程

前言:虽有陈皓<Javascript 面向对象编程>珠玉在前,但是我还是忍不住再画蛇添足的补上一篇文章,主要是因为javascript这门语言魅力.另外这篇文章是一篇入门文章,我也是才开始学习Javascript,有一点心得,才想写一篇这样文章,文章中难免有错误的地方,还请各位不吝吐槽指正 吐槽Javascript 初次接触Javascript,这门语言的确会让很多正规军感到诸多的不适,这种不适来自于Javascript的语法的简练和不严谨,这种不适也 来自Javascript这个悲催的名称,

JavaScript面向对象轻松入门之概述(demo by ES5、ES6、TypeScript)

写在前面的话 这是一个JavaScript面向对象系列的文章,本篇文章主要讲概述,介绍面向对象,后面计划还会有5篇文章,讲抽象.封装.继承.多态,最后再来一个综合. 说实话,写JavaScript面向对象的文章实在是太多了,网上一搜一大堆,很多书里面也介绍的很详细.但作者当初在学习面向对象的时候还是非常困难,特别是在习惯了面向过程编程的情况下,不知道大家有没有这个感受. 作者分析了一下其中的原因,恐怕是因为里面涉及的概念太多:原型.原型链.继承.this.constructor.call等等,这

JavaScript面向对象(一)——JS OOP基础与JS 中This指向详解

  前  言 JRedu 学过程序语言的都知道,我们的程序语言进化是从"面向机器".到"面向过程".再到"面向对象"一步步的发展而来.类似于汇编语言这样的面向机器的语言,随着时代的发展已经逐渐淘汰:而面向过程的语言也只有C语言老大哥依然坚挺:现在主流的语言(例如Java.C++.PHP等)都是面向对象的语言. 而我们的JavaScript语言,恰恰介于面向过程与面向对象之间,我们称它为"基于对象"的语言.但是,JS中的OOP依

用大白话扯扯那&quot;神奇&quot;的面向对象编程思维

前言: 每当提到面向对象的时候,初学者肯定都是一脸懵逼的状态,到底什么是面向对象?会用面向对象后有什么牛逼之处吗?不会用是不是就会死掉?答案肯定不会死掉,我们可以来简单的举一 个栗子 1.当你想到熊猫的时候你想到了什么? 答:"国宝" 2.当你看到"国宝"穿上衣服的时候你想到了什么名字? 答:"功夫熊猫"; 其实你可以理解成面向对象就是一种武功!你可以想象一下会武功和不会武功的人有什么区别?"走路带风.飞檐走壁.不食人间烟火.让妹子一看

JavaScript面向对象及相关知识

最近在学习JavaScript面向对象,写下自己的理解及相关资料,以备查阅. 一.面向对象中涉及的相关几个概念 1.作用域 所谓作用域,就是说属性和函数的可访问范围.在JavaScript中,作用域分为两种.全局作用域和局部作用域. 所有没有var 声明 或 定义于最外层函数和最外层函数外面即为全局作用域.也就是定义可以随意调用. 自定义函数内部用var声明的为局部作用域. var num = 1; //全局作用域 window.onload = function() { //最外层为全局作用域

javascript面向对象之this指针

下午用面向对象的方法写一个幻灯片插件的时候不小心写出了这样的代码: Slider.prototype.auto=function() { setInterval(this.toRun,4000);//注意 } Slider.prototype.toRun=function() { if(this.iNow==this.aA.length - 1) ...... } 在浏览器打开的时候发现幻灯片不能如预期般自动切换,控制台给出了这样的错误提示: this.aA isundefined?然而我已经在

javascript面向对象2

原文:javascript面向对象2 首先我们先创建一个对象 var user = Object(); user.name = "张三"; user.age = 20; user.sex = "男"; 上面呢创建了一个对象,当然创建对象的方法有很多种,但是用这样的方法创建对象比较简单直观,也是JavaScript种创建对象最基本的方法. 同时呢也出现了另外一个弊端,当我们想要创建多个对象的时候,我们就要写很多重复的代码,这样一来就增加了代码量,减少了工作的效率, 为

JavaScript面向对象之类的继承

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-

Javascript面向对象特性实现封装、继承、接口详细案例——进级高手篇

Javascript面向对象特性实现(封装.继承.接口) Javascript作为弱类型语言,和Java.php等服务端脚本语言相比,拥有极强的灵活性.对于小型的web需求,在编写javascript时,可以选择面向过程的方式编程,显得高效:但在实际工作中,遇到的项目需求和框架较大的情况下,选择面向对象的方式编程显得尤其重要,Javascript原生语法中没有提供表述面向对象语言特性的关键字和语法(如extends.implement).为了实现这些面向对象的特性,需要额外编写一些代码,如下.