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

Can you inherit private functions in JavaScript?

我正在使用一个闭包用私有和公共方法创建一个对象。看起来像这样-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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中是可能的吗?


不,你不能。

Javascript继承是基于原型的,所以您只能"扩展"原型中的方法。


javascript中变量(函数)的隐私权是通过函数范围实现的。只有当它们从闭包范围中导出时,才可以从外部访问它们,没有其他方法。

要使方法可以访问私有函数的对象,只需将其放在同一范围内。对象是否是从其他对象继承的对象是完全无关的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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();


有点。。。正如Bergi指出的那样,访问是由作用域定义的,所以如果您在父对象的直接对象内定义继承者,您可以大致得到您想要的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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


您想让一个实例继承另一个实例的私有状态吗?当然可以用JavaScript实现。首先,我们需要定义一个实用函数:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
}());

现在您可以创建一只狗,如下所示:

1
2
3
var dog = new Dog;
alert(dog.saySize()); // I am a big dog.
alert(dog.size);      // undefined

我们可以继承私有国家如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
}());

现在您可以创建一个奇瓦瓦,如下所示:

1
2
3
var chi = new Chihuahua;
alert(chi.saySize());    // I am a small dog.
alert(chi.size);         // undefined

参见演示:http://jsfiddle.net/b3eyn/

注意:我写这个答案只是为了证明可以在javascript中继承私有状态。不过,我建议你不要使用这种模式。如果您的代码设计得很好,那么首先就不需要继承私有状态。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
})()