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

c++, class, javascript, oop

Solution

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 comments in the question suggest that using `this.bar` inside the function body makes it private, but that isn't the case.

Problem

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 comes 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?

Original source