简体   繁体   中英

arguments.callee alternative in es6 for determining caller function

In framework, I'm developing, I've constructed mechanism, that allowed to define private and protected properties and methods.
The only ability, I found in ES5 specifications for doing that was using arguments.callee
like this:

descriptor.method = function () {
    if (__callerIsProptected(arguments.callee.caller.caller, cls))
        return value.apply(this, __defaults(_.values(arguments), defaults));
    throw 'Attempt to call ' + access + ' method "' + cls._name + '::' + name + '"';
};

As far as in strict mode calls to arguments.callee and arguments.caller cause throwing of exceptions are there any convenient alternatives to do that?

Update - added whole called function code

    function __descriptor(cls, type, name, descriptor, access) {
    //protected private non-function descriptor.value is replaced by get/set pair
    if (access !== 'public' && type == 'property') {
        delete descriptor.value;
        delete descriptor.writable;
        _.isFunction(descriptor.get) || (descriptor.get = function () {
            return this.__get(name);
        });
        _.isFunction(descriptor.set) || (descriptor.set = function (value) {
            return this.__set(name, value);
        });
    }
    //remove uselesses
    if (_.isFunction(descriptor.get) || _.isFunction(descriptor.set)) {
        delete descriptor.value;
        delete descriptor.writable;
        if (!_.isFunction(descriptor.get)) {
            descriptor.get = function () {
                return this.__get(name);
            };
        }
        if (!_.isFunction(descriptor.set)) {
            descriptor.set = function (value) {
                return this.__set(name, value);
            };
        }
    } else {
        delete descriptor.get;
        delete descriptor.set;
    }
    if (descriptor.get) {
        var getter = descriptor.get;
        //mutate getter and setter if given respectively to access level
        if (access === 'public') {
            descriptor.getter = function () {
                return getter.apply(this, arguments);
            };
        } else if (access === 'protected') {
            descriptor.getter = function () {
                if (__callerIsProptected(arguments.callee.caller.caller, cls))
                    return getter.apply(this, arguments);
                throw 'Attempt to get ' + access + ' property "' + cls._name + '::' + name + '"';
            };
        } else if (access === 'private') {
            descriptor.getter = function () {
                if (__callerIsPrivate(arguments.callee.caller.caller, cls))
                    return getter.apply(this, arguments);
                throw 'Attempt to get ' + access + ' property "' + cls._name + '::' + name + '"';
            };
        }
        descriptor.getter._class = cls;
    }
    if (descriptor.set) {
        var setter = descriptor.set;
        //mutate getter and setter if given respectively to access level
        if (access === 'public') {
            descriptor.setter = function () {
                return setter.apply(this, arguments);
            };
        } else if (access === 'protected') {
            descriptor.setter = function () {
                if (__callerIsProptected(arguments.callee.caller.caller, cls))
                    return setter.apply(this, arguments);
                throw 'Attempt to set ' + access + ' property "' + cls._name + '::' + name + '"';
            };
        } else if (access === 'private') {
            descriptor.setter = function () {
                if (__callerIsPrivate(arguments.callee.caller.caller, cls))
                    return setter.apply(this, arguments);
                throw 'Attempt to set ' + access + ' property "' + cls._name + '::' + name + '"';
            };
        }
        descriptor.setter._class = cls;
    }
    if (descriptor.value !== undefined) {
        if (!_.isFunction(descriptor.value)) return descriptor;
        var value = descriptor.value;
        var defaults = descriptor.defaults || [];
        if (access === 'public' && type == 'method') {
            descriptor.method = function () {
                return value.apply(this, __defaults(_.values(arguments), defaults));
            };
        } else if (access === 'protected') {
            descriptor.method = function () {
                if (__callerIsProptected(arguments.callee.caller.caller, cls))
                    return value.apply(this, __defaults(_.values(arguments), defaults));
                throw 'Attempt to call ' + access + ' method "' + cls._name + '::' + name + '"';
            };
        } else if (access === 'private') {
            descriptor.method = function () {
                if (__callerIsPrivate(arguments.callee.caller.caller, cls))
                    return value.apply(this, __defaults(_.values(arguments), defaults));
                throw 'Attempt to call ' + access + ' method "' + cls._name + '::' + name + '"';
            };
        }
        descriptor.method._class = cls;
    }
    return descriptor;
}

Once I was developing same framework (abandoned) and the only way to figure out a caller in strict mode was to actually throw an exception and RegExp caller name from stack trace. As far as I remember it wasn't always precise. Look for example at the code of caller-id script

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM