javascript无法访问私有资产 [英] javascript can't access private properties

查看:123
本文介绍了javascript无法访问私有资产的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码,我不明白为什么在重新声明get方法时无法访问私有属性。

I have the following code and I don't understand why I can't access the private properties when I redeclare the get method.

(function(w,d,a,undefined){
    var cfg = {
        currency: 'GBP',
        exponent: 2
    };
    var get = function () {
        return cfg;
    };
    a.init = function (settings) {
        for (var k in settings) {
            cfg[k] = settings[k];
        }
    };
    a.set = function (args) {
        get = args.get || get;
        //eval(args) //works but why??
    };
    a.get = function () {
        return get();
    };
})(window,document,window.fxc = {});

fxc.init({currency: 'EUR'});

// prints, Object { currency="EUR", exponent=2}
console.log(fxc.get());

fxc.set({get: function(msg){
    // cannot access private properties
    return cfg;
}});

// prints, undefined
console.log(fxc.get());

我一直试图找到正确的方法来做一段时间,但我可以'似乎找到了正确的组合。我确实有 eval(),但肯定不是正确的方法吗?会喜欢任何帮助。

I've been trying to find the right way to do this for a while now but I can't seem to find the correct combination. I did have eval(), but surely that can't be the right way? Would love any help.

推荐答案

这是正确的。部分原因是因为javascript没有私有属性。你所做的不是宣布私人财产。您正在使用一个使用闭包来模拟私有属性的设计模式。

That's correct. Partly because javascript does not have private properties. What you're doing is not declaring a private property. You're using a design pattern that uses a closure to emulate private properties.

闭包变得超出范围。范围是指变量的生命周期,而对象属性是指变量的绑定。

Closures evolve out of scope. A scope refers to the lifespan of variables while object properties refer to binding of variables.

因此,在讨论闭包之前,我们先简单讨论一下范围。

So before discussing closures, lets have a short discussion about scope.

范围与堆栈框架相关(在计算机科学中它被称为激活记录但大多数开发人员熟悉C或汇编知道它更好地作为堆栈框架)。范围是堆栈框架类对象的类型。我的意思是,当一个对象是一个类的实例时,一个堆栈框架就是一个范围的实例。

