2011-10-21 43 views
5

Khi tôi chạy mã này:thừa kế JavaScript diệu

function foo() { 
    console.log("foo"); 
    var self = this; 
    this.a = function() { 
     return arguments.length == 0 ? self.b : (self.b = arguments[0]); 
    }; 
}; 
function bar() { 
}; 
bar.prototype = new foo(); 
var a = new bar(); 
var b = new bar(); 
console.log(a.a()); 
b.a(true); 
console.log(a.a()); 

tôi nhận được kết quả như sau: foo, undefined, true

Những gì tôi không hiểu là như thế nào đối tượng được trả về bởi hàm xây dựng foo bằng cách nào đó quản lý để phân bổ một vị trí bộ nhớ mới cho b. Tôi đã hoàn toàn mong đợi sản lượng cuối cùng là true vì tôi chỉ nhận được 1 đầu ra foo.

Đó là công trình tuyệt vời, nhưng nó cảm thấy quá nhiều như ma thuật.

Vấn đề của tôi thực sự ở đây là tôi muốn thiết lập thứ tự khởi tạo (hoặc chuỗi). Những gì tôi đã nhận ra là foo không thể lấy bất kỳ đối số nào, bởi vì nó chỉ được gọi một lần, để cung cấp một cơ sở (hoặc mẫu các loại).

Tôi muốn đưa ra một sơ đồ thực sự đơn giản mà foo có thông số mà đã được thông qua bar-foo (vì bar thừa hưởng foo). Tôi tốt với một cái gì đó như gọi foo.apply(this, arguments) từ bar nhưng các cuộc gọi để thiết lập các mẫu thử nghiệm đã được thực hiện mà không có đối số, những gì tôi cần là một cách thông thạo để bằng cách nào đó nói với nhau hai.

Nhưng tôi thực sự không muốn để xây dựng toàn bộ một dịch vụ xung quanh tạo các đối tượng cho phép một số loại thừa kế, điều duy nhất tôi thực sự quan tâm là xây dựng các đối tượng, đúng ...

+1

Tôi đã đăng nhập 'foo, undefined, true'. "Không xác định" cuối cùng không hiển thị trong Công cụ dành cho nhà phát triển Chrome nhưng đó chỉ là giá trị trả lại của 'console.log'. Bạn chỉ có 3 nhật ký. – pimvdb

+0

Vâng, đúng vậy, tôi vừa sao chép từ đầu ra từ bảng điều khiển Chrome, bỏ qua ... –

+0

Câu hỏi chính xác là gì? – user123444555621

Trả lời

3

Lưu ý phụ, đôi khi bạn sử dụng self và đôi khi sử dụng this ... cá nhân, tôi sẽ nhất quán hơn. Tôi thích sử dụng thatthis can be confusingself is part of the BOM, nhưng đó chỉ là vấn đề về hương vị.

Hãy thử parasitic inheritance:

function foo(arg) { 
    var that = this; 
    that.a = function() { 
     return arguments.length == 0 ? that.b : (that.b = arguments[0]); 
    }; 
} 

function bar(arg) { 
    return new foo(arg); 
} 

bar.prototype = new foo(); 
var a = new bar(); // the `new` is now optional. Personally I'd remove it... 
var b = bar(); // ... like I did here! 
console.log(a.a()); 
b.a(true); 
console.log(a.a()); 
console.log(b.a()); 

... ở đây các thừa kế cư xử trong một cổ điển hơn, gọi một cách rõ ràng một constructor mẹ khi constructor được gọi.

+2

Tôi ghét "đó", nó bao hàm một cái gì đó khác với điều này. Tôi thích "cá thể" –

+0

@George Jempty - Đủ công bằng. Tôi nghĩ phần quan trọng là nhất quán; không sử dụng 'this' và sau đó' self' chẳng hạn. –

+0

Tôi đồng ý về tính nhất quán. Và tôi biết Crockford sử dụng "đó" vì vậy tôi là một chút ra trên một chi. –

0

Vâng, đây là một trong những điểm yếu (của các điểm mạnh) của JS. Bạn đang gặp sự cố mẫu ở đây. Tôi khuyên bạn nên xem http://ejohn.org/blog/simple-javascript-inheritance/ - có một 'lớp' miễn phí mà bạn có thể sử dụng để giúp làm thẳng lên những gì người ta mong đợi với một thừa kế 'cổ điển' hơn. Cũng giống như một ví dụ nhanh, hầu hết các mẫu mà tôi đã nhìn thấy có một 'đối tượng' cơ bản (ít nhiều là một lớp tùy chỉnh) và hàm tạo (ít nhiều là 'cách đối tượng được xây dựng') gọi như thế nào một cái gì đó như "this.init.apply (this, arguments)". Điều đó gọi phương thức 'init' trên đối tượng với tất cả các đối số đã được thông qua. Vì vậy, init có thể được thiết lập, mở rộng, thiết lập lại, vv, và constructor luôn gọi một cái là 'cục bộ' với chính nó với các đối số đã được thông qua. Khá gọn gàng.

Hy vọng điều đó sẽ giúp ích hoặc ít nhất không gây nhầm lẫn.

0

Đầu ra cuối cùng true. Bạn đang bị lừa bởi bảng điều khiển JavaScript của mình. Giá trị trả về cuối cùng từ biểu thức của bạn là undefined.Hãy console.log() cuộc gọi của bạn mô tả nhiều hơn để tỏa sáng một ánh sáng vào những gì đang xảy ra:

function foo() { 
    console.log("foo constructor called"); 
    var self = this; 
    this.a = function() { 
     return arguments.length == 0 ? self.b : (self.b = arguments[0]); 
    }; 
} 
function bar() { 
} 
bar.prototype = new foo(); 
var a = new bar(); 
var b = new bar(); 
console.log("value from a.a(): " + a.a()); 
b.a(true); 
console.log("value from a.a(): " + a.a()); 
console.log("done logging"); 

Điều này mang lại kết quả như sau trong bảng điều khiển

foo constructor called 
value from a.a(): undefined 
value from a.a(): true 
done logging 
undefined 
0

Nó không kỳ diệu, đó là nguyên chủng thừa kế. Tôi nghĩ rằng những gì bạn đang cố gắng đạt được là kết hợp hai hàm xây dựng để được gọi là automagically. Có lẽ bạn đang trộn lẫn các nhà xây dựng và nguyên mẫu.

Nhưng tôi thực sự không muốn để xây dựng toàn bộ một dịch vụ xung quanh tạo đối tượng cho phép một số loại thừa kế, điều duy nhất tôi thực sự chăm sóc về đang xây dựng các đối tượng, đúng ...

Tôi không biết ý bạn là gì bởi "dịch vụ". Nhưng như trong bất kỳ ngôn ngữ lập trình hướng đối tượng nào khác, các cuộc gọi phương thức siêu lớp cần được thực hiện thủ công. Vì vậy, hoặc bạn mã hóa cứng "siêu lớp" như sau:

function foo() { 
    console.log("foo"); 
    var self = this; 
    this.a = function() { 
     return arguments.length == 0 ? self.b : (self.b = arguments[0]); 
    }; 
} 
function bar() { 
    foo.apply(this, arguments); // <- ugly 
} 
//bar.prototype = new foo(); // this is not neccessary 

... hoặc bạn xây dựng một số công cụ bao bọc để kết nối "lớp học" của bạn. Một cái gì đó như:

function inherit(superconstructor) { 
    return function() { 
     superconstructor.apply(this, arguments); 
    }; 
} 
function foo() {...} 
bar = inherit(foo); 
Các vấn đề liên quan