Ruby的改进允许您临时“升级”词法范围内的对象。我正试图在javascript中实现类似的想法。这里有一些工作代码几乎我想要的东西:
function dateExtension() {
return {
day: function() { return this.getDate() }
}
}
function refine(ctor, mixin) {
return function() {
var ret = new (Function.prototype.bind.apply(ctor, arguments));
return Object.assign(ret, mixin);
}
}
function test() {
// Cant overwrite native Date function,
// so have to rename it.
var XDate = refine(Date, dateExtension());
var d = new XDate();
console.log(d.day()); // prints the day of the month to console
}
test();
我真正想做的是:
function test() {
var Date = refine(Date, dateExtension());
var d = new Date();
console.log(d.day()); // Uncaught TypeError: Bind must be called on a function
}
我们的想法是仅在var Date
的正文中使本地Date
覆盖内置test()
。因此,在test()
内,它会获得新方法day()
,但test()
Date
之外的方法不受影响。这显然是不允许的。
是否有一些解决方法可以使这个想法发挥作用?
答案 0 :(得分:1)
我做了tiny library called chill-patch来做到这一点。它使您能够将函数用作方法,并安全地修补原型。
以下是如何使用它的示例:
const chillPatch = require('chill-patch')
const lastFunc = arr => arr[arr.length - 1]
const array = [1, 2, 3]
// safely add a method to `Array`
const last = chillPatch(Array, lastFunc, 'last')
// call the new method!
array[last]() //=> 3
如果您想自己动手,整个源代码如下:
'use strict'
const chillPatch = (klass, func, optionalDescription) => {
const symbol = Symbol(optionalDescription)
klass.prototype[symbol] = function(){
const args = Array.prototype.slice.call(arguments)
args.unshift(this)
return func.apply(null, args)
}
return symbol
};
module.exports = chillPatch
我看到你在评论中说你不想修改原型,但你的理由可能是修改原型是危险的。但是,上面的方法使用Symbol补丁,这是完全安全的。除非有人使用
进行反思,否则更改对代码库的其他部分是不可见的Object.getOwnPropertySymbols()
答案 1 :(得分:0)
所以我想出了一些有用的东西,虽然它很讨厌。
这是一个小提琴:https://jsfiddle.net/40cty4qa/
这是代码
function lg() { console.log.apply(console, arguments) }
function extend(o, mixin) {
for (var k in mixin) o.prototype[k] = mixin[k]
}
function unextend(o, mixin) {
for (var k in mixin) delete o.prototype[k];
}
Function.prototype.refine = function(ctor, mixin) {
var self = this;
return function() {
extend(ctor, mixin);
var ret = self.apply(this, arguments);
unextend(ctor, mixin);
return ret;
}
}
function dateExtension() {
return {
day: function() { return this.getDate() }
}
}
function refine(ctor, mixin) {
return function() {
var ret = new (Function.prototype.bind.apply(ctor, arguments));
return Object.assign(ret, mixin);
}
}
function test() {
var d = new Date();
lg(d.day());
}
test = test.refine(Date, dateExtension());
test(); // This works, since were inside a refinement
var d = new Date();
lg(d.day()); // This doesnt work, as desired.