A scope is related to the stack frame (in Computer Science it's called the "activation record" but most developers familiar with C or assembly know it better as stack frame). A scope is to a stack frame what a class is to an object. By that I mean that where an object is an instance of a class, a stack frame is an instance of scope.

让我们用一种虚构的语言作为例子。在这种语言中,就像在javascript中一样,函数定义范围。让我们来看一个示例代码:

Let's use a made-up language as an example. In this language, like in javascript, functions define scope. Lets take a look at an example code:

var global_var

function b {
    var bb
}

function a {
    var aa
    b();
}

当我们阅读上面的代码时,我们说变量 aa 在函数 a 的范围内,变量 bb 在范围内功能 b 。请注意,我们不会将此事称为私有变量。因为私有变量的反义是公共变量,并且都引用绑定到对象的属性。相反,我们调用 aa bb 局部变量。局部变量的反面是全局变量(不是公共变量)。

When we read the code above, we say that the variable aa is in scope in function a and the variable bb is in scope in function b. Note that we don't call this thing private variables. Because the opposite of private variables are public variables and both refer to properties bound to objects. Instead we call aa and bb local variables. The opposite of local variables are global variables (not public variables).

现在,让我们看看当我们调用 a

Now, let's see what happens when we call a:

a()被调用,创建一个新的堆栈帧。为堆栈上的局部变量分配空间:

a() gets called, create a new stack frame. Allocate space for local variables on the stack:

The stack:
 ┌────────┐
 │ var aa │ <── a's stack frame
 ╞════════╡
 ┆        ┆ <── caller's stack frame

a()来电 b(),创建一个新的堆栈帧。为堆栈上的局部变量分配空间:

a() calls b(), create a new stack frame. Allocate space for local variables on the stack:

The stack:
 ┌────────┐
 │ var bb │ <── b's stack frame
 ╞════════╡
 │ var aa │
 ╞════════╡
 ┆        ┆

在大多数编程语言中,这个包括javascript,一个函数只能访问自己的堆栈帧。因此 a()无法访问 b()中的局部变量,全局范围访问中的任何其他函数或代码都不能访问 a()中的变量。唯一的例外是全局范围内的变量。从实现的角度来看,这是通过在不属于堆栈的内存区域中分配全局变量来实现的。这通常称为堆。所以为了完成图片,此时内存看起来像这样:

In most programming languages, and this includes javascript, a function only has access to its own stack frame. Thus a() cannot access local variables in b() and neither can any other function or code in global scope access variables in a(). The only exception are variables in global scope. From an implementation point of view this is achieved by allocating global variables in an area of memory that does not belong to the stack. This is generally called the heap. So to complete the picture the memory at this point looks like this:

The stack:     The heap:
 ┌────────┐   ┌────────────┐
 │ var bb │   │ global_var │
 ╞════════╡   │            │
 │ var aa │   └────────────┘
 ╞════════╡
 ┆        ┆

(作为旁注,你也可以使用malloc()或new在函数内的堆上分配变量)

(as a side note, you can also allocate variables on the heap inside functions using malloc() or new)

现在 b()完成并返回,它的堆栈帧从堆栈中删除:

Now b() completes and returns, it's stack frame is removed from the stack:

The stack:     The heap:
 ┌────────┐   ┌────────────┐
 │ var aa │   │ global_var │
 ╞════════╡   │            │
 ┆        ┆   └────────────┘

以及 a()完成同样的堆栈帧。这就是局部变量如何被自动分配和释放 - 通过从堆栈中推出和弹出对象。

and when a() completes the same happens to its stack frame. This is how local variables gets allocated and freed automatically - via pushing and popping objects off the stack.

闭包是一种更高级的堆栈帧。但是,一旦函数返回,正常的堆栈帧就会被删除,带闭包的语言只会将堆栈帧(或它只包含的对象)从堆栈中取消链接,同时保持对堆栈帧的引用,只要它是必需的。

A closure is a more advanced stack frame. But whereas normal stack frames gets deleted once a function returns, a language with closures will merely unlink the stack frame (or just the objects it contains) from the stack while keeping a reference to the stack frame for as long as it's required.

现在让我们看一下带闭包语言的示例代码:

Now let's look at an example code of a language with closures:

function b {
    var bb
    return function {
        var cc
    }
}

function a {
    var aa
    return b()
}

现在让我们看看如果我们这样做会发生什么:

Now let's see what happens if we do this:

var c = a()

调用第一个函数 a(),然后调用 b() 。创建堆栈帧并将其压入堆栈:

First function a() is called which in turn calls b(). Stack frames are created and pushed onto the stack:

The stack:
 ┌────────┐
 │ var bb │
 ╞════════╡
 │ var aa │
 ╞════════╡
 │ var c  │
 ┆        ┆

功能 b()返回,所以它的堆栈帧从堆栈中弹出。但是,函数 b()返回一个匿名函数,该函数在闭包中捕获 bb 。所以我们弹出堆栈框架,但不要从内存中删除它(直到所有对它的引用都被完全垃圾收集):

Function b() returns, so it's stack frame is popped off the stack. But, function b() returns an anonymous function which captures bb in a closure. So we pop off the stack frame but don't delete it from memory (until all references to it has been completely garbage collected):

The stack:             somewhere in RAM:
 ┌────────┐           ┌╶╶╶╶╶╶╶╶╶┐
 │ var aa │           ┆ var bb  ┆
 ╞════════╡           └╶╶╶╶╶╶╶╶╶┘
 │ var c  │
 ┆        ┆

a()现在将函数返回到 c 。因此,对 b()的调用的堆栈帧被链接到变量 c 。请注意,它是链接的堆栈帧,而不是范围。有点像从类中创建对象,它是分配给变量的对象,而不是类:

a() now returns the function to c. So the stack frame of the call to b() gets linked to the variable c. Note that it's the stack frame that gets linked, not the scope. It's kind of like if you create objects from a class it's the objects that gets assigned to variables, not the class:

The stack:             somewhere in RAM:
 ┌────────┐           ┌╶╶╶╶╶╶╶╶╶┐
 │ var c╶╶├╶╶╶╶╶╶╶╶╶╶╶┆ var bb  ┆
 ╞════════╡           └╶╶╶╶╶╶╶╶╶┘
 ┆        ┆

另请注意,因为我们实际上没有调用函数 c() ,变量 cc 尚未在内存中的任何位置分配。在我们调用 c()之前,它目前只是一个范围,还不是堆栈框架。

Also note that since we haven't actually called the function c(), the variable cc is not yet allocated anywhere in memory. It's currently only a scope, not yet a stack frame until we call c().

现在会发生什么我们叫 c()?正常创建 c()的堆栈框架。但这次有区别:

Now what happens when we call c()? A stack frame for c() is created as normal. But this time there is a difference:

The stack:
 ┌────────┬──────────┐
 │ var cc    var bb  │  <──── attached closure
 ╞════════╤──────────┘
 │ var c  │
 ┆        ┆

b()的堆栈框架附加到 c()的堆栈框架。所以从函数 c()的角度来看,它的堆栈还包含函数 b()(再次注意,不是函数b()中的变量,而是调用函数b()时创建的变量 - 换句话说,不是b()的范围,而是调用b()时创建的堆栈帧。这意味着只有一个可能的函数b(),但很多调用b()创建了许多堆栈帧。

The stack frame of b() is attached to the stack frame of c(). So from the point of view of function c() it's stack also contains all the variables that were created when function b() was called (Note again, not the variables in function b() but the variables created when function b() was called - in other words, not the scope of b() but the stack frame created when calling b(). The implication is that there is only one possible function b() but many calls to b() creating many stack frames).

但本地和全局变量的规则仍然存在适用。 b()中的所有变量都成为 c()的局部变量,而不是其他任何变量。调用 c()的函数无法访问它们。

But the rules of local and global variables still applies. All variables in b() become local variables to c() and nothing else. The function that called c() has no access to them.

这意味着当你重新定义<调用者范围内的code> c 如下所示:

What this means is that when you redefine c in the caller's scope like this:

var c = function {/* new function */}

发生这种情况:

                     somewhere in RAM:
                           ┌╶╶╶╶╶╶╶╶╶┐
                           ┆ var bb  ┆
                           └╶╶╶╶╶╶╶╶╶┘
The stack:
 ┌────────┐           ┌╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶┐
 │ var c╶╶├╶╶╶╶╶╶╶╶╶╶╶┆ /* new function */ ┆
 ╞════════╡           └╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶┘
 ┆        ┆

正如你所看到的,重新夺回一个是不可能的从 b()的调用中访问堆栈帧,因为 c 所属的范围无权访问对它来说。

As you can see, it's impossible to regain access to the stack frame from the call to b() since the scope that c belongs to doesn't have access to it.

解决方法,因为这是一个绑定(javascript称之为上下文)问题不是范围问题,是使用对象绑定来存储你的 cfg 对象。

The workaround, since this is a binding (javascript calls it context) issue not a scope issue, is to use object binding to store your cfg object.

不幸的是,javascript没有私有变量。因此,只能将其绑定为公共变量。解决方法解决此问题的方法是使用Perl约定来告诉其他程序员不要触摸该对象,除非他们正在修改实现本身。该惯例是使用下划线开始变量名称:

Unfortunately javascript doesn't have private variables. So it's only possible to bind it as a public variable. The workaround's workaround to this problem is to use Perl convention to tell other programmers not to touch that object unless they're modifying the implementation itself. And that convention is to start a variable name with underscores:

// WARNING: Private!
a._cfg = {
    currency: 'GBP',
    exponent: 2
};

这篇关于javascript无法访问私有资产的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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