JavaScript基础13——面向对象

什么是面向对象?

面向对象(Object Oriented,OO)是软件开发方法。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统,交互式界面,应用结构,应用平台,分布式系统,网络管理结构,CAD技术,人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后到产物,是一种高级的编程思想。
 
    面向对象就是一种新的编程模式。

面向对象的特点

    封装:不考虑内部实现,只考虑功能实现
 
    继承:从已有对象上,继承出新对象
    
    多态:多种形态,一个功能的不同的应用场景

对象的组成

    方法(有归属)----函数(自由的)
 
    属性(有归属)----变量(自由的)

OOA和OOD

OOA面向对象分析:
面向对象分析:将大问题拆分成小问题,并试图用分工协作来完成的思维方式。
OOD面向对象设计:
        1.分析模块后,确定职责
            大哥招小弟--端茶倒水,点烟捶背捏脚
 
        2.确定耦合关系
            确定通信关系,如何交流,暗号
            弊端:当耦合达到一定程度时,如果换了一个助理,需要重新耦合,资源消耗太大
           高内聚低耦合
 
        3.为OOP做准备
 
        分析角色特性:
             我当老师----技术过硬
                   ----讲课技能(口才)
 
             我当销售----沟通技巧(口才)
            
            找到角色共同特性----继承
大量信息的处理和加工困难,打包之后,将内容包含在其中。信息传递速度更快,效率更高
        
    面向对象和面向过程的区别
        面向对象--先实现功能,再运行。分工协作,同时发生,解决问题。
        面向过程--一边实现,一边运行。效率低下。
    
    面向对象并不是程序员发明的。在程序中我们叫面向对象(OO),在生活中叫分工协作。

构造函数

    function CreatPeople(name,age,like){
            this.name = name;
            this.age = age;
            this.like = like;
            this.show = function(){
                alert("我叫"+this.name+",今年"+this.age+"岁,喜欢"+this.like);
            }
        }
        var obj = new CreatPeople("ABC",20,"PHP");
        var obj2 = new CreatPeople("QWE",32,"Python");
        obj.show();
        obj2.show();

构造函数和对象的关系

    面向对象----对一个对象进行编程
    构造函数----提供一个对象供你编程
 
    通过构造函数,实现面向对象编程

使用Json创建对象

    var obj = {
        name:"admin",
        age:23,
        like:"LOL",
        show:function(){
            alert("我叫"+this.name+",今年"+this.age+"岁,喜欢"+this.like)
        }
    }
    obj.show()

使用构造函数创建对象

        function CreatPeople(name,age,like){
            this.name = name;
            this.age = age;
            this.like = like;
            this.show = function(){
                alert("我叫"+this.name+",今年"+this.age+"岁,喜欢"+this.like);
            }
        }
        var obj = new CreatPeople("ABC",20,"PHP");
        var obj2 = new CreatPeople("QWE",32,"Python");
        obj.show();

        obj2.show();

原型的概念

    在对象中,两个新创建的函数,是不相等的:
    var obj1 = {
        fn:function(){
            alert(1);
        }
    }
    var obj2 = {
        fn:function(){
            alert(1);
        }
    }
    console.log(obj1.fn == obj2.fn);    //false

    在构造函数中,同样属于两个新创建的函数,也是不相等的
    function Fn(name){
        this.name = name;
        this.show = function(){
            alert(this.name);
        }
    }
    var obj1 = new Fn("AAA");
    var obj2 = new Fn("BBB");
    console.log(obj1.show==obj2.show);        //false
    
    此时可以看出构造函数的多次创建会产生多个同名函数,造成冗余太多。
    
    利用原型prototype解决。
    function Fn(){}
    console.log(Fn.prototype);
    //constructor表示当前的函数属于谁
    //__proto__  ==  [[prototype]],书面用语,表示原型链


    var fn1 = new Object();
    var fn2 = new Object();
    Object.prototype.show = function(){
        alert(1);
    }
    console.log(fn1.show==fn2.show);     //ture

 

 
    此时,任何一个对象的原型上都有了show方法,由此得出,Object.prototype身上的添加的方法,相当于添加到了所有的Object身上。
    
    为了解决构造函数的冗余问题,我们将属性写在构造函数内,方法写在原型中。这是面向对象的编程格式之一。
    面向对象的编程格式之一:
        1.属性写在构造函数内;
        2.方法写在原型中
        3.构造函数中的this指向当前new出来的对象
       4.原型方法中的this指向当前原型所属的函数被new出来的对象
