如果属性名称相同,是否有办法自动调用父方法。
// library part
var parent = {
foo: function() { console.log('foo from parent'); },
bar: function() { console.log('bar from parent'); }
}
// User part
var child = Object.create(parent);
child.foo = function() { console.log('foo from child'); };
child.bar = function() { console.log('bar from child'); };
如果我调用child.foo()
,则输出为foo from child
,我的目标输出为foo from child
,foo from parent
是控制台注销的。现在,当我需要这样做时,我使用这段代码:
child.foo = function() {
console.log('foo from child');
this.__proto__.foo();
}
我有理由这样做,它就像提供可以由用户扩展的父对象的库,而我不想提醒用户每次调用this.__proto__.foo()
他们分配属性名称与父对象属性相同的方法的时间。
解决方案当然必须修改库部分(父对象或可能在对象创建中),而不是用户部分。
答案 0 :(得分:3)
解决方案当然必须修改库部分(父对象或可能在对象创建中),而不是用户部分。
如果这意味着你真的希望用户能够写
child.foo = function() { ... };
...然后这会改变一些事情,但是仍然可以不使用代理(真的慢)。首先,我的原始答案,因为你接受了它,然后更新说明:
我不想提醒用户每次分配属性名称与父对象属性相同的方法时调用
this.__proto__.foo()
在这种情况下,您可能希望为它们提供一个工作函数,用于设置这些函数属性,并自动检测情况并对其进行处理。你必须决定是否在用户的新代码之前或之后调用原型的版本,如果你不打算让它们控制调用的位置,并决定是否返回它们的函数或原型的结果。 / p>
当然,没有什么能阻止他们选择忽略这一点,但只有你能做的事情。
例如,此示例假设您要在之后调用原始(如示例所示)并返回其覆盖的结果。
var mainProto = {
addMethod: function(name, method) {
var p = Object.getPrototypeOf(this); // See note later
if (typeof p[name] === "function") {
this[name] = function() {
var result = method.apply(this, arguments);
p[name].apply(this, arguments);
return result;
};
} else {
this[name] = method;
}
return this;
}
};
var parent = Object.create(mainProto);
parent.addMethod("foo", function foo() { console.log('foo from parent'); });
parent.addMethod("bar", function bar() { console.log('bar from parent'); });
var child = Object.create(parent);
child.addMethod("foo", function foo() { console.log('foo from child'); });
child.addMethod("bar", function bar() { console.log('bar from child'); });
var grandChild = Object.create(child);
grandChild.addMethod("foo", function foo() { console.log('foo from grandChild'); });
grandChild.addMethod("bar", function bar() { console.log('bar from grandChild'); });
console.log("---");
parent.foo();
parent.bar();
console.log("---");
child.foo();
child.bar();
console.log("---");
grandChild.foo();
grandChild.bar();
.as-console-wrapper {
max-height: 100% !important;
}
关于__proto__
vs getPrototypeOf
:__proto__
官方仅在浏览器上支持,而不是在其他JavaScript环境中支持,并在Object.prototype
上定义,因此完全可以拥有没有它的对象(通过Object.create(null)
)。相反,getPrototypeOf
是跨环境定义的,无论对象是否继承自Object.prototype
,都可以正常工作。
我们可以在相关属性上使用setter来插入包装器而不是让用户调用addMethod
:
// Library code
function wrapMethod(newMethod, parentMethod) {
if (typeof parentMethod === "function") {
return function() {
var result = newMethod.apply(this, arguments);
parentMethod.apply(this, arguments);
return result;
};
}
return newMethod;
}
function defineMethod(obj, name, method) {
Object.defineProperty(obj, name, {
set: function(newValue) {
if (this === obj) {
return;
}
defineMethod(this, name,wrapMethod(newValue, Object.getPrototypeOf(this)[name]));
},
get: function() {
if (this === obj) {
return method;
}
return this[name];
}
});
}
var parent = (function() {
var _foo = function foo() { console.log("foo from parent"); };
var _bar = function bar() { console.log("bar from parent"); };
var parent = {};
defineMethod(parent, "foo", _foo);
defineMethod(parent, "bar", _bar);
return parent;
})();
// User code
var child = Object.create(parent);
child.foo = function foo() { console.log('foo from child'); };
child.bar = function bar() { console.log('bar from child'); };
var grandChild = Object.create(child);
grandChild.foo = function foo() { console.log('foo from grandChild'); };
grandChild.bar = function bar() { console.log('bar from grandChild'); };
console.log("---");
parent.foo();
parent.bar();
console.log("---");
child.foo();
child.bar();
console.log("---");
grandChild.foo();
grandChild.bar();
.as-console-wrapper {
max-height: 100% !important;
}
答案 1 :(得分:0)
我想另一种方法是在没有明确调用 proto 的情况下使用工厂函数:
const createChild = parent => Object.create(parent);
const enchanceChild = parent => ({
foo() {
console.log('from child');
parent.foo();
}
});
const parent = {
foo(){ console.log('from parent') },
}
const child = createChild(parent);
const enchancedChild = enchanceChild(child);
enchancedChild.foo(); // from child form parent
这只是做你已经做过的事情的另一种方法。
您怎么看?
修改强>
使用Proxy Objects更清洁的方法:
var createObject = parent => {
var handler = {
get(target, name) {
if (typeof target[name] === 'function' && typeof parent[name] === 'function') {
return function() {
const res = target[name]();
parent[name]();
return res;
}
}
return target[name];
}
}
return new Proxy({}, handler);
}
const parent = { foo() { console.log('parent'); }, };
const child = createObject(parent);
child.foo = () => console.log('child');
child.foo();
// returns:
// child
// parent