2015-11-19 19 views
12

Tôi muốn dọn dẹp dự án của mình một chút và bây giờ tôi cố gắng sử dụng các lớp học es6 cho các tuyến đường của mình. Vấn đề của tôi là này luôn không xác định.Nodejs, các tuyến đường tốc hành như các lớp es6

var express = require('express'); 
var app = express(); 

class Routes { 
    constructor(){ 
     this.foo = 10 
    } 

    Root(req, res, next){ 
     res.json({foo: this.foo}); // TypeError: Cannot read property 'foo' of undefined 
    } 
} 

var routes = new Routes(); 
app.get('/', routes.Root); 
app.listen(8080); 

Trả lời

10

cố gắng sử dụng mã để ghim this:

app.get('/', routes.Root.bind(routes)); 

Bạn có thể thoát khỏi bản mẫu sử dụng nhấn bindAll chức năng. Ví dụ:

var _ = require('underscore'); 

// .. 

var routes = new Routes(); 
_.bindAll(routes) 
app.get('/', routes.Root); 

Tôi cũng thấy rằng ES7 cho phép bạn viết mã một cách tao nhã hơn:

class Routes { 
    constructor(){ 
     this.foo = 10 
    } 

    Root = (req, res, next) => { 
     res.json({foo: this.foo}); 
    } 
} 

var routes = new Routes(); 
app.get('/', routes.Root); 
+1

cho đến khi ES7 được ở đây - Tôi yêu _.bindAll tôi đã hoàn toàn không biết gì về nó. Nó đẹp hơn nhiều so với việc gắn kết người dùng với chính nó trong mọi tuyến đường! –

5

này đang xảy ra bởi vì bạn đã vượt qua một phương pháp như một chức năng độc lập để bày tỏ . Express không biết bất cứ điều gì về lớp mà nó đến từ, do đó nó không biết giá trị nào sử dụng là this khi phương thức của bạn được gọi.

Bạn có thể buộc giá trị this bằng bind.

app.get('/', routes.Root.bind(routes)); 

Hoặc bạn có thể sử dụng cấu trúc thay thế để quản lý tuyến đường. Bạn vẫn có thể sử dụng rất nhiều lợi ích cú pháp cho lập trình hướng đối tượng mà không cần lớp.

function Routes() { 
    const foo = 10; 

    return { 
    Root(req, res, next) { 
     res.json({ foo }); 
    } 
    }; 
} 

const routes = Routes(); 
app.get('/', routes.Root); 
app.listen(8080); 
  • Bạn sẽ không phải lo lắng về giá trị của this
  • Nó không quan trọng cho dù hàm được gọi với new hay không
  • Bạn có thể tránh sự phức tạp của gọi bind trên mỗi tuyến đường

Có danh sách tốt các tài nguyên here, về lý do tại sao các lớp ES6 không tốt như chúng có vẻ.

2

Các câu trả lời ở trên có vẻ phức tạp hơn một chút. Thanh toán những gì tôi đã làm ở đây:

class Routes { 
    constructor(req, res, next) { 
    this.req = req; 
    this.res = res; 
    this.next = next; 
    this.foo = "BAR" 
    // Add more data to this. here if you like 
    } 

    findAll(){ 
    const {data, res,} = this; // Or just reference the objects directly with 'this' 
    // Call functions, do whaterver here... 
    // Once you have the right data you can use the res obejct to pass it back down 

    res.json ({foo: this.foo}); // Grabs the foo value from the constructor 

    } 
} 

Bây giờ khi nói đến sử dụng lớp này bạn có thể làm một cái gì đó dọc theo dòng này:

var express = require('express'); 
var router = express.Router(); 
var {Routes} = require('./Routes'); 

router.get('/foo', (req, res, next) => { 
    new Routes(req, res, next).findAll(); 
}); 

tôi sẽ tách hai tập tin, do đó bạn chỉ cần yêu cầu lớp Routes vào tệp Router của bạn.

Hy vọng điều này giúp!

+0

Điều này có vẻ phức tạp hơn nhiều so với câu trả lời được chấp nhận. Điều này đòi hỏi bạn phải có các thành viên riêng của lớp của bạn để req, res, và next(). Các thành viên lớp này thực sự chỉ là các hàm trung gian mà chỉ cần cung cấp chữ ký giống như loại middleware Express mong muốn. Sử dụng phương thức '.bind' là giải pháp tốt nhất cho việc xem xét thiết kế này. Như một lưu ý, tôi đang làm điều này trong TypeScript & dường như được làm việc ra tuyệt vời. –

1

Hoặc nếu bạn không thích ràng buộc ngữ cảnh trên mỗi tuyến đường, bạn có thể tùy chọn liên kết nó với các phương thức trong bản dựng của lớp của bạn.

ví dụ:

constructor() { 
    this.foo = 10; 
    this.Root = this.Root.bind(this); 
} 
Các vấn đề liên quan