在javascript中获取实例父属性访问器链



我有理由相信我想要的是可能的,但我没有正确表达,而且在搜索它时遇到了困难。我试图实现的目标如下:

想象一下,我有一个通用对象obj,如下所示:

const obj={
job:function(){},
age:function(){},
school:function(){}
}

我希望能够将其称为具有可变长度的对象属性的链表,然后在最终方法中访问该链表。一些例子:

js

obj.job.school.age.job.school() // in the school body, I should know  'job.school.age.job' and that I am `school`
obj.job.school() // in the school body, I should know 'job' and that I am `school`
obj.job.job.job() // in the job body, I should know 'job.job' and that I am `job`

格式无关紧要。它不一定是一根绳子。主要的一点是,在最后的方法中,我应该知道这个实例的属性链。属性应该能够作为函数或纯属性进行链接。

在我看来,有两个问题需要解决。第一个是链接部分。我想我解决了这个问题:js

Object.setPrototypeOf(obj.job,obj)
Object.setPrototypeOf(obj.school,obj)
Object.setPrototypeOf(obj.age,obj)

这使得对象在每个键处都可以动态链接。因此,例如,它允许:

obj.job.job.school.job.age.age.school.job.school.age.age.job()

但我被第二部分卡住了。这就是要知道我们是如何到达方法体内部的。因此,在上面的最后一个job方法中,应该知道它是job,在这个例子中,它前面的属性是:job.job.school.job.age.age.school.job.school.age.age

我希望这不是太混乱。如果有什么不清楚的地方,我会编辑。

链接不是魔法。当你说

a.b.c()

它真的和一样

let x = a.b
x.c()

所以在您的例子中,obj有3个键,每个键都是一个函数。如果每个函数都返回this,那么你可以将它们链接起来,但你也必须调用函数——不仅仅是给出它的密钥:

const obj={
job: () => {/* do something */ return obj},
age: () => {/* do something */ return obj},
school: () => {/* do something */ return obj}
}
// you can now chain them because each returns 'obj'
obj.job().job().school().job().age().age().school().job().school().age().age().job();
// but doing this won't work since obj.job returns the job function itself, not obj
obj.job.job();
// gives: Uncaught TypeError: obj.job.job is not a function

根据您的问题,您似乎希望在实现链接的同时跟踪函数调用。这是解决你问题的可能办法。也许它可以改进,但它会为你提供基本的想法。

问题01:

我们需要链接行为,下面是我们的做法。

const email_validator = {
tld: function(){ return this;},
min: function(length){ return this;},
max: function(length){ return this; }
}

请确保使用常规函数,因为它们会按预期工作,在web浏览器的情况下,箭头函数会导致问题。

问题02

跟踪我们的链条。

const email_validator = {
// Regular functions
tld: function(){ this.addToStack(this.tld); return this;},
min: function(length){ this.addToStack(this.min); return this;},
max: function(length){ this.addToStack(this.max); return this; },
// We will keep track of chain.
stack: [],
// The function needs to be after each function call.
addToStack: function(func){ this.stack.push(func); }
}

上面的代码将把每个函数调用存储在一个数组中,只需确保在每个函数之后调用addToStack函数,然后再返回。

如果你想跟踪字符串而不是函数,你可以传递字符串而不是函式。或者根据您的需要进行更改。

我希望以上内容能为您提供一些如何做到这一点的想法。

用法

以下是如何使用上述代码:


const email_validator = {
// Regular functions
tld: function(){ this.addToStack(this.tld); return this;},
min: function(length){ this.addToStack(this.min); return this;},
max: function(length){ this.addToStack(this.max); return this; },
// We will keep track of chain.
stack: [],
// The function needs to be after each function call.
addToStack: function(func){ this.stack.push(func); }
}
// This will contain stack of functions.
const history = email_validator.tld().tld().max().tld().stack;
// Print in format: tld.tld.max
const message = history.map(item => item.name).join(".");
console.log(message); // tld.tld.max

我意识到这个问题已经过时了,但我觉得这个问题应该得到答案——这能实现你想要做的吗?:


function the_obj() {
console.log(...arguments)
console.log(the_obj.accessStack)
the_obj.accessStack.splice(0, the_obj.accessStack.length)
}
the_obj.accessStack = []
Object.defineProperty(the_obj, 'job', {
get: function() {
the_obj.accessStack.push('job')
return the_obj
},
})
Object.defineProperty(the_obj, 'school', {
get: function() {
the_obj.accessStack.push('school')
return the_obj
},
})
Object.defineProperty(the_obj, 'age', {
get: function() {
the_obj.accessStack.push('age')
return the_obj
},
}) 

the_obj.job.school.age.job.school() // ['job', 'school', 'age', 'job', 'school']

最新更新