你能在JavaScript中继承私有函数吗?

11

我正在使用闭包来创建一个包含私有和公共方法的对象。代码如下 -

var Dog = (function() {
    function Dog() {}

    var size = 'big';

    var _privateSaySize = function() {
        return 'I am a ' + size + ' dog.';
    }

    Dog.prototype.publicSaySize = function() {
        return _privateSaySize();
    }

    return Dog;
})();

但是现在我想要一个只有私有函数并被另一个对象继承的对象。但是在JavaScript中是否可能实现这个?


1
这个 function Dog = (function() {})() 是什么? - Amberlamps
2
private 成员在任何支持面向对象编程的语言中,仅在定义它们的类内部可见。我不明白你试图做什么。 - Leri
3
OP希望保护成员。 - nice ass
@csss 它们被称为“protected”方法。请阅读有关访问修饰符的内容。 - Leri
我猜不可能。即使可以,也会是一个非常不好的解决方法。 - Leri
显示剩余6条评论
5个回答

9
不行,你不能。
JavaScript的继承是基于原型的,因此你只能“扩展”原型中的方法。

同意。不过值得注意的是,许多JS开发者会通过在本来公有的方法前加下划线来表示它们是受保护的或者不属于公共API。开发者可以选择修改它们,但风险自负。老实说,在JS中尝试保护一个公开可访问的对象是一项相当徒劳的努力,因为任何使用您库的人都可以覆盖任何公共功能,甚至混淆共享对象/原型。这似乎不值得头疼。 - Alexis Beingessner

5
JavaScript中变量(函数)的隐私通过函数作用域来实现。只有在闭包范围内导出它们,才能从外部访问它们,没有其他方法。
要使具有访问私有函数权限的方法的对象,您只需将其放置在同一作用域中即可。该对象是否继承自其他对象并不重要。
function Dog() {}
function Dalmatian() {}
Dalmation.prototype = Object.create(Dog.prototype);
Dalmation.prototype.size = "big";
function Dackel() {}
Dackel.prototype = Object.create(Dog.prototype);
Dackel.prototype.size = "small";

(function() {
    // private function
    function say(s) {
        console.log("I'm a "+s+" dog");
    }
    // both accessible from the Dog and Dackel public methods
    Dog.prototype.saySize = function() {
        say(this.size || "normal");
    };
    Dackel.prototype.saySize = function() {
        say(this.size + " but loud");
    };
})();
new Dog().saySize();
new Dalmatian().saySize();
new Dackel().saySize();

2

在Bergi指出的情况下,访问权限由作用域定义,因此如果您在父级的直接内部定义继承者,您可以大致获得所需的结果。

var BarkingDog;
var Dog = (function() {
    function Dog() {}

    var size = 'big';

    var _privateSaySize = function() {
        return 'I am a ' + size + ' dog.';
    };

    Dog.prototype.publicSaySize = function() {
        return _privateSaySize();
    };

    BarkingDog = (function () {
        function BarkingDog () {}

        var say = 'woof';

        BarkingDog.prototype = new Dog();

        BarkingDog.prototype.bark = function () {
            return _privateSaySize() + ' ' + say;
        };

        return BarkingDog;

    })();

    return Dog;
})();

var myDog = new BarkingDog();
console.log(myDog.bark());
console.log(myDog.publicSaySize());

不确定为什么你想要这样做... :D

1

你希望一个实例可以继承另一个实例的私有状态?在 JavaScript 中,当然可以做到。首先,我们需要定义一个实用函数:

function weakBind(functable, prototype, state) {
    return function () {
        return functable.apply(this, Object.getPrototypeOf(this) === prototype ?
            [state].concat(Array.prototype.slice.call(arguments)) : arguments);
    };
}

现在我们可以创建基类如下所示:

var Dog = (function () {
    function Dog() {
        if (this instanceof Dog) {
            // constructor code
        } else return Object.create(private);
    }

    var public = Dog.prototype, private = Object.create(public, {
        size: {
            value: "big"
        }
    });

    public.saySize = weakBind(function (private) {
        return "I am a " + private.size + " dog.";
    }, public, private);

    return Dog;
}());

现在你可以按照以下步骤创建一只狗:
var dog = new Dog;
alert(dog.saySize()); // I am a big dog.
alert(dog.size);      // undefined

我们可以按以下方式继承私有状态:

var Chihuahua = (function () {
    function Chihuahua() {
        Dog.call(this);
    }

    var private = Dog();

    Object.defineProperty(private, {
        size: {
            value: "small"
        }
    });

    var public = Chihuahua.prototype = Object.create(Dog.prototype);

    public.saySize = weakBind(public.saySize, public, private);

    return Chihuahua;
}());

现在您可以按照以下步骤创建一只吉娃娃:
var chi = new Chihuahua;
alert(chi.saySize());    // I am a small dog.
alert(chi.size);         // undefined

查看演示:http://jsfiddle.net/b3Eyn/

注意:我写这篇答案只是为了展示在JavaScript中继承私有状态是可能的。但是我建议你不要使用这种模式。如果你设计你的代码得当,那么你就不需要在第一时间继承私有状态。


0

你可以避免使用点符号。但这并不是真正的私有。

var Dog = (function() {
    function Dog() {}

    var size = 'big';

    Dog.prototype['-privateSaySize'] = function() {
        return 'I am a ' + size + ' dog.';
    }

    Dog.prototype.publicSaySize = function() {
        return this['-privateSaySize']();
    }

    return Dog;
})()

1
为了表示属性的“内部性”,使用下划线 _ 而不是减号。这样,您就可以避免使用括号表示法... - Bergi
@Bergi 这就是重点。我使用了减号,因为这样你就不能使用点符号表示法,所以只能使用括号表示法。 - boskop
@Bergi 我知道,我不会质疑这一点。我所指的是仅使用点表示法的方法的可见性。我知道这是一种不太优雅的解决方案,并且仅部分解决了可见性问题,但它是对象的一部分,因此该方法可以被另一个对象继承。 - boskop
“Visibility”是什么意思?你是指源代码的外观(与括号表示法不同)吗? - Bergi
@Bergi,你不能使用myDog.-privateSaySize,因为减号在这种情况下是非法字符。在使用JavaScript对象时,方括号表示法不常用于访问函数或属性,因此使用点表示法可以避免使用该函数,而这是最常用的方法。 - boskop
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接