在代码中再次看看区别
   // 1.创建对象:构造函数
        // function Fn(){
        //     this.xxx = xxxx;
        // }
        // var f = new Fn()
        
        // 模型,构造器
        function Fn(n){
            this.name = n;
            this.show();
        }

        Fn.prototype.show = function(){
            console.log(this.name)
        }

        var f1 = new Fn("admin");
        var f2 = new Fn("root");


        // new出来的实例
        console.log(f1);
        console.log(f2);
        console.log(f2 == f1);
        console.log(f2.__proto__ == f1.__proto__);
        console.log(f2.__proto__.show == f1.__proto__.show);

        f1.show();
        f2.show();

        // console.dir(Fn);
        // console.log(Fn.length)
        // console.log(Fn.name)
        // console.log(Fn.prototype)
        // console.log(f1.__proto__)
        // console.log(f1.__proto__ === Fn.prototype)

        // // 抽象
        // // 具象
        // f1.show();
        // f2.show();
        // console.log(f1.show == f2.show);

        console.log(f1.abc);

    
    // var arr1 = new Array("hello","world");
    // var arr2 = new Array("hello","html");
    // console.log(arr1);
    // console.log(arr2);
    // console.log(arr2 == arr1);
    // console.log(arr1.length);
    // console.log(arr2.length);

    // arr1.push("hello");
    // arr2.push("hello");
    
    // console.log(arr1.push == arr2.push);
    
    // Array.prototype.hahaha = function(){}
    // var arr = new Array();
    // arr.norepeat()

    // 为什么要相等?节省内存,减少方法的冗余
    // 怎么做?写成公共方法
    // 怎么实现?
    // ↓↓↓↓↓↓↓↓↓
    // __proto__:原型链(隐示原型),作用:与自身类型的父级建立连接
    // prototype:原型对象(显示原型),只有函数(除了箭头函数)才有,作用:为了给自身被new之后创建出来的实例做父级使用

    // 此属性对于函数自身来说,没有用
    // 但是这个属性是给函数被new执行创建出的实例,当爸的

    // new的原理:
        // 1.自动创建一个新对象
        // 2.改变了函数内部的this,为第一步的新对象
        // 3.将第一步创建的新对象的父级,改成new执行函数的prototype
        // 4.检测函数是否主动返回对象,没有,就返回第一步创建的新对象

    // 对象读取属性或方法的原则:
        // 就近原则:当对象查找自身的属性或方法时,如果自身有,直接使用;如果自身没有,顺着__proto__向上找父级,找到了就使用,没找到,继续向上;直到顶部,还没找到,就抛出undefined;在这个过程中,只要找到了,就停止向上查找。
        
    // 构造函数身上的原型对象身上的方法中的this,依然指向将来构造函数被new出来的实例

 面向对象案例——烟火

<!DOCTYPE html>
<html>
    <head>
        <meta charset = "utf-8">
        <title></title>
        <style>
            .box {width: 800px;height: 600px;background-color: black;margin: 0 auto;position: relative;}
            .fire1 {width: 15px;height: 15px;border-radius: 50%;position: absolute;bottom: 0;}
            .fire2 {width: 10px;height: 10px;border-radius: 50%;position: absolute;}
        </style>
    </head>
    <body>
        <div class="box"></div>
    </body>
    <script>
        
        function Fire(obj){
            this.x = obj.x;
            this.y = obj.y;
            this.cont = obj.parent;
            this.onoff = obj.onoff;
            this.start();
        }

        Fire.prototype.start = function(){
            // 1.创建烟花给样式
            this.div = document.createElement("div");
            this.div.className = "fire1";
            this.div.style.background = randomColor();
            this.div.style.left = this.x + "px";
            this.cont.appendChild(this.div);
            // 开始运动this.transition();
            this.transition();
        }

        Fire.prototype.transition = function(){
            move(this.div,{top:this.y},()=>{
                // 运动,结束后删除
                this.div.remove();
                // 3创建小烟花this.boom();
                this.onoff = this.onoff == 1 ? this.boom1() : this.boom2();
                //选择烟花样式
            })
        }

        Fire.prototype.boom1 = function(){
            // 4.小烟花运动,消失
            var num = random(2,3);
            for(var i = 0;i < num;i++){
                let star = document.createElement("div");
                star.className = "fire2";
                star.style.background = randomColor();
                star.style.left = this.x + "px";
                star.style.top = this.y + "px";
                this.cont.appendChild(star);
                var l = random(0,this.cont.offsetWidth-star.offsetWidth);
                var t = random(0,this.cont.offsetHeight-star.offsetHeight);
                move(star,{left:l,top:t},function(){
                    star.remove();
                })
            }
        }
        Fire.prototype.boom2 = function(){
            // 4.小烟花运动,消失
            var num = random(20,35);
            var r = random(100,200);
            for(var i = 0;i < num;i++){
                let star = document.createElement("div");
                star.className = "fire2";
                star.style.background = randomColor();
                star.style.left = this.x + "px";
                star.style.top = this.y + "px";
                this.cont.appendChild(star);
                var l = parseInt(Math.cos(Math.PI/180*(360/num*i))*r)+this.x;
                var t = parseInt(Math.sin(Math.PI/180*(360/num*i))*r)+this.y;
                move(star,{left:l,top:t},function(){
                    star.remove();
                })
            }
        }




        var obox = document.querySelector(".box");
        addEvent(obox,"mousemove",function(eve){
            var e = eve || window.event;
            new Fire({
                x:e.offsetX,
                y:e.offsetY,
                parent:this,
                onoff:1
            });
        })

        addEvent(obox,"contextmenu",function(eve){
            var e = eve || window.event;
            e.preventDefault();
            new Fire({
                x:e.offsetX,
                y:e.offsetY,
                parent:this,
                onoff:0
            });
        })
        // 运动
        function move(ele,obj,fn){
            clearInterval(ele.t);
            ele.t = setInterval(() => {
            var onoff = true;
            for(var i in obj){
                var pos = parseInt(getComputedStyle(ele,false)[i]);
                var speed = (obj[i]-pos)/10;
                speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                if(pos != obj[i]){
                    onoff = false;
                }
                ele.style[i] = pos + speed + "px";
                if(onoff == true){
                    clearInterval(ele.t);
                    fn && fn();
                }
            }    
            }, 30);
        }

        // 范围随机数
        function random(max,min){
            return Math.round(Math.random()*(max-min)+min);
        }
        // 随机颜色
        function randomColor(){
            return "rgb("+random(0,255)+","+random(0,255)+","+random(0,255)+")";
        }
        // 监听式绑定:
        function addEvent(ele,eve,cb){
            if(ele.addEventListener){
                ele.addEventListener(eve,cb);
            }else if(ele.attachEvent){
                ele.attachEvent("on"+eve,cb);           //ie
            }else{
                ele["on"+eve] = cb;
            }
        }

      
    </script>
</html>

 

 
 
 
 
 
posted @ 2019-12-21 15:59  优冠的味道  阅读(181)  评论(0编辑  收藏  举报