最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Is there a way to create JavaScript objects that behave like C++ RValues? - Stack Overflow

programmeradmin4浏览0评论

I'm a C++ programmer who recently landed on the JavaScript world; now I'm trying to apply some of the dessign patterns of C++ to JavaScript for the sake of my understanding and mental health.

AFAIK, the following codes are kind of equivalent in C++ and Javascript:

C++

// Class definition
template <typename T> class foo
{
public:
    // Constructor
    foo(T value) { this->value = value; }
    // Public function
    T twice() { return this->value + this->value; }

private:
    // Private function
    void bar() { }
    // Private member
    T value;
};

JavaScript

// "Class" definition and constructor
function foo(value)
{
    // "Private" member
    this.value = value;

    // "Private" function
    this.bar = function() { };
}

// Public function
foo.prototype.twice = function() { return this.value + this.value; };

The usage of both classes are similar too:

C++ live demo

foo<int> f1(1);
foo<std::string> f2("1");

std::cout << f1.twice() << '\n'; // output: 2
std::cout << f2.twice() << '\n'; // output: 11

JavaScript live demo

var f1 = new foo(1);
var f2 = new foo('1');

print(f1.twice()); // output: 2
print(f2.twice()); // output: 11

But there's a thing that cannot be done with a JavaScript class and is possible to do with a C++ class: the use of a temporary RValue to do a task:

C++

std::cout << foo<float>(3.14f).twice() << '\n'; // output: 6.28

JavaScript

print(foo(3.14).twice()); // Uncaught TypeError: undefined is not a function

I think that the error on the JavaScript version is due to the fact that foo is a function and it returns nothing (undefined), so at first I was thinking of change the constructor with the code below:

JavaScript

// "Class" definition and constructor
function foo(value)
{
    // "Private" member
    this.value = value;

    // "Private" function
    this.bar = function() { };

    return this; // <----- new code!
}

But this doesn't work at all; the object returned by the return this; instruction isnt of type foo (foo(3.14) instanceof foo is false).

While debugging in Chrome 35.0.1916.114 the type of this in the instruction return this; is foo but the type changes to window in this situation:

var x = foo(3.14); // x is typeof window

Once made the introduction, here es the questions:

  • Why the type of this is foo inside the constructor and window when captured outside?
    • Is because the new operator isn't used?
  • Is there a way to create JavaScript objects that behave like C++ RValues?

I'm a C++ programmer who recently landed on the JavaScript world; now I'm trying to apply some of the dessign patterns of C++ to JavaScript for the sake of my understanding and mental health.

AFAIK, the following codes are kind of equivalent in C++ and Javascript:

C++

// Class definition
template <typename T> class foo
{
public:
    // Constructor
    foo(T value) { this->value = value; }
    // Public function
    T twice() { return this->value + this->value; }

private:
    // Private function
    void bar() { }
    // Private member
    T value;
};

JavaScript

// "Class" definition and constructor
function foo(value)
{
    // "Private" member
    this.value = value;

    // "Private" function
    this.bar = function() { };
}

// Public function
foo.prototype.twice = function() { return this.value + this.value; };

The usage of both classes are similar too:

C++ live demo

foo<int> f1(1);
foo<std::string> f2("1");

std::cout << f1.twice() << '\n'; // output: 2
std::cout << f2.twice() << '\n'; // output: 11

JavaScript live demo

var f1 = new foo(1);
var f2 = new foo('1');

print(f1.twice()); // output: 2
print(f2.twice()); // output: 11

But there's a thing that cannot be done with a JavaScript class and is possible to do with a C++ class: the use of a temporary RValue to do a task:

C++

std::cout << foo<float>(3.14f).twice() << '\n'; // output: 6.28

JavaScript

print(foo(3.14).twice()); // Uncaught TypeError: undefined is not a function

I think that the error on the JavaScript version is due to the fact that foo is a function and it returns nothing (undefined), so at first I was thinking of change the constructor with the code below:

JavaScript

// "Class" definition and constructor
function foo(value)
{
    // "Private" member
    this.value = value;

    // "Private" function
    this.bar = function() { };

    return this; // <----- new code!
}

But this doesn't work at all; the object returned by the return this; instruction isnt of type foo (foo(3.14) instanceof foo is false).

While debugging in Chrome 35.0.1916.114 the type of this in the instruction return this; is foo but the type changes to window in this situation:

var x = foo(3.14); // x is typeof window

Once made the introduction, here es the questions:

  • Why the type of this is foo inside the constructor and window when captured outside?
    • Is because the new operator isn't used?
  • Is there a way to create JavaScript objects that behave like C++ RValues?
Share Improve this question edited Jun 4, 2014 at 16:29 MrCode 64.6k10 gold badges92 silver badges113 bronze badges asked Jun 4, 2014 at 10:48 PaperBirdMasterPaperBirdMaster 13.4k9 gold badges53 silver badges103 bronze badges 1
  • One of the best questions I've ever read :). +1 for live demos etc. – clambake Commented Jun 4, 2014 at 10:59
Add a ment  | 

1 Answer 1

Reset to default 6

In JavaScript, when you use the new keyword with a function, the function behaves differently to when called without the new keyword. With it, the function acts like a class, and a new object is instantiated from it, just like in traditional OOP languages. Additionally, the this context is set to itself and the return value of the function is disregarded.

By contrast, without the new keyword, the this context is set to the global scope, which for browsers is the window object, and the return value can be captured by whatever called it.

It is possible to create something like your C++ example, whereby you don't need the new keyword, and it still returns a new object.

Fiddle

function foo(value) {
    function foo(value) {
        this.value = value;

        this.bar = function () {};
        this.twice = function() { return this.value + this.value; }
    }

    return new foo(value);
}

console.log( foo(3.14).twice() ); // 6.28

Explanation:

the outer function foo behaves like a normal function, and is intended to be called without the new keyword. Inside lives the inner foo, which is intended to be like a class - called with the new keyword. The outer foo instantiates a new instance of the inner foo and returns it. Thus it can be used like the C++ example. It is not necessary to declare the class-like function within the outer function, it just depends if you want to encapsulate it within the outer.


Visibility

The two examples in the question are not exactly equivalent because the JavaScript example uses all public properties and methods, whereas the C++ example has bar and value as private.

Below is a version that is closer to the C++ version:

Fiddle

function foo(value) {
    function foo(value) {
        var value = value;

        function bar(){}
        this.twice = function() { return value + value; }
    }

    return new foo(value);
}

console.log( foo(3.14).twice() ); // 6.28 
console.log( foo(3.14).value ); // undefined because it's private
console.log( foo(3.14).bar() ); // undefined because it's private

As you can see from the test cases, value and bar are not publicly accessible/visible. This is achieved by not using the this prefix and declaring value using the var keyword (which defines a local variable). The function is declared as a declaration instead of an expression. In JavaScript, there is no formal way of declaring/differentiating public and private properties or methods like in OOP languages.

You may have noticed the above examples don't use prototype to declare any methods. The reason for this is that the prototype way would always declare methods with public visibility, and prototype methods cannot see any variables from inside the "class" or function. The code ments in the question suggest that using this.bar inside the function body makes it private, but that isn't the case.

发布评论

评论列表(0)

  1. 暂无评论