2009-01-14 44 views
39

Tôi đã sử dụng javascript một lúc, nhưng chưa bao giờ học ngôn ngữ qua các khái niệm cơ bản. Tôi đang đọc "Kỹ thuật Javascript Pro" của John Resig - Tôi đang đưa ra một số câu hỏi, nhưng tôi không tìm thấy câu trả lời cho họ trong sách hoặc trên google, v.v.Câu hỏi hướng đối tượng trong Javascript

John đưa ví dụ này vào sách của anh ấy :
Function # 1

function User(name, age){ 
    this.name = name; 
    this.age = age; 
} 
// Add a new function to the object prototype 
User.prototype.getName = function(){ 
    return this.name; 
}; 
User.prototype.getAge = function(){ 
    return this.age; 
}; 
var user = new User("Bob", 44); 
console.log("User: " + user.getName() + ", Age: " + user.getAge()); 

tôi vẫn đang tìm hiểu về nguyên mẫu tài sản, vì vậy tôi cố gắng viết một cái gì đó tương tự:
Function # 2

function User (name, age) { 
    this.name = name; 
    this.age = age; 
    this.getName = function() { 
    return this.name; 
    }; 
    this.getAge = function() { 
    return this.age; 
    }; 
} 
var user = new User("Bob", 44); 
console.log("User: " + user.getName() + ", Age: " + user.getAge()); 

Không sử dụng thuộc tính nguyên mẫu để tạo các hàm getName và getAge, nhưng đầu ra giống như ví dụ của John.

tôi mất nó thêm một bước nữa, và tạo này:
Function # 3

var User = { 
    name: "", 
    age: 0, 
    setName: function(name) { 
    this.name = name; 
    }, 
    setAge: function(age) { 
    this.age = age; 
    }, 
    getName: function() { 
    return this.name; 
    }, 
    getAge: function() { 
    return this.age; 
    } 
}; 
User.setName("Bob"); 
User.setAge(44); 
console.log("User: " + User.getName() + ", Age: " + User.getAge()); 

Một lần nữa - có vẻ khác với ví dụ của John (và tôi đã phải thêm các phương pháp setter), nhưng sản lượng là giống nhau.

Câu hỏi # 1 - sự khác nhau giữa 3 chức năng là gì? Lợi thế của thuộc tính prototype là gì, và Function # 2 làm bất cứ điều gì không chính xác, vì nó có vẻ thẳng hơn về mã # 2 thay vì # 1 (mặc dù tôi chắc chắn # 1 đang làm tốt hơn khi thấy John tạo ra nó) .

Câu hỏi # 2 - Làm cách nào tôi có thể sửa đổi hàm # 3 để không sử dụng các phương thức setName và setAge, nhưng vẫn giữ ký hiệu {...}? Có thể {...} viết tắt có nhà thầu?

Cảm ơn bạn đã giúp tôi học!

EDIT Tôi nghĩ câu hỏi thứ 2 của tôi hơi khó hiểu. Tôi có nghĩa là làm thế nào tôi có thể sử dụng {...} các kí hiệu để tạo ra một đối tượng dùng, nhưng sau đó sau khi tôi tạo ra các đối tượng, nói điều gì đó như:

var user = new User("Bob", 44); 

Cũng giống như trong Function # 1 - hoặc là không thể ?

EDIT # 2 Wow! Cảm ơn tất cả mọi người vì những câu trả lời tuyệt vời. Điều đó thực sự làm cho nó rõ ràng hơn rất nhiều với tôi. Vì vậy, nếu tôi hiểu chính xác, sự khác biệt giữa # 1 và # 2 không quá nhiều. Nếu tôi chỉ tạo ra một đối tượng "Người dùng" - chúng có thể không khác gì cả. Nhưng nếu chương trình của tôi tạo ra nhiều đối tượng User, thì # 1 rất có thể sẽ hiệu quả hơn và sử dụng ít bộ nhớ hơn vì tất cả các đối tượng sẽ chia sẻ cùng một chức năng.

Tôi thực sự đánh giá cao tất cả các câu trả lời tuyệt vời - Cảm ơn!

Trả lời

22

Mỗi lần hàm() {} được đánh giá, nó tạo ra một đối tượng hàm mới. Vì vậy, trong # 1 tất cả các đối tượng User đang chia sẻ cùng một hàm getName và getAge, nhưng trong # 2 và # 3, mỗi đối tượng có một bản sao riêng của getName và getAge.Tất cả các hàm getName khác nhau đều hoạt động giống nhau, vì vậy bạn không thể thấy bất kỳ sự khác biệt nào trong đầu ra.

Ký hiệu {...} một hàm tạo. Khi được đánh giá, nó xây dựng một "đối tượng" mới với các thuộc tính đã cho. Khi bạn chạy "Người dùng mới (...)", nó sẽ tạo một "Người dùng" mới. Bạn tình cờ đã tạo ra một đối tượng có hành vi tương tự như một người dùng, nhưng chúng có nhiều loại khác nhau.

Trả lời nhận xét:

Bạn không thể trực tiếp. Bạn có thể tạo một hàm tạo đối tượng mới theo # 3. Ví dụ:

function make_user(name, age) { 
    return { 
     name: name, 
     age: age, 
     getName: function() { return name; }, 
     getAge: function() { return age; }, 
    }; 
} 

var user = make_user("Joe", "18"); 
+0

Tôi đoán tôi có nghĩa là câu hỏi # 2 là làm thế nào tôi có thể sửa đổi chức năng # 3 để tôi có thể nói điều gì đó như var person = new User(); – BrianH

+0

Nhận xét này không hoàn toàn đúng 'Tất cả các hàm getName khác nhau đều hoạt động giống hệt nhau'. Loại # 2 có quyền truy cập vào các vars riêng – meouw

+0

Quan điểm của tôi là chúng hoạt động giống nhau trong ví dụ. – Glomek

5

2:

Bạn có thể truy cập vào tên và tuổi tác, mà không sử dụng chức năng này. Trong javascript, bạn phải sử dụng các hacks khác nhau để giữ một cái gì đó riêng tư hoặc được bảo vệ.

này

User.name = "BoB"; 
User.age = 44; 

sẽ sản xuất cùng một đầu ra như ví dụ của bạn.

Không có nhà thầu nào xuất hiện ở các ngôn ngữ khác. Cách dễ nhất là chỉ định nghĩa hàm init() và gọi nó ngay sau khi bạn thể hiện đối tượng.

Nhưng mẹo lớn nhất của tôi dành cho bạn là xem xét http://www.prototypejs.org/. Đó là một thư viện javascript với rất nhiều tính năng thú vị mà cố gắng để làm cho javascript "hơn OO *".

Sử dụng thư viện mẫu, bạn có thể làm cho các lớp hoạt động giống như các lớp OOP thực. Nó cũng có các hàm tạo.

Edit: Đối với những gì bạn yêu cầu trong bình luận của bạn:

person = new User(); 
person.name = "Bob"; 
person.age = 44; 
1

Câu hỏi # 1

prototype có lợi ích của monkey patching. Như ví dụ đầu tiên cho thấy, chức năng được thêm vào sau khi thực tế. Bạn có thể tiếp tục điều này để thêm hoặc thay thế bất kỳ phương thức nào bạn cần (mặc dù, với cảnh báo công bằng).

Xác định các đối tượng như # 2 là nhiều hơn dọc theo dòng OOP cổ điển. Nhưng, sau đó một lần nữa, vá khỉ không được phép trong tất cả các ngôn ngữ OOP.

Câu hỏi # 2

Trong chức năng thứ 3 của bạn, bạn thậm chí không cần các chức năng getset-nameage là tài sản công cộng (nhược điểm tiềm năng để {}).

var User = { 
    name: "", 
    age: 0 
}; 

User.name = 'Bob'; 
User.age = 44; 

console.log("User: " + User.name + ", Age: " + User.age); 

Khi bạn tạo một đối tượng sử dụng {} (một đối tượng theo nghĩa đen), {} là các nhà xây dựng (khác nhau trên trình duyệt). Nhưng, về cơ bản, không có bạn không thể sử dụng một constructor trong định dạng này.

+0

