Javascript 将对象封装为当调用类似“set”的方法时,它';s执行,并返回对象本身(与JQuery非常相似)

Javascript 将对象封装为当调用类似“set”的方法时,它';s执行,并返回对象本身(与JQuery非常相似),javascript,closures,Javascript,Closures,我试图抽象JQuery的常见行为,这使我能够更轻松地编写代码:将对象封装到调用类似set的方法、执行该方法并返回对象本身时(非常像JQuery) 看: 测试用例是: // works let date = new Date(); console.log(date.setDate(10)); // logs 1494447383428 console.log(date.getDate()); // logs 10 console.log(Date.prototype.setDate.apply(d

我试图抽象JQuery的常见行为,这使我能够更轻松地编写代码:将对象封装到调用类似
set
的方法、执行该方法并返回对象本身时(非常像JQuery)

看:

测试用例是:

// works
let date = new Date();
console.log(date.setDate(10)); // logs 1494447383428
console.log(date.getDate()); // logs 10
console.log(Date.prototype.setDate.apply(date, [20])); // logs 1494447383428
console.log(date.getDate()); // logs 20

// does not work
let ED = encapsulate(Date);
let date1 = new ED();
console.log(date1.setDate(10)); // should log date1 object but throws an error
在不兼容的接收器[对象对象]上调用的方法Date.prototype.setDate会引发错误

你能帮我吗?D:

(更新)来自Bergi的新建议:

let encapsulate = function (guy) {
    return function () {
        this.inner = new (Function.prototype.bind.apply(guy, arguments))

        let prototype =
            Object.getOwnPropertyNames(guy.prototype)
                .reduce((proto, propName) => {
                    let method = propName.match(/^set/g) ?
                        (function () {
                            guy.prototype[propName].apply(this.inner, [].slice.apply(arguments))
                            return this
                        }).bind(this) :
                        (function () {
                            return guy.prototype[propName].apply(this.inner, [].slice.apply(arguments))
                        }).bind(this)

                    return Object.defineProperty(proto, propName, {
                        value: method,
                        enumerable: false,
                        writable: false,
                        configurable: false
                    })
                }, {})

        Object.defineProperty(prototype, 'applyFunction', {
            value: fn => { fn(this); return this },
            enumerable: false,
            writable: false,
            configurable: false
        })

        Object.setPrototypeOf(this, prototype)
    }
}
(已弃用)按照Bergi所说的,我已经使用合成完成了这项工作:

let encapsulate = function (guy) {
    return function () {
        let argumentsWrapper =
            [].slice.apply(arguments)
                .reduce((aw, argument, idx) => {
                    aw['a' + idx] = argument;
                    return aw;
                }, {})

        this.inner = eval('new guy(' +
            Object.keys(argumentsWrapper)
                .reduce((string, argumentName, idx, arr) =>
                    string + 'argumentsWrapper.'
                    + argumentName
                    + (idx != arr.length - 1 ? ',' : ''),
                '')
            + ')')

        let setProperties = Object.getOwnPropertyNames(guy.prototype)
            .filter(propName => propName.match(/^set/g))

        setProperties.forEach(function (propName) {
                this[propName] = (function () {
                    guy.prototype[propName].apply(this.inner, [].slice.apply(arguments))
                    return this
                }).bind(this)
            }, this)

        Object.getOwnPropertyNames(guy.prototype)
            .filter(propName => !propName.match(/^set/g))
            .forEach(function (propName) {
                this[propName] = (function () {
                    return guy.prototype[propName].apply(this.inner, [].slice.apply(arguments))
                }).bind(this)
            }, this)

        this.applyFunction = fn => {
            fn(this)
            return this
        }
    }
}

它不漂亮://

它的意思正是它所说的
Date
不是真正的子类,当然也不像您那样。尝试使用组合而不是继承(就像jQuery那样)!当然但是这个错误,为什么在我调用
guy.prototype[propName].apply(这个,[].slice.apply(参数))
时出现,而不是在调用
Date.prototype.setDate.apply(Date[20])
时出现?我很困惑。因为
date
是一个具有适当内部插槽的真实日期实例,而
this
不是-一个继承自
date.prototype
的对象是不够的。我明白了!我正在用我所做的来回答我自己的问题。关于如何避免
评估
,请看一看。另外,您不应该将所有这些属性放在返回函数的
.prototype
上吗?谢谢,@Bergi!现在可以了吗?不可以,不要在每次调用时重新创建那些
prototype
对象并使用
Object.setPrototypeOf(this)
,而应该将它们分配给
封装
返回的函数的
.prototype
let encapsulate = function (guy) {
    return function () {
        let argumentsWrapper =
            [].slice.apply(arguments)
                .reduce((aw, argument, idx) => {
                    aw['a' + idx] = argument;
                    return aw;
                }, {})

        this.inner = eval('new guy(' +
            Object.keys(argumentsWrapper)
                .reduce((string, argumentName, idx, arr) =>
                    string + 'argumentsWrapper.'
                    + argumentName
                    + (idx != arr.length - 1 ? ',' : ''),
                '')
            + ')')

        let setProperties = Object.getOwnPropertyNames(guy.prototype)
            .filter(propName => propName.match(/^set/g))

        setProperties.forEach(function (propName) {
                this[propName] = (function () {
                    guy.prototype[propName].apply(this.inner, [].slice.apply(arguments))
                    return this
                }).bind(this)
            }, this)

        Object.getOwnPropertyNames(guy.prototype)
            .filter(propName => !propName.match(/^set/g))
            .forEach(function (propName) {
                this[propName] = (function () {
                    return guy.prototype[propName].apply(this.inner, [].slice.apply(arguments))
                }).bind(this)
            }, this)

        this.applyFunction = fn => {
            fn(this)
            return this
        }
    }
}