JS面向对象组织代码

JS本身不存在类的概念,它对于继承的判定有时非常混乱,当然这并不影响我们以面向对象的思维去编程。

例如我们有两个类A类B类,我们想让B类继承A类,在python中可以轻而易举的实现,在JS中需要一种折中法

        function A() {

        }

        A.prototype.hello = function() {
            console.log(1)
        }

        function B() {

        }
        B.prototype = new A();
        (new B()).hello()

B的原型对象指向了A的实例

        // 在子类需要继承父类属性的情况下需要用这种方法
        function A(a) {
            this.a = a;
        }

        A.prototype.hello = function() {
            console.log(this.a)
        }

        function B(a, b) {
            this.constructor.apply(this, arguments)
            this.b = b;
        }
        B.prototype = new A();
        (new B(1, 2)).hello()
1        var obj = {
2            a : 1,
3            b : 2,
4            c : false
5        }
6
7        console.log("a" in obj);    //true
8        console.log("b" in obj);    //true
9        console.log("c" in obj);    //true
        console.log("d" in obj);    //false

in不仅仅检测是对象自己有没有这个属性,如果原型链上有这个属性,那么也会返回true。整个原型链如果没有这个属性,就返回false。也就是说,in操作符会进行原型链查找。

 

for in 这个循环,会把原型链上所有的可枚举的属性列出来

hasOwnProperty方法则是只检测自己是否有这个属性

 

值得说的是instanceof这个运算符的机理,它会查找原型链所有原型,只有要构造函数指向了原型链上的任意原型它就会返回true

        function A() {

        }

        function B() {

        }

        B.prototype = new A();
        console.log(new B() instanceof B)

        // 此时B的原型已经是A的实例,在原型链层面上没有任何逻辑可以证明B的实例的构造函数是B但是结果是true

        // 再举个例子

        function C() {}
        C.prototype = Array.prototype;
        var arr = [];

        console.log(arr instanceof C)
            // 返回的也是true,如果说上一个例子B的实例和构造函数的关系是真实的,那么构造函数C和arr并不存在任何关系
            // 只是C的原型指向了Array的原型,但instanceof的意义是证明arr 是 C 的实例,实际并不是

面向对象对于代码的组织结构更加清晰例如,贪吃蛇小游戏

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    table,
    tr,
    td {
        border: 1px solid #000;
        border-collapse: collapse;
    }
    
    td {
        width: 18px;
        height: 18px;
    }
    
    .red {
        background-color: red;
    }
    
    .blue {
        background-color: blue;
    }
</style>

<body>
    <table id="snake">
    </table>


    <script>
        // 面向对象的思维做游戏,首先确认需要的类
        // 地图类
        // 蛇类
        // 食物类
        // 创建地图类

        function Map() {
            this.data = [];
            this.timer = null;
            this.dom = document.getElementById('snake');
            this.init();
        }

        // 地图类有一个初始化的方法

        Map.prototype.init = function() {
                var rowArr;
                var tr;
                var td;
                for (var row = 0; row < 40; row++) {
                    rowArr = [];
                    tr = document.createElement('tr');
                    this.dom.appendChild(tr);
                    for (var col = 0; col < 40; col++) {
                        td = document.createElement('td');
                        tr.appendChild(td);
                        rowArr.push(td);
                    }
                    this.data.push(rowArr)
                }
            }
            // Map有一个清空画布的方法
        Map.prototype.clear = function() {
            for (var i = 0; i < 40; i++) {
                for (var j = 0; j < 40; j++) {
                    this.data[i][j].className = "";
                }
            }
        };


        // 创建蛇类
        function Snake() {
            this.location = [{
                'x': 5,
                'y': 10
            }, {
                'x': 5,
                'y': 9
            }, {
                'x': 5,
                'y': 8
            }, {
                'x': 5,
                'y': 7
            }, {
                'x': 5,
                'y': 6
            }, {
                'x': 5,
                'y': 5
            }, ];
            this.direction = 'right';
            this.isEnd = false;
            this.render();
            this.bindEvenet();
        }


        // 蛇有一个渲染方法
        Snake.prototype.render = function() {
            var tempDom;
            for (var i = 0; i < this.location.length; i++) {
                if (this.isEnd) {
                    break;
                }
                tempDom = map.data[this.location[i].x][this.location[i].y];
                tempDom.className = 'blue'
            }
        };

        // 蛇有一个更新自己的函数
        Snake.prototype.update = function() {
            // 蛇头向用户输入方向加1蛇尾减1
            this.location.pop();
            // 随时都要监听用户输入了什么方向
            switch (this.direction) {
                case 'left':
                    this.location.unshift({
                        'x': this.location[0].x,
                        'y': this.location[0].y - 1,
                    });
                    break;
                case 'top':
                    this.location.unshift({
                        'x': this.location[0].x - 1,
                        'y': this.location[0].y,
                    });
                    break;
                case 'right':
                    this.location.unshift({
                        'x': this.location[0].x,
                        'y': this.location[0].y + 1,
                    });
                    break;
                case 'bottom':
                    this.location.unshift({
                        'x': this.location[0].x + 1,
                        'y': this.location[0].y,
                    });
                    break;
            }
            this.check();
        };

        // 给蛇类绑定一个方向事件
        Snake.prototype.bindEvenet = function() {
            var self = this;
            document.onkeydown = function(event) {
                event = event || window.event;
                switch (event.keyCode) {
                    case 37:
                        // 蛇头只有一个方向,假设当前方向为左
                        // 那么我们蛇的X值是-1的,如果这时候用户输入右
                        // 那么X值变为 + 1,此时就会出现bug也就是短暂的重合

                        if (self.direction == 'right') {
                            return;
                        }
                        self.direction = 'left'
                        break;
                    case 38:
                        if (self.direction == 'bottom') {
                            return;
                        }
                        self.direction = 'top'
                        break;
                    case 39:
                        if (self.direction == 'left') {
                            return;
                        }
                        self.direction = 'right'
                        break;
                    case 40:
                        if (self.direction == 'top') {
                            return;
                        }
                        self.direction = 'bottom'
                        break;
                }
            };

        };
        // 蛇有一个吃食物的方法
        Snake.prototype.eatFood = function() {
            // 蛇头碰到食物
            if (this.location[0].x == food.x && this.location[0].y == food.y) {
                // 当我们碰到食物时重新计算位置
                food.change();
                // 蛇头加1
                switch (this.direction) {
                    case 'left':
                        this.location.unshift({
                            'x': this.location[0].x,
                            'y': this.location[0].y - 1,
                        });
                        break;
                    case 'top':
                        this.location.unshift({
                            'x': this.location[0].x - 1,
                            'y': this.location[0].y,
                        });
                        break;
                    case 'right':
                        this.location.unshift({
                            'x': this.location[0].x,
                            'y': this.location[0].y + 1,
                        });
                        break;
                    case 'bottom':
                        this.location.unshift({
                            'x': this.location[0].x + 1,
                            'y': this.location[0].y,
                        });
                        break;
                }
            }
        };
        //  蛇有要检测是否撞到自己或边缘
        Snake.prototype.check = function() {
            if (snake.location[0].x < 0 || snake.location[0].x > 39 || snake.location[0].y < 0 || snake.location[0].y > 39) {
                this.isEnd = true;
            }
            for (var i = 0; i < this.location.length - 1; i++) {
                if (this.location[0].x == this.location[i + 1].x && this.location[0].y == this.location[i + 1].y) {
                    this.isEnd = true
                }
            }
        };
        // 食物类
        function Food() {
            this.x = NaN;
            this.y = NaN;
            this.change();
        };
        // 食物类有个方法,计算食物的位置
        Food.prototype.change = function() {
            // 食物不能和蛇重合
            this.x = parseInt(Math.random() * 40)
            this.y = parseInt(Math.random() * 40)
            for (var i = 0; i < snake.location.length; i++) {
                if (this.x == snake.location[i].x && this.y == snake.location[i].y) {
                    food.create();
                }
            }
        };

        // 食物类有一个渲染方法
        Food.prototype.render = function() {
            map.data[this.x][this.y].className = 'red';
        };
        var map = new Map();
        var snake = new Snake();
        var food = new Food();

        var timer = setInterval(function() {
            // 清空画布
            map.clear();
            // 我们将其想象成canvas现在我们自己建的画布每秒都在重新绘制
            // 清空画布后我们需要渲染蛇与食物
            snake.update();
            snake.eatFood();
            snake.render();
            food.render();
            if (snake.isEnd) {
                clearInterval(timer)
                alert('GAME OVER')
            }
        }, 300);
        // 当然这里只是最简单的实现,如果你想同时产生多个不同大小的食物,根据蛇身体大小加速等等,都可以自由实现
        // 比如要产生多个食物,可以给食物类添加食物地图...
        // 面向对象的思维就是可以根据人类的思维无限延伸,理论上是这样,创造性和协调性更强
    </script>

</body>

</html>

 

posted on 2020-02-25 11:52  素心~  阅读(275)  评论(0编辑  收藏  举报

导航