有没有办法创建行为类似于C ++ RValues的JavaScript对象?

时间:2014-06-04 10:48:48

标签: javascript c++ class oop

我是一位最近登陆JavaScript世界的C ++程序员;现在我为了理解和心理健康,试图将一些C ++的dessign模式应用到JavaScript中。

AFAIK,以下代码在C ++和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; };

两个类的用法也相似:

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

但是有一个用JavaScript类无法完成的事情并且可以用C ++类做:使用临时RValue来完成任务:

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

我认为JavaScript版本的错误是由于foo是一个函数并且它什么也没有返回(undefined),所以起初我想用下面的代码更改构造函数:< / p>

的JavaScript

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

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

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

但这根本不起作用; return this;指令返回的对象不属于foo类型(foo(3.14) instanceof foofalse)。

在Chrome 35.0.1916.114中进行调试时,this指令中return this;的类型为foo,但在这种情况下类型更改为window

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

一旦做了介绍,问题就出现了:

  • 为什么this的类型在构造函数中是foo而在外部捕获时是window
    • 是因为new运算符未被使用?
  • 有没有办法创建行为类似于C ++ RValues的JavaScript对象?

1 个答案:

答案 0 :(得分:6)

在JavaScript中,当您将new关键字与函数一起使用时,该函数的行为与不使用new关键字时调用的行为不同。有了它,该函数就像一个类,并且从它实例化一个新对象,就像在传统的OOP语言中一样。此外,this上下文设置为自身,并忽略该函数的返回值。

相比之下,如果没有new关键字,this上下文将设置为全局范围,对于浏览器而言是window对象,并且返回值可以通过任何内容捕获叫它。

可以创建类似于C ++示例的内容,因为您不需要new关键字,它仍会返回一个新对象。

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

说明:

外部函数foo的行为类似于普通函数,并且打算在没有new关键字的情况下调用它。内部生活内部foo,其意图类似于一个类 - 使用new关键字调用。外部foo实例化内部foo的新实例并返回它。因此它可以像C ++示例一样使用。没有必要在外部函数中声明类类函数,它只取决于你是否要将它封装在外部函数中。


可见性

问题中的两个示例并不完全等效,因为JavaScript示例使用所有公共属性和方法,而C ++示例将barvalue作为私有。

以下版本更接近C ++版本:

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

从测试用例中可以看出,valuebar无法公开访问/可见。这是通过不使用this前缀并使用value关键字(定义局部变量)声明var来实现的。该函数声明为声明而不是表达式。在JavaScript中,没有正式的方法来声明/区分OOP语言中的公共和私有属性或方法。

您可能已经注意到上述示例并未使用原型来声明任何方法。这样做的原因是原型方法总是声明具有公共可见性的方法,而原型方法无法从&#34;类&#34;中看到任何变量。或功能。问题中的代码注释表明在函数体内使用this.bar会使其成为私有,但事实并非如此。