Helpex - Trao đổi & giúp đỡ Đăng nhập
20

Tôi là một lập trình viên C ++ gần đây đã đặt chân vào thế giới JavaScript; bây giờ tôi đang cố gắng áp dụng một số mẫu thiết kế của C ++ vào JavaScript vì lợi ích của sự hiểu biết và sức khỏe tinh thần của tôi.

AFAIK, các mã sau thuộc loại tương đương trong C ++ và 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ách sử dụng của cả hai lớp cũng giống nhau:

Bản trình diễn trực tiếp C ++

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

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

Bản demo trực tiếp JavaScript

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

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

Nhưng có một điều không thể làm được với lớp JavaScript và có thể làm được với lớp C ++: việc sử dụng RValue tạm thời để thực hiện một tác vụ:

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

Tôi nghĩ rằng lỗi trên phiên bản JavaScript là do foo là một hàm và nó không trả về gì ( undefined), vì vậy lúc đầu tôi đã nghĩ đến việc thay đổi hàm tạo bằng đoạn mã dưới đây:

JavaScript

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

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

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

Nhưng điều này không hiệu quả chút nào; đối tượng được trả về bởi return this;lệnh không thuộc kiểu foo( foo(3.14) instanceof foofalse).

Trong khi gỡ lỗi trong Chrome 35.0.1916.114, loại thistrong hướng dẫn return this;foonhưng loại thay đổi thành windowtrong tình huống này:

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

Sau khi giới thiệu, đây là các câu hỏi:

  • Tại sao kiểu của thisfoobên trong hàm tạo và windowkhi được bắt bên ngoài?
    • Có phải vì newnhà điều hành không được sử dụng?
  • Có cách nào để tạo các đối tượng JavaScript hoạt động giống như C ++ RValues ​​không?
20 hữu ích 1 bình luận 2.4k xem chia sẻ
6

Trong JavaScript, khi bạn sử dụng newtừ khóa với một hàm, hàm sẽ hoạt động khác với khi được gọi mà không có newtừ khóa. Với nó, hàm hoạt động giống như một lớp và một đối tượng mới được khởi tạo từ nó, giống như trong các ngôn ngữ OOP truyền thống. Ngoài ra, thisngữ cảnh được đặt thành chính nó và giá trị trả về của hàm bị bỏ qua.

Ngược lại, không có newtừ khóa, thisngữ cảnh được đặt thành phạm vi toàn cục, đối với các trình duyệt là windowđối tượng và giá trị trả về có thể được thu nhận bởi bất kỳ thứ gì được gọi là nó.

Có thể tạo một cái gì đó giống như ví dụ C ++ của bạn, theo đó bạn không cần newtừ khóa và nó vẫn trả về một đối tượng mới.

Vĩ cầm

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

Giải trình:

hàm bên ngoài hoạt foođộng giống như một hàm bình thường và được dùng để gọi mà không có newtừ khóa. Bên trong sống bên trong foo, được dự định giống như một lớp - được gọi với newtừ khóa. Bên ngoài fookhởi tạo một thể hiện mới của bên trong foovà trả về nó. Vì vậy, nó có thể được sử dụng giống như ví dụ C ++. Không nhất thiết phải khai báo hàm giống lớp bên trong hàm bên ngoài, nó chỉ phụ thuộc nếu bạn muốn đóng gói nó bên trong hàm bên ngoài.


Hiển thị

Hai ví dụ trong câu hỏi không hoàn toàn tương đương vì ví dụ JavaScript sử dụng tất cả các thuộc tính và phương thức công khai, trong khi ví dụ C ++ có barvà ở valuedạng riêng tư.

Dưới đây là phiên bản gần với phiên bản C ++ hơn:

Vĩ cầm

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

Như bạn có thể thấy từ các trường hợp thử nghiệm, valuebarkhông thể truy cập / hiển thị công khai. Điều này đạt được bằng cách không sử dụng thistiền tố và khai báo valuebằng vartừ khóa (định nghĩa một biến cục bộ). Hàm được khai báo dưới dạng một khai báo thay vì một biểu thức. Trong JavaScript, không có cách chính thức nào để khai báo / phân biệt các thuộc tính hoặc phương thức public và private như trong các ngôn ngữ OOP.

Bạn có thể nhận thấy các ví dụ trên không sử dụng nguyên mẫu để khai báo bất kỳ phương thức nào. Lý do cho điều này là cách nguyên mẫu sẽ luôn khai báo các phương thức với khả năng hiển thị công khai và các phương thức nguyên mẫu không thể nhìn thấy bất kỳ biến nào từ bên trong "lớp" hoặc hàm. Các chú thích mã trong câu hỏi gợi ý rằng việc sử dụng this.barbên trong thân hàm khiến nó trở nên riêng tư, nhưng không phải vậy.

6 hữu ích 2 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ javascript c++ class oop , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading