Javascript:如何将其他对象B,C的方法与我的对象A混合,而不复制但是链接? [英] Javascript: How can I mix in methods of other Objects B, C to my Object A without copying but with linking?

查看:174
本文介绍了Javascript:如何将其他对象B,C的方法与我的对象A混合,而不复制但是链接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我创建一个对象A:

If I create an Object A:

let A = {};

想要混合其他对象B和C中的方法:

And want to mix in methods from other Objects B and C:

let B = {
    foo() {
        alert("Boo!");
    }
};
let C = {
    bar() {
        alert("No!");
    }
};

通常我会调用:

对象.assign(A,B,C);
然后我更改我的函数foo:

Object.assign(A, B, C); Then I change my function foo:

Object.assign(B, {
    foo() {
        alert("Hooray!");
    }
});
Objcect.assign(C, {
    bar() {
        alert("Yes!");
    }
});

之后我调用foo或bar:

After that I call foo or bar:

A.foo(); // Actual output: "Boo!", desired: "Hooray!"
A.bar(); // Actual output: "No!",  desired: "Yes!"

到目前为止,我发现, Object.assign 只复制目标中的方法,但不链接它们。
我已经上传了一个关于混合的问题,只有一个对象被解决了:混合在一个对象中,解决方案:原型继承

So far I found out, that Object.assign only copies methods in the target, but it doesn't link them. I already uploaded a question concerning mixing in only one Object, which was solved: Mix in one object, solution: prototypical inheritance

关于继承和组合我在这里找到一个有用的博客:了解原型,授权和组合

About inheritance and composition I found a useful blogposts here: Understanding Prototypes, Delegation & Composition

我想在对象中混合方法,但不能复制方法,更重要的是我需要对混合函数的定义进行分配。

I want to mix methods in an Object, but not copy the methods, much more rather I want an assignments to the definitions of the mixed in functions.

怎么可能? (可能在ES2015?)

How is this possible? (Maybe in ES2015?)

推荐答案

两个答案:


我想在对象中混合方法,但不复制方法...

I want to mix methods in an Object, but not copy the methods...

你所做的不是复制方法(函数; JavaScript 没有真正的方法),它重用了你已经有的。功能只有一个 foo bar 只有 A B A C ,都是指相同的功能。

What you're doing isn't copying the methods (functions; JavaScript doesn't really have methods), it's reusing the ones you already have. Only a single foo or bar function exists; there are just properties on A and B, and on A and C, that both refer to that same function.

你可以看到,从 A.foo === B.foo A.bar === C.bar

let B = {
    foo() {
        alert("Boo!");
    }
};
let C = {
    bar() {
        alert("No!");
    }
};
let A = Object.assign({}, B, C);
snippet.log(A.foo === B.foo); // true
snippet.log(A.bar === C.bar); // true

<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

您的代码在内存中产生的内容看起来像这(省略一些细节):

What your code produces in memory looks like this (with some details omitted):


                        +----------+  
                    B>->| (object) |  
                        +----------+     +----------------+
                        | foo      |>-+->|   (function)   |
                        +----------+  |  +----------------+
                                      |  | (code for foo) |
                  +-------------------+  +----------------+
                  |
                  |     +----------+      
                  | C>->| (object) |      
                  |     +----------+     +----------------+
                  |     | bar      |>-+->|   (function)   |
                  |     +----------+  |  +----------------+
                  |                   |  | (code for bar) |
                  |                   |  +----------------+
                  |                   |
    +----------+  |                   |
A>->| (object) |  |                   |
    +----------+  |                   |
    | foo      |>-+                   |
    | bar      |>---------------------+
    +----------+



但是如果你真的想要一个链接



如果你想要<将 B.foo C.bar 函数替换为其他东西,并具有 A 看到这个变化,你可以通过使 foo bar A 属性访问器

But if you really want a link

If you want to be able to replace the B.foo or C.bar function with something else, and have A see that change, you can do that by making foo and bar on A property accessors:

let A = {
    get foo() { return B.foo; },
    get bar() { return C.bar; }
};

现在 A 链接到 B C

let B = {
    foo() {
      snippet.log("foo1");
    }
};
let C = {
    bar() {
      snippet.log("bar1");
    }
};

let A = {
    get foo() { return B.foo; },
    get bar() { return C.bar; }
};

A.foo(); // foo1
A.bar(); // bar1

B.foo = function() {
    snippet.log("foo2");
};

A.foo(); // foo2

C.bar = function() {
    snippet.log("bar2");
};

A.bar(); // bar2

<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

的属性使用 Object.defineProperty

function linkMethods(to, ...from) {
    from.forEach(source => {
        for (let key in source) { // We're intentionally not filtering out inherited
            if (typeof source[key] === "function") {
                Object.defineProperty(to, key, {
                    get: function() {
                        return source[key];
                    }
                });
            }
        }
    });
    return to;
}

在行动中:

function linkMethods(to, ...from) {
    from.forEach(source => {
        for (let key in source) { // We're intentionally not filtering out inherited
            if (typeof source[key] === "function") {
                Object.defineProperty(to, key, {
                    get: function() {
                        return source[key];
                    }
                });
            }
        }
    });
}

let B = {
    foo() {
      snippet.log("foo1");
    }
};
let C = {
    bar() {
      snippet.log("bar1");
    }
};

let A = {};
linkMethods(A, B);
linkMethods(A, C);

A.foo(); // foo1
A.bar(); // bar1

B.foo = function() {
    snippet.log("foo2");
};

A.foo(); // foo2

C.bar = function() {
    snippet.log("bar2");
};

A.bar(); // bar2

<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

尽管我使用了上述的ES2015箭头功能如果您将这些函数转换为函数函数,以上所有这些功能都可以在ES5中工作(但不是ES3或更早版本,没有属性访问器)。

Despite my use of ES2015 arrow functions above, if you convert those to function functions, all of the above works in ES5 (but not ES3 or earlier, which didn't have property accessors).

重新发表评论:


解释复制,引用和链接之间的区别是什么?

Could you please explain what the difference between copying, a reference and a link is?

几个关键的事情:


  1. 在JavaScript中,函数是对象。具有其他类型对象的所有功能的真正的真实对象,以及包含和运行代码的能力。 (这在其他语言中通常不是这样)。

  1. In JavaScript, functions are objects. Genuine, real objects that have all of the features of other kinds of objects, and also the ability to contain and run code. (This is frequently not the case in other languages.)

变量和属性保持

是一个原始的(如1或foo)或对象引用。对象引用不是对象,它只是对对象的引用,它存在于其他位置。

A value is either a primitive (like 1 or "foo"), or an object reference. The object reference isn't the object, it's just a reference to the object, which exists elsewhere.

将值分配给变量或属性时,您正在复制该值。如果该值是一个对象引用,那意味着您要复制该引用,该对象。

When you assign a value to a variable or property, you're copying the value. If the value is an object reference, that means you're copying the reference, not the object.

JavaScript不有(在外部级别)变量引用属性引用。 (大多数语言没有,但有些做)。

JavaScript doesn't have (at the external level) either variable references or property references. (Most languages don't, but some do.)

我喜欢解释对象引用,变量和值像这样:说我们有这个家伙乔。乔今天很高兴,因为他今年42岁,他是银河旅客指南的粉丝。所以他在一张纸上写了42号。 42是一个值,在这种情况下是一个数字。这张纸是一个变量或财产。

I like to explain object references, variables, and values like this: Say we have this guy Joe. Joe's really happy because he's turning 42 today, and he's a fan of The Hitchhiker's Guide to the Galaxy. So he writes the number 42 on a piece of paper. The 42 is a value, in this case a number. The piece of paper is a variable or property.

乔决定参加一个聚会,所以他在休息室通知单上做了一个派对公告,说他是参加聚会,并写上他的家庭住址。该通知也是一个变量或财产。乔的房子是一个对象。在公告中写的地址是一个对象引用,告诉我们Joe的房子在哪里。

Joe decides to have a party, so he puts up a party announcement on the break room notice board at his job saying he's having a party and writes his home address on it. The announcement is also a variable or property. Joe's house is an object. The address written on the announcement is an object reference, telling us where Joe's house is.

Joe在休息室跑进穆罕默德,知道他是一个HHG粉丝,向他显示他的论文42条,并指出了党的公告。穆罕默德拿出一张纸,将42复制到它上面,记住乔的转动程度(可能是购买适合的卡)。也就是说,他将将42(该值)复制到他的纸上(变量/属性)。然后,因为他以前没有去过乔的房子,他得到了另一张纸,从乔的派对公告中复制了房子的地址。只有地址不复制房屋对象未被复制,只是参考

Joe runs into Mohammed in the break room, and knowing he's a fellow HHG fan, shows him his paper with 42 on it, and points out the party announcement. Mohammed gets out a piece of paper and copies the 42 onto it, to remember how old Joe's turning (perhaps to buy the appropriate card). That is, he copies the 42 (the value) onto his piece of paper (the variable/property). Then, because he hasn't been to Joe's house before, he gets another piece of paper and copies the house's address from Joe's party announcement. The house isn't copied, just the address. The object wasn't copied, just the reference to it.

之后,Joe意识到派对的过程他的房子很大,决定搬到城里一家酒吧。他在公告上交出了地址,写在酒吧的地址上。但他忘了告诉穆罕默德。所以来聚会的时候,穆罕默德去了乔的家而不是酒吧。

Later, Joe realizes the party's getting too big for his house, and decides to move it to a pub in the city. He crosses out the address on the announcement and writes in the address of the pub. But he forgets to tell Mohammed. So come party time, Mohammed goes to Joe's house instead of the pub.

回到JavaScript和功能,这是对象:

Back to JavaScript and functions, which are objects:

如果你有:

let B = {
    foo() {
        console.log("I'm foo");
    }
};

B.foo 包含 foo 函数,它包含指向 foo 的值(对象引用) 函数。然后当你这样做:

B.foo doesn't contain the foo function, it contains a value (an object reference) that refers to the foo function. Then when you do:

let A = {};
A.foo = B.foo;

...你复制 code> B.foo into A.foo 。没有任何连接,在 A.foo B.foo 之间没有链接,除了他们恰好包含同样的价值,就像Joe的派对公告和Mohammed的论文没有任何关系,除了他们碰巧都有Joe的地址(首先)。

...you copy the value (the object reference) from B.foo into A.foo. There is no connection, no link whatsoever between A.foo and B.foo other than that they happen to contain the same value, just like there's no connection between Joe's party announcement and Mohammed's piece of paper, other than that they happen to both have Joe's address on them (to start with).

后来,如果你执行 B.foo = function(){/*...*/}; ,你正在替换 B.foo 与一个引用另一个功能的新的值。这对 A.foo 没有影响,因为再次, A.foo B.foo 。就像Joe在派对公告上写下地址,并写在酒吧的地址上一样,对Mohammed的纸张没有任何影响。

Later, if you do B.foo = function() { /*...*/ };, you're replacing the value in B.foo with a new value that refers to a different function. This has no effect on A.foo because, again, there's no link between A.foo and B.foo. Just like it didn't have any effect on Mohammed's piece of paper when Joe crossed out the address on the party announcement and wrote in the address of the pub.

原因我上面的属性访问器机制是一个属性访问器是一个函数,它每次读取属性的值时都会运行。所以当你得到 A.foo 的值时,它真的运行一个函数,返回值 B.foo 因为它是然后,不如以前那样。比喻将是穆罕默德在他的纸上写下看公告,而不是写下乔的地址,然后准备去参加聚会,看着他的纸张记住去哪里,看到看看这个公告,回到休息室,看到更新的地址—并进入酒吧。

The reason my property accessor mechanism above works is that a property accessor is a function which gets run every time you read the property's value. So when you get the value of A.foo, it really runs a function that returns the value of B.foo as it is then, not as it was earlier. The analogy would be Mohammed writing down "look at the announcement" on his piece of paper instead of writing down Joe's address, and then when getting ready to go to the party, looking at his piece of paper to remember where to go, seeing "look at the announcement," going back to the break room, and seeing the updated address — and thus going to the pub.

这篇关于Javascript:如何将其他对象B,C的方法与我的对象A混合,而不复制但是链接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