有没有一种方法可以创建行为像c++ RValues的JavaScript对象?

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

本文关键字:c++ RValues 对象 JavaScript 创建 一种 方法 有没有      更新时间:2023-09-26

我是一名最近进入JavaScript世界的c++程序员;现在,为了我的理解和心理健康,我正在尝试将一些c++的设计模式应用到JavaScript中。

下面的代码在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实时演示

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),所以起初我想用下面的代码改变构造函数:

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中调试时,指令return this;中的this类型是foo,但在这种情况下类型更改为window:

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

一旦做了介绍,问题就来了:

  • 为什么this的类型是foo内部的构造器和window捕获外部时?
    • 是因为没有使用new操作符吗?
  • 是否有一种方法来创建行为像c++右值的JavaScript对象?

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

相比之下,没有new关键字,this上下文被设置为全局作用域,对于浏览器来说是window对象,返回值可以被调用它的任何东西捕获。

可以创建类似c++示例的东西,其中不需要new关键字,它仍然返回一个新对象。

小提琴

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++的版本:

小提琴

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前缀,并使用var关键字(它定义了一个局部变量)声明value来实现的。将函数声明为声明而不是表达式。在JavaScript中,没有像OOP语言那样的正式方式来声明/区分公共和私有属性或方法。

你可能已经注意到上面的例子没有使用prototype来声明任何方法。这样做的原因是原型方法总是声明具有公共可见性的方法,并且原型方法不能看到"类"或函数内部的任何变量。问题中的代码注释表明,在函数体内使用this.bar使其私有,但事实并非如此。