Việc thêm thuộc tính hoặc phương thức vào đối tượng do người dùng xác định không đủ điều kiện làm bản vá lỗi của khỉ. Khỉ vá là thêm phương pháp hoặc tài sản cho các đối tượng được xây dựng trong đó tức là thay đổi hành vi của chính ngôn ngữ đó. – meouw

4

Ví dụ số 1 của bạn cho biết cách sử dụng thuộc tính mẫu thử.Thuộc tính này có sẵn cho tất cả các đối tượng javascript bạn tạo và cho phép bạn thêm các thuộc tính hoặc hàm vào khai báo đối tượng, vì vậy bạn có một đối tượng có 2 thuộc tính và sau đó bạn thêm 4 hàm (getters và setters).

Bạn sẽ thấy thuộc tính prototype như là cách để thay đổi đặc điểm kỹ thuật đối tượng của bạn trong thời gian chạy, nói rằng bạn có một đối tượng gọi tên:

var Name = { 
    First: "", 
    Last: "" 
}; 

Bạn có thể sử dụng linh kiện này để thêm một chức năng getFullName() sau này chỉ đơn giản là:

Name.prototype.getFullName = function() { return this.First + " " + this.Last; } 

Trong ví dụ 2 bạn điền vào khai báo các getters và setters này trong khai báo đối tượng để cuối cùng chúng giống nhau. Cuối cùng, trên ví dụ thứ 3, bạn sử dụng ký hiệu đối tượng JavaScript, bạn sẽ thấy JSON.

Về câu hỏi của bạn 2 bạn chỉ có thể tuyên bố đối tượng của bạn như:

var User = { 
    name: "", 
    age: 0 
}; 

này sẽ cung cấp cho bạn cùng một đối tượng mà không getter và setter.

12

Nếu bạn muốn thực hiện OOP trong JavaScript, tôi khuyên bạn nên xem xét đóng cửa. Tôi bắt đầu học tập của tôi về chủ đề với các trang ba web:

http://www.dustindiaz.com/javascript-private-public-privileged/

http://www.dustindiaz.com/namespace-your-javascript/

http://blog.morrisjohns.com/javascript_closures_for_dummies

Sự khác biệt giữa 1, 2, và 3 như sau: 1) là một ví dụ về việc thêm các phương thức mới vào một đối tượng hiện có. 2) Giống như # 1, ngoại trừ một số phương pháp được bao gồm trong đối tượng trong chức năng Người dùng. 3) Là một ví dụ về việc xác định một đối tượng sử dụng JSON. Thiếu sót là bạn không thể sử dụng mới (ít nhất là không có ví dụ đó) để xác định các cá thể mới của đối tượng đó. Tuy nhiên, bạn có được lợi ích của kiểu mã JSON thuận tiện.

Bạn chắc chắn nên đọc trên JSON nếu bạn chưa biết. JavaScript sẽ có ý nghĩa hơn khi bạn hiểu JSON.

chỉnh sửa Nếu bạn muốn sử dụng mới trong chức năng # 3 bạn có thể viết nó như

function User() { 
    return { 
    name: "", 
    age: 0, 
    setName: function(name) { 
     this.name = name; 
    }, 
    setAge: function(age) { 
     this.age = age; 
    }, 
    getName: function() { 
     return this.name; 
    }, 
    getAge: function() { 
     return this.age; 
    } 
    }; 
} 

Tất nhiên tất cả những chức năng và đặc tính sau đó sẽ được công khai. Để đặt chúng ở chế độ riêng tư, bạn cần sử dụng các bao đóng. Ví dụ: bạn có thể đặt tuổi và tên riêng tư với cú pháp này.

function User() { 
    var age=0; 
    var name=""; 
    return { 
    setName: function(name_) { 
     name = name_; 
    }, 
    setAge: function(age_) { 
     age = age_; 
    }, 
    getName: function() { 
     return name; 
    }, 
    getAge: function() { 
     return age; 
    } 
    }; 
} 
+1

Cảm ơn vì điều đó ... hy vọng bạn vẫn ở xung quanh và trả lời nội dung trên SO :) –

Các vấn đề liên quan