求大佬给解释下,为什么下面代码的构造函数要封装在一个自调用函数里?

var Ball = function() {
    function Ball(id, x, y, radius, speed) {

        this.id = id;
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.colours = newColours();
        this.speed = speed;
        var initialVector = {
            x: Math.random() * 2 - 1,
            y: Math.random() * 2 - 1
        };
        var vectorX = initialVector.x / Math.sqrt(initialVector.x * initialVector.x + initialVector.y * initialVector.y);
        var vectorY = initialVector.y / Math.sqrt(initialVector.x * initialVector.x + initialVector.y * initialVector.y);
        this.vector = {
            x: vectorX,
            y: vectorY
        };
    }

    Ball.prototype.draw = function draw() {
        cx.beginPath();
        cx.arc(this.x, this.y, this.radius, 0, tau);
        cx.fillStyle = 'rgba(' + this.colours.r + ',' + this.colours.g + ',' + this.colours.b + ', 1)';
        cx.fill();
    };

    Ball.prototype.step = function step() {
        this.x += this.vector.x * this.speed;
        this.y += this.vector.y * this.speed;
        this.checkBounds();
    };

    Ball.prototype.checkBounds = function checkBounds() {
        if (this.x - this.radius <= 0) {
            this.vector.x *= -1;
        }
        if (this.x + this.radius >= width) {
            this.vector.x *= -1;
        }
        if (this.y - this.radius <= 0) {
            this.vector.y *= -1;
        }
        if (this.y + this.radius >= height) {
            this.vector.y *= -1;
        }
    };

    return Ball;
}();
阅读 1.7k
2 个回答
  1. 可以防止代码的碎片化,很多编辑器都可以把函数体折叠起来,把一个类的所有代码包含在一个函数体内,折叠这个函数就可以折叠整个类,便于代码结构查看;
  2. 可以控制方法、属性的可见性,因为 ES5 以下不能使用类关键字,更不能使用 privatestatic等关键字控制可见性,所以只能用闭包来控制:
var MyClass = (function(){
    // 构造函数
    function My(){
        if(!this || this.__proto__ !== p){
            throw '构造函数 MyClass 只能使用 new 关键字调用';
        }
    };
    
    // 简写 prototype
    var p = My.prototype
    
    // 模拟私有方法,外部无法访问这种方法
    // 原则上这种方法里不要用 this 关键字,否则需要在调用处绑定 this
    function _private(){}
    
    // 模拟静态方法,这些方法不用实例化就能访问
    // 但是不能被实例和子类直接继承,
    My.staticMethod = function staticMethod(){};
    
    // 模拟一般的方法,可以被子类所继承
    p.default = function default(){};
    
    // 用属性混入来模拟提升,注意这个实现并不完整
    // 子类或实例提升之后就可以访问(拟)静态方法
    p.super = function super(){
        var _this = this;
        var superClassMethods = Object.keys(My);
        superClassMethods.forEach(function(key){
            if(My.hasOwnProperty(key)){
                _this[key] = My[key];
            }
        });
    };
    
    return My;
})();

不过现在已经有 ES6+ ,类的写法更加规范,就不必使用这些奇技淫巧了。

封装在函数里面,应该是避免污染全局变量,大部分原生js库都是这么做的
`
var Zepto = (function() { return $})()
`

跟业务代码隔离

推荐问题