是否存在私有/受保护的原型继承模式

时间:2016-09-27 17:50:28

标签: javascript inheritance prototype private public

Javascript对象中大多数私有/受保护方法的问题是,它们使用闭包。这样,它们必须在构造函数中定义,并且所有想要访问它们的公共方法也必须在构造函数中定义。

这使得两件事变得不可能:

  • 共享公共方法实例的对象的实例。对象的每个实例必须具有可以访问私有成员的每个方法的自己的实例
  • 儿童能够从父母那里获取和重复使用受保护的方法

有没有办法解决这两个问题,因此可以在所有实例之间共享私有方法,以及子级能够重用其父级保护方法。

同样不错的浏览器支持,至少在ECMA5级别上会很棒。

1 个答案:

答案 0 :(得分:0)

虽然这可能不是一个完美而优雅的解决方案,但我找到了解决上述问题的方法

构造

首先看看我们的构造函数,以及一些原型方法。

function FooConstructor(args) {
    this.args = args;
    this.private = "lower case secret from foo";

    this.exports = {
        publicMethod: this.publicMethod.bind(this)
    };
}

FooConstructor.prototype.privateMethod = function() {
    return this.private;
}

FooConstructor.prototype.publicMethod = function() {
    return this.privateMethod().toUpperCase();
}

不是对象this.exports。在这里,我们将存储应该公开的所有内容。

重要的是,我们不直接调用构造函数,而是使用Factorymethod,它获取对象的实例,然后只返回exports对象。

function getInstanceFoo(args) {
    return new FooConstructor(args).exports;
}

现在,如果我们想要一个Foo实例,我们就可以了。

var fooInstance = getInstanceFoo("fooArg");

从这个实例中我们只能访问我们放入exports对象的内容。

fooInstance.publicMethod(); // "LOWER CASE SECRET FROM FOO"
fooInstance.private;        // undefined
fooInstance.privateMethod;  // undefined 
                            // calling it would give you: 
                            // Uncaught TypeError: fooInstance.privateMethod is not a function

儿童构造函数

现在好处是,我们的工厂只出口我们想要公开的东西,但我们仍然有一个可以访问的构造函数。所以对于一个孩子,我们可以这样做:

function BarConstructor(args) {
    // this will just copy all the exported methods from Foo
    FooConstructor.call(this, args);

    // overwrite stuff we don’t want from the parents constructor
    this.privateMember = "lower case secret from bar";

    // add publics that should be exported for the child
    this.exports.newPublicMethod = this.newPublicMethod.bind(this);
}

BarConstructor.prototype = new FooConstructor();

BarConstructor.prototype.newPublicMethod = function() {
    return "My args: " + this.args;
}

function getInstanceBar(args) {
    return new BarConstructor(args).exports;
}

var barInstance = getInstanceBar("barArg");

barInstance.publicMethod();    // "LOWER CASE SECRET FROM BAR"
barInstance.newPublicMethod(); // "My args: barArg"
barInstance.private;           // undefined

摘要

就是这样。这几乎是我们想要的。 在这里你可以尝试一下:



	// FooConstructor ------------------------------------------
	function FooConstructor(args) {
		this.args = args;
		this.privateMember = "lower case secret from foo";

		this.exports = {
			publicMethod: this.publicMethod.bind(this)
		};
	}

	FooConstructor.prototype.privateMethod = function() {
		return this.privateMember;
	}

	FooConstructor.prototype.publicMethod = function() {
		return this.privateMethod().toUpperCase();
	}

	// FooFactory
	function getInstanceFoo(args) {
		return new FooConstructor(args).exports;
	}

	// BarConstructor ------------------------------------------
	function BarConstructor(args) {
		// this will just copy all the exported methods from Foo
		FooConstructor.call(this, args);

		this.privateMember = "lower case secret from bar";
		this.exports.newPublicMethod = this.newPublicMethod.bind(this);
	}

	BarConstructor.prototype = new FooConstructor();

	BarConstructor.prototype.newPublicMethod = function() {
		return "My args: " + this.args;
	}

	// BarFactory
	function getInstanceBar(args) {
		return new BarConstructor(args).exports;
	}

	// Get Instances ------------------------------------------
	var fooInstance = getInstanceFoo("fooArg"),
		barInstance = getInstanceBar("barArg");

	console.log( "fooInstance.publicMethod(): " + fooInstance.publicMethod() );
	console.log( "fooInstance.private: " + fooInstance.private );
	console.log( "fooInstance.privateMethod: " + fooInstance.privateMethod );


	console.log( "barInstance.publicMethod(): " + barInstance.publicMethod() );
	console.log( "barInstance.newPublicMethod(): " + barInstance.newPublicMethod() );
	console.log( "barInstance.private: " + barInstance.private );




缺点

有一些东西,可能是缺点,即使有可能为那些找到工作。你必须决定这些是否是交易破坏者。

instanceof无效。

fooInstance instanceof FooConstructor; // false

bind

如果您担心bind会降低您的程序速度并且开销不是可行的,那么您可以通过将构造函数更改为此来返回非私有版本:

function getInstanceBar(args) {
    return new BarConstructor(args);
}

从构造函数中删除this.exports。因此,您可以轻松地在两者之间切换,而无需进行太多重构。同样在这种情况下,向所有私有成员添加下划线可能是个好主意。