Tôi đã thấy một vài câu trả lời tương tự, nhưng tôi muốn đề cập rằng bài đăng này mô tả nó tốt nhất, vì vậy tôi muốn chia sẻ nó với bạn.
Đây là một số mã được lấy từ nó, mà tôi đã sửa đổi để có được một ví dụ hoàn chỉnh, hy vọng sẽ mang lại lợi ích cho cộng đồng vì nó có thể được sử dụng làm mẫu thiết kế cho các lớp.
Nó cũng trả lời câu hỏi của bạn:
function Podcast() {
// private variables
var _somePrivateVariable = 123;
// object properties (read/write)
this.title = 'Astronomy Cast';
this.description = 'A fact-based journey through the galaxy.';
this.link = 'http://www.astronomycast.com';
// for read access to _somePrivateVariable via immutableProp
this.immutableProp = function() {
return _somePrivateVariable;
}
// object function
this.toString = function() {
return 'Title: ' + this.title;
}
};
// static property
Podcast.FILE_EXTENSION = 'mp3';
// static function
Podcast.download = function(podcast) {
console.log('Downloading ' + podcast + ' ...');
};
Cho ví dụ đó, bạn có thể truy cập các thuộc tính / hàm tĩnh như sau:
// access static properties/functions
console.log(Podcast.FILE_EXTENSION); // 'mp3'
Podcast.download('Astronomy cast'); // 'Downloading Astronomy cast ...'
Và các thuộc tính / hàm đối tượng đơn giản là:
// access object properties/functions
var podcast = new Podcast();
podcast.title = 'The Simpsons';
console.log(podcast.toString()); // Title: The Simpsons
console.log(podcast.immutableProp()); // 123
Lưu ý rằng trong podcast.immutableProp (), chúng tôi có một bao đóng : Tham chiếu đến _somePrivateVariable được giữ bên trong hàm.
Bạn thậm chí có thể định nghĩa getters và setters . Hãy xem đoạn mã này ( d
nguyên mẫu của đối tượng mà bạn muốn khai báo thuộc tính y
là biến riêng tư không hiển thị bên ngoài hàm tạo):
// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
get: function() {return this.getFullYear() },
set: function(y) { this.setFullYear(y) }
});
Nó xác định thuộc tính d.year
thông qua get
và các set
chức năng - nếu bạn không chỉ định set
, thì thuộc tính chỉ đọc và không thể sửa đổi (lưu ý rằng bạn sẽ không gặp lỗi nếu bạn cố gắng đặt nó, nhưng nó không có hiệu lực). Mỗi thuộc tính có các thuộc tính writable
, configurable
(cho phép thay đổi sau khi khai báo) và enumerable
(cho phép sử dụng nó làm điều tra viên), theo mặc định false
. Bạn có thể đặt chúng qua defineProperty
tham số thứ 3, vd enumerable: true
.
Điều gì cũng hợp lệ là cú pháp này:
// getters and setters - alternative syntax
var obj = { a: 7,
get b() {return this.a + 1;},
set c(x) {this.a = x / 2}
};
trong đó xác định thuộc tính có thể đọc / ghi được a
, thuộc tính chỉ đọc b
và thuộc tính chỉ ghi c
, thông qua thuộc tính đóa
có thể được truy cập.
Sử dụng:
console.log(obj.a); console.log(obj.b); // output: 7, 8
obj.c=40;
console.log(obj.a); console.log(obj.b); // output: 20, 21
Ghi chú:
Để tránh hành vi không mong muốn trong trường hợp bạn quên new
từ khóa, tôi khuyên bạn nên thêm các chức năng sau vào chức năng Podcast
:
// instantiation helper
function Podcast() {
if(false === (this instanceof Podcast)) {
return new Podcast();
}
// [... same as above ...]
};
Bây giờ cả hai cảnh báo sau sẽ hoạt động như mong đợi:
var podcast = new Podcast(); // normal usage, still allowed
var podcast = Podcast(); // you can omit the new keyword because of the helper
Câu lệnh 'mới' tạo ra một đối tượng mới và sao chép tất cả các thuộc tính và phương thức, tức là
var a=new Podcast();
var b=new Podcast();
a.title="a"; b.title="An "+b.title;
console.log(a.title); // "a"
console.log(b.title); // "An Astronomy Cast"
Cũng lưu ý rằng , trong một số trường hợp, có thể hữu ích khi sử dụng return
câu lệnh trong hàm Podcast
tạo để trả về một hàm bảo vệ đối tượng tùy chỉnh mà lớp bên trong dựa vào nhưng cần phải được phơi bày. Điều này được giải thích thêm trong chương 2 (Đối tượng) của loạt bài viết.
Bạn có thể nói điều đó a
và b
kế thừa từ Podcast
. Bây giờ, điều gì sẽ xảy ra nếu bạn muốn thêm một phương thức vào Podcast áp dụng cho tất cả chúng sau đó a
và b
đã được cung cấp? Trong trường hợp này, sử dụng .prototype
như sau:
Podcast.prototype.titleAndLink = function() {
return this.title + " [" + this.link + "]";
};
Bây giờ gọi a
và b
một lần nữa:
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
Bạn có thể tìm thêm chi tiết về nguyên mẫu ở đây . Nếu bạn muốn làm thừa kế nhiều hơn, tôi khuyên bạn nên xem xét điều này .
Các bài viết tôi đã đề cập ở trên rất khuyến khích để đọc, chúng cũng bao gồm các chủ đề sau:
- Chức năng
- Các đối tượng
- Nguyên mẫu
- Thực thi mới trên các hàm xây dựng
- Tời kéo
- Tự động chèn dấu chấm phẩy
- Thuộc tính và phương thức tĩnh
Lưu ý rằng chèn dấu chấm phẩy tự động "tính năng" của JavaScript (như được đề cập trong 6.) thường rất có trách nhiệm gây ra các vấn đề lạ trong mã của bạn. Do đó, tôi thà coi nó là một lỗi hơn là một tính năng.
Nếu bạn muốn đọc thêm, đây là một bài viết MSDN khá thú vị về các chủ đề này, một số trong số chúng được mô tả ở đó cung cấp nhiều chi tiết hơn nữa.
Điều thú vị để đọc là tốt (cũng bao gồm các chủ đề được đề cập ở trên) là những bài viết từ Hướng dẫn JavaScript MDN :
Nếu bạn muốn biết cách mô phỏng out
các tham số c # (như trong DateTime.TryParse(str, out result)
) trong JavaScript, bạn có thể tìm mã mẫu ở đây.
Những người bạn đang làm việc với IE (không có giao diện điều khiển cho JavaScript trừ khi bạn mở các công cụ dành cho nhà phát triển bằng cách sử dụng F12và mở tab bảng điều khiển) có thể thấy đoạn mã sau hữu ích. Nó cho phép bạn sử dụng console.log(msg);
như được sử dụng trong các ví dụ trên. Chỉ cần chèn nó trước Podcast
chức năng.
Để thuận tiện cho bạn, đây là đoạn mã trên trong một đoạn mã hoàn chỉnh:
let console = { log: function(msg) {
let canvas = document.getElementById("log"), br = canvas.innerHTML==="" ? "" : "<br/>";
canvas.innerHTML += (br + (msg || "").toString());
}};
console.log('For details, see the explaining text');
function Podcast() {
// with this, you can instantiate without new (see description in text)
if (false === (this instanceof Podcast)) {
return new Podcast();
}
// private variables
var _somePrivateVariable = 123;
// object properties
this.title = 'Astronomy Cast';
this.description = 'A fact-based journey through the galaxy.';
this.link = 'http://www.astronomycast.com';
this.immutableProp = function() {
return _somePrivateVariable;
}
// object function
this.toString = function() {
return 'Title: ' + this.title;
}
};
// static property
Podcast.FILE_EXTENSION = 'mp3';
// static function
Podcast.download = function(podcast) {
console.log('Downloading ' + podcast + ' ...');
};
// access static properties/functions
Podcast.FILE_EXTENSION; // 'mp3'
Podcast.download('Astronomy cast'); // 'Downloading Astronomy cast ...'
// access object properties/functions
var podcast = new Podcast();
podcast.title = 'The Simpsons';
console.log(podcast.toString()); // Title: The Simpsons
console.log(podcast.immutableProp()); // 123
// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
get: function() {
return this.getFullYear()
},
set: function(y) {
this.setFullYear(y)
}
});
// getters and setters - alternative syntax
var obj = {
a: 7,
get b() {
return this.a + 1;
},
set c(x) {
this.a = x / 2
}
};
// usage:
console.log(obj.a); console.log(obj.b); // output: 7, 8
obj.c=40;
console.log(obj.a); console.log(obj.b); // output: 20, 21
var a=new Podcast();
var b=new Podcast();
a.title="a"; b.title="An "+b.title;
console.log(a.title); // "a"
console.log(b.title); // "An Astronomy Cast"
Podcast.prototype.titleAndLink = function() {
return this.title + " [" + this.link + "]";
};
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
<div id="log"></div>
Ghi chú:
Một số mẹo hay, gợi ý và đề xuất hay về lập trình JavaScript nói chung bạn có thể tìm thấy ở đây (thực tiễn tốt nhất về JavaScript) và ở đó ('var' so với 'let') . Cũng đề nghị là bài viết này về các kiểu chữ ngầm (cưỡng chế) .
Một cách thuận tiện để sử dụng các lớp và biên dịch chúng thành JavaScript là TypeScript. Đây là một sân chơi nơi bạn có thể tìm thấy một số ví dụ cho bạn thấy nó hoạt động như thế nào. Ngay cả khi bạn hiện không sử dụng TypeScript, bạn vẫn có thể xem vì bạn có thể so sánh TypeScript với kết quả JavaScript trên chế độ xem song song. Hầu hết các ví dụ đều đơn giản, nhưng cũng có một ví dụ Raytracer mà bạn có thể thử ngay lập tức. Tôi đặc biệt khuyên bạn nên xem xét các ví dụ "Sử dụng lớp", "Sử dụng kế thừa" và "Sử dụng Generics" bằng cách chọn chúng trong hộp tổ hợp - đây là những mẫu đẹp bạn có thể sử dụng ngay trong JavaScript. Bản đánh máy được sử dụng với Angular.
Để đạt được đóng gói các biến cục bộ, hàm vv trong JavaScript, tôi khuyên bạn nên sử dụng một mẫu như sau (JQuery sử dụng cùng một kỹ thuật):
<html>
<head></head>
<body><script>
'use strict';
// module pattern (self invoked function)
const myModule = (function(context) {
// to allow replacement of the function, use 'var' otherwise keep 'const'
// put variables and function with local module scope here:
var print = function(str) {
if (str !== undefined) context.document.write(str);
context.document.write("<br/><br/>");
return;
}
// ... more variables ...
// main method
var _main = function(title) {
if (title !== undefined) print(title);
print("<b>last modified: </b>" + context.document.lastModified + "<br/>");
// ... more code ...
}
// public methods
return {
Main: _main
// ... more public methods, properties ...
};
})(this);
// use module
myModule.Main("<b>Module demo</b>");
</script></body>
</html>
Tất nhiên, bạn có thể - và nên - đặt mã tập lệnh vào một *.js
tệp riêng ; đây chỉ là nội tuyến để giữ cho ví dụ ngắn.
Các hàm tự gọi (còn được gọi là IIFE = Biểu thức hàm được gọi ngay lập tức) được mô tả chi tiết hơn ở đây .