2010-09-16 52 views
6

Dường như có nhiều cách khác nhau để thực hiện OO trong JavaScript.Cú pháp OO Javascript

tôi thích:

function ClassA(){}; 
ClassA.prototype={ 
    someFunc:function(a,b,c){}, 
    otherFunc:function(){} 
} 
var c=new ClassA(); 

và chưa bao giờ sử dụng các tính năng xa hơn những gì này cung cấp (mặc dù là một OOer thành thạo). Tôi nghi ngờ đây là lỗi thời, bởi vì mỗi khi tôi thường thấy các biến thể mới vướng víu, và nó làm cho tôi tự hỏi nếu tôi chọn cách tiếp cận tốt nhất. Ví dụ, bạn có thể làm phép thuật trong phương thức khởi tạo để tạo các biến riêng và các phương thức truy cập, cái mà tôi tin (cho đến tương đối gần đây) là không thể. Điều gì về subclassing? Tôi sẽ không biết làm thế nào để đạt được điều này, nhưng nó phải có một số loại mô hình phổ biến của bây giờ.

Bạn làm như thế nào và tại sao?

Trả lời

6
function foo() { 
    var bar = function() { console.log("i'm a private method"); return 1; }; 
    var iAmAPrivateVariable = 1; 

    return { 
    publicMethod: function() { alert(iAmAPrivateVariable); }, 
    publicVariable: bar() 
    } 
} 

//usage 
var thing = foo() 

Đây được gọi là appoach chức năng, vì bạn thực sự tận dụng bao đóng gói để đóng gói (đây là cách duy nhất để thực hiện nó trong javascript).

Nói chung, bạn không nên làm OO trong javascript, nó không phải là một ngôn ngữ tuyệt vời cho nó vì nhiều lý do. Hãy suy nghĩ về lược đồ với các dấu ngoặc nhọn và dấu chấm phẩy, và bạn sẽ bắt đầu viết ngôn ngữ giống như các chuyên gia. Điều đó đang được nói, đôi khi OO phù hợp hơn. Trong những trường hợp, ở trên thường là đặt cược tốt nhất

EDIT: để mang lại thừa kế vào trộn

function parent() { 
    return { parentVariable: 2 }; 
} 

function foo() { 
    var bar = function() { console.log("i'm a private method"); return 1; }; 
    var iAmAPrivateVariable = 1; 

    me = parent(); 
    me.publicMethod = function() { alert(iAmAPrivateVariable); }; 
    me.publicVariable = bar(); 

    return me; 
} 

này làm cho mọi thứ một chút complected hơn, nhưng hoàn thành kết quả cuối cùng mong muốn trong khi vẫn tham gia một cách tiếp cận chức năng với các khái niệm OO (trong trường hợp này, sử dụng các hàm trang trí thay vì thừa kế thực). Những gì tôi thích về toàn bộ cách tiếp cận là chúng tôi vẫn đang thực sự xử lý các đối tượng theo cách mà chúng được dự định trong loại ngôn ngữ này - một túi tài sản mà bạn có thể đính kèm theo ý muốn.

EDIT2:

Chỉ muốn cung cấp tín dụng mà tín dụng là do, phương pháp này là đơn giản hơn rất nhẹ với những gì Doug Crockford gợi ý trong Javascript: The Good Parts. Nếu bạn muốn đưa kỹ năng js của bạn lên cấp độ tiếp theo, tôi sẽ khuyên bạn nên bắt đầu từ đó. Tôi không nghĩ rằng tôi đã học được rất nhiều từ một cuốn sách nhỏ như vậy.

Một lưu ý khác là cực kỳ khác biệt, bạn sẽ thấy phần lớn thời gian trong hầu hết các công việc bạn làm, và thường rất khó giải thích a) điều gì đang xảy ra và b) tại sao là một ý tưởng hay với đồng nghiệp.

+0

Tôi thích điều này rất nhiều. Nó có thể được uốn cong để cung cấp thừa kế mà không cần sử dụng nguyên mẫu? – spender

+0

'bar' sẽ trở thành thuộc tính của đối tượng chung (' window.bar'), vì nó không được khai báo với câu lệnh 'var' trong phạm vi của hàm' foo'. Cũng trong ECMAScript 5 Strict Mode, nó sẽ cung cấp cho bạn một 'ReferenceError', vì vậy luôn luôn sử dụng' var' để * khai báo * một biến;) – CMS

+1

@CMS wow ... đã gây khó chịu ... –

5

Simple JavaScript Inheritance

Bởi vì John Resig nói như vậy.

+1

Vâng, nhưng ông cũng phổ biến $ như một tên biến ... không thể tha thứ. – spender

+3

không phải khi $ được coi là một phần mở rộng ngôn ngữ –

2

"subclassing" trong JavaScript thường dùng để thừa kế dựa trên nguyên mẫu, mà cơ bản sau mô hình này:

function Superclass() { } 
Superclass.prototype.someFunc = function() { }; 

function Subclass() { } 
Subclass.prototype = new Superclass(); 
Subclass.prototype.anotherFunc = function() { }; 

var obj = new Subclass(); 

này xây dựng một "chuỗi nguyên mẫu" từ obj -> Subclass.prototype -> Superclass.prototype -> Object.prototype.

Khá nhiều thư viện OOP để JavaScript xây dựng dựa trên kỹ thuật này, cung cấp các hàm trừu tượng hầu hết nguyên mẫu "ma thuật".

+0

đây không phải là một ý tưởng hay; nó dựa vào việc gọi hàm tạo của cha mẹ để lấy nguyên mẫu cho hàm tạo con. Tốt hơn để làm một cái gì đó như thế này (xem phản ứng của tôi): 'function C() {}; function clone (obj) {C.prototype = obj, trả về C} mới; Subclass.prototype = clone (Superclass.prototype); '... theo cách đó, ctor cha không được gọi, có thể tạo ra các tác dụng phụ không mong muốn. –

1

Đối tượng trong JavaScript không giống như hầu như tất cả các ngôn ngữ cấu hình cao khác. Thay vì là dựa trên lớp (như trong Java, C++, PHP, v.v.), chúng là dựa trên nguyên mẫu. Như vậy, mô hình cơ bản của lập trình hướng đối tượng phải được sửa đổi đáng kể. Những người không thể hoặc không muốn nghĩ lại điều này và nhấn mạnh vào việc sử dụng tư duy dựa trên lớp học phải xây dựng logic dựa trên lớp học trong JavaScript hoặc sử dụng mã từ người khác đã xây dựng nó.

+0

hoàn toàn đồng ý.các lớp giả mạo trong JavaScript đang cố gắng trêu ghẹo java vào một cái gì đó mà chỉ tạo ra một sự tương đồng bề ngoài với nó. –

0

Tôi muốn làm một cái gì đó giống như

// namespace "My" 
var My = new function { 

    // private methods 
    /** 
    * Create a unique empty function. 
    * @return {Function} function(){} 
    */ 
    function createFn() {return function(){}} 

    /** A reusable empty function. */ 
    function emptyFn() {} 

    /** 
    * Clone an object 
    * @param {Object} obj  Object to clone 
    * @return {Object}   Cloned object 
    */ 
    function clone (obj) { emptyFn.prototype=obj; return new emptyFn() } 

    // public methods 
    /** 
    * Merge two objects 
    * @param {Object} dst  Destination object 
    * @param {Object} src  Source object 
    * @param {Object} [options] Optional settings 
    * @return {Object}   Destination object 
    */ 
    this.merge = function (dst, src, options) { 
    if (!options) options={}; 
    for (var p in src) if (src.hasOwnProperty(p)) { 
     var isDef=dst.hasOwnProperty(p); 
     if ((options.noPrivate && p.charAt(0)=='_') || 
      (options.soft && isDef) || 
      (options.update && !isDef)) continue; 
     dst[p]=src[p]; 
    } 
    return dst; 
    } 

    /** 
    * Extend a constructor with a subtype 
    * @param {Function} superCtor  Constructor of supertype 
    * @param {Function} subCtor  Constructor of subtype 
    * @param {Object} [options]  Optional settings 
    * @return {Function}    Constructor of subtype 
    */ 
    this.extend = function (superCtor, subCtor, options) { 
    if (!subCtor) subCtor=createFn(); 
    if (!options) options={}; 
    if (!options.noStatic) this.merge(subCtor, superCtor, options); 
    var oldProto=subCtor.prototype; 
    subCtor.prototype=clone(superCtor.prototype); 
    this.merge(subCtor.prototype, oldProto); 
    if (!options.noCtor) subCtor.prototype.constructor=subCtor; 
    return subCtor; 
    } 

} 

Và sau đó một cái gì đó giống như ...

// namespace "My.CoolApp" 
My.CoolApp = new function(){ 

    // My.CoolApp.ClassA 
    this.ClassA = new function(){ 

    // ClassA private static 
    var count=0; 

    // ClassA constructor 
    function ClassA (arg1) { 
     count++; 
     this.someParam=arg1; 
    } 

    // ClassA public static 
    My.merge(ClassA, { 
     create: function (arg1) { 
     return new ClassA(arg1); 
     } 
    } 

    // ClassA public 
    My.merge(ClassA.prototype, { 
     doStuff : function (arg1) { 
     alert('Doing stuff with ' + arg1); 
     }, 
     doOtherStuff : function (arg1) { 
     alert('Doing other stuff with ' + arg1); 
     } 
    } 

    return ClassA; 
    } 

    // My.CoolApp.ClassB 
    this.ClassB = new function(){ 

    My.extend(My.CoolApp.ClassA, ClassB); 
    // ClassB constructor 
    function ClassB() { 
     ClassA.apply(this, arguments); 
    } 

    return ClassB; 
    } 

} 

... các clone chức năng là chìa khóa để thừa kế. Trong ngắn hạn:

  • Sao chép một đối tượng bằng cách làm cho nó là nguyên mẫu của một chức năng ném và gọi hàm với 'mới'.
  • Sao chép nguyên mẫu của hàm tạo của cha mẹ và đặt kết quả làm nguyên mẫu của lớp con.
0

OOP trong Javascript cho Canvas

Kiểm tra ra cách hữu ích OOP trong js có thể trong một tình huống khác nhau ... Điều này cho phép bạn vẽ hình vuông và hình tròn as objects để bạn có thể quay trở lại và vòng qua hoặc thao tác chúng như bạn muốn.

function Shape(x,y,color){ 
    this.x = x 
    this.y = y 
    this.color = color 
} 

function Square(height,width,color){ 
    Shape.call(this, event.x, event.y, color) 
    this.height = height 
    this.width = width 
    this.x -= canvas.offsetLeft + (this.height/2) 
    this.y -= canvas.offsetTop + (this.width/2) 
} 

Square.prototype = new Shape(); 
Square.prototype.draw = function(color){ 
    ctx.fillStyle = color 
    ctx.fillRect(this.x,this.y,this.height,this.width) 
} 

function Circle(color, width){ 
    Shape.call(this) 
    this.x = event.x -60 
    this.y = event.y -60 
    this.width = width 
} 

Circle.prototype = new Shape(); 
Circle.prototype.draw = function(color){ 
    ctx.beginPath() 
    ctx.arc(this.x,this.y,this.width,0,2*Math.PI, false); 
    ctx.fillStyle = color 
    ctx.fill() 
} 
Các vấn đề liên quan