Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS之私有——一个世界性的难题 #11

Open
Jeffersondyj opened this issue Jun 14, 2017 · 1 comment
Open

JS之私有——一个世界性的难题 #11

Jeffersondyj opened this issue Jun 14, 2017 · 1 comment

Comments

@Jeffersondyj
Copy link
Owner

JS之私有

Jefferson其实蛮早就研究过了这个topic并写了sample。今天只不过整理出文字来而已。

一般说来,如果想原型中实现私有方法,我们约定俗成地加一个_:

SomeClass.prototype._somePrivateMethod = function () {
    // TODO
};

但是老道发话了(引用原话):

Do not use _ (underbar) as the first character of a name. It is sometimes used to indicate privacy, but it does not actually provide privacy. If privacy is important, use the forms that provide private members. Avoid conventions that demonstrate a lack of competence.

和私有方法类似,下例是一个加_的特权属性:

function Car() {
    this._mile = 0;
}

Car.prototype.getMile = function () {
    return this._mile;
};

但很遗憾,依然无法实现真正的私有,我们可以简单地: var car = new Car(); car._mile = 1;

改进1.0版

var Car = (function () {
    var privateStore = {};
    var uid = 0;
    
    function Car() {
        privateStore[this.id = uid++] = {};
        privateStore[this.id].mile = 0;
    }
    
    Car.prototype.getMile = function () {
        return privateStore[this.id].mile;
    };
}());

用uid生成递增的Car的this.id,所有的setter和getter都通过privateStore,这样无法直接写car.mile = 1了。实现了私有保护!

貌似有用诶~不过这是终极方案了吗?No,原因如下:

1 额外代码茫茫多,业务一旦复杂了,FE还要写一堆privateStore神马的,会精神崩溃直至跳楼;
2 this.id被占用,如果某个业务类也需要this.id,就傻眼了;
3 内存泄露——privateStore会对每个实例有引用,这些实例不会被回收。

改进思路

1 声明私有的途径,好歹应该快捷方便些;
2 私有方法可以调用共有方法;
3 不能占用this.id;不能有内存泄露问题。

改进2.0版

设计一个util函数,PrivateParts.create。传入privateMethods,其中:
var privateMethods = Object.create(A.prototype); // A为类名

而var _ = PrivateParts.create(privateMethods);
之后所有的私有变量、私有方法,都通过:_(this).*** 来获取句柄。

function isType(type) {
    return function (obj) {
        return Object.prototype.toString.call(obj) === "[object " + type + "]";
    };
}
var isFunction = isType('Function');

var PrivateParts = {
    create: function (methods) {
        var store = {};
        return function (obj) {
            for (var k in methods) {
                if (isFunction(methods[k]) && !store[k]) {
                    (function (_k) {
                        store[_k] = function () {
                            return methods[_k].apply(obj, arguments);
                        };
                    })(k);
                }
            }
            return store;
        };
    }
};

// 以下是sample
var A = function (opt) {
    this.getAttr = function () {
        return _(this).attr;
    };
    this.getPrivateMethod = function (key) {
        return _(this)[key];
    };
    
    var privateMethods = Object.create(A.prototype);
    privateMethods.invokePublic = function (str) {
        str = str || '1';
        return this.getNameAndAttr() + str;
    };
    privateMethods.invokePrivate = function (str) {
        str = str || '2';
        return _(this).invokePublic() + str;
    };
    privateMethods.getParams = function (str) {
        str = str || '3';
        return _(this).attr + this.name + str;
    };
    
    var _ = PrivateParts.create(privateMethods);
    opt = opt || {};
    this.name = opt.name || 'name';
    _(this).attr = opt.attr || 'attr';
};

A.prototype.getName = function () {
    return this.name;
};
A.prototype.getNameAndAttr = function () {
    return this.getName() + this.getAttr();
};

var a1 = new A();
function process(obj, str) {
    function printcall(method) {
        console.log(method ? method(str) : 'cannot access');
    }
    console.log(obj.name, obj.attr, obj.getAttr());
    printcall(obj.invokePublic);
    printcall(obj.getPrivateMethod('invokePublic'));
    printcall(obj.invokePrivate);
    printcall(obj.getPrivateMethod('invokePrivate'));
    printcall(obj.getParams);
    printcall(obj.getPrivateMethod('getParams'));
}
process(a1);

End

上述依然远非最终版本,只是自己设计的一个2.0版本而已。

司徒正美的《JS框架设计》里面chapter5也有很多不错的类工厂范例,值得推荐!

So, 欢迎大家提出建议,Jefferson Deng waiting for you.

@catjam
Copy link

catjam commented Aug 3, 2017

俊哥 666

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants