Các tính năng ẩn của JavaScript? [đóng cửa]


312

"Tính năng ẩn" nào của JavaScript mà bạn nghĩ mọi lập trình viên nên biết?

Sau khi thấy chất lượng tuyệt vời của các câu trả lời cho các câu hỏi sau đây, tôi nghĩ rằng đã đến lúc hỏi nó về JavaScript.

Mặc dù JavaScript được cho là ngôn ngữ phía khách hàng quan trọng nhất hiện nay (chỉ cần hỏi Google), thật đáng ngạc nhiên khi hầu hết các nhà phát triển web đánh giá cao mức độ thực sự của nó.


1
Không phải bạn muốn nói "Đã thấy các điểm đại diện và xem câu hỏi khác này bị thu hút, tôi nghĩ tôi đã hỏi gần như chính xác cùng một câu hỏi để thúc đẩy câu hỏi của mình"? ;-)
Bobby Jack

1
Chắc chắn, bi quan. :) Tôi đã xem xét làm cho điều này một câu hỏi cộng đồng. Ngoài ra, sau khi bạn nhận được một số điểm nhất định, tất cả lợi nhuận sẽ giảm dần.
Allain Lalonde

1
Đủ công bằng - nó không giống như bạn 'cần' đại diện! Tôi đoán tôi chỉ gặp vấn đề lớn với C # one - dường như không chính xác đối với tôi giống như loại câu hỏi mà trang web này được dự định.
Bobby Jack

3
Vâng, có thể không, nhưng tôi tìm thấy kiến ​​thức trong các câu trả lời tuyệt vời. Tôi nghĩ rằng bạn sẽ khó có thể đưa một lập trình viên C # trung bình đến tất cả ở một nơi nếu không phải vì SO. Phải mất nhiều năm chơi với nó để đưa ra danh sách chiến thắng khó khăn tương tự.
Allain Lalonde

7
Tôi đã viết JavaScript chuyên nghiệp được 10 năm và tôi đã học được một hoặc ba điều từ chủ đề này. Cảm ơn, Alan!
Andrew Hedges

Câu trả lời:


373

Bạn không cần xác định bất kỳ tham số nào cho hàm. Bạn chỉ có thể sử dụng argumentsđối tượng giống như mảng của hàm .

function sum() {
    var retval = 0;
    for (var i = 0, len = arguments.length; i < len; ++i) {
        retval += arguments[i];
    }
    return retval;
}

sum(1, 2, 3) // returns 6

117
Đáng lưu ý rằng mặc dù các đối số hoạt động như một mảng, nhưng đó không phải là một mảng javascript thực tế - nó chỉ là một đối tượng. Vì vậy, bạn không thể tham gia (), pop (), đẩy (), lát () và vv. (Bạn có thể chuyển đổi nó thành một mảng thực nếu bạn muốn: "var argArray = Array.prototype.slice.call (argument);")
Jacob Mattison

51
Cũng đáng lưu ý rằng việc truy cập vào đối tượng Đối tượng tương đối tốn kém - ví dụ tốt nhất là trong các đêm, Safari và Chrome trong đó việc chỉ tham chiếu argumentsđối tượng khiến việc gọi hàm chậm hơn nhiều - ví dụ: nếu (sai) đối số; sẽ làm tổn thương sự hoàn hảo
olliej

48
Trong cùng một hướng, các đối số có thuộc tính "callee" là chính hàm hiện tại. Điều này cho phép thực hiện đệ quy với các chức năng ẩn danh, tuyệt vời!
Vincent Robert

4
@Nathan "f (x, y, z)" trông tốt hơn "f ([x, y, z])".
Đánh dấu Cidade

16
@Vincent Robert: xin lưu ý rằng arguments.calleeđang bị phản đối.
ken

204

Tôi có thể trích dẫn hầu hết cuốn sách tuyệt vời của Douglas Crockford : The Good Parts .

Nhưng tôi sẽ chỉ lấy một cái cho bạn, luôn luôn sử dụng ===!==thay vì ==!=

alert('' == '0'); //false
alert(0 == ''); // true
alert(0 =='0'); // true

==không mang tính bắc cầu. Nếu bạn sử dụng ===nó sẽ cung cấp sai cho tất cả các tuyên bố này như mong đợi.


29
Thật xấu hổ khi rất nhiều người nghĩ rằng Crockford là tất cả hiểu biết. Được cho phép, anh chàng này đã đúng với hầu hết những lời chỉ trích của anh ta, nhưng tôi không ngừng đưa ra công cụ của anh ta chứng thực chăn gối như rất nhiều nhà phát triển làm ...
Jason Bunting

21
Tôi thứ hai cảnh báo của Jason. Cuốn sách trong chính nó là rất thú vị, và nó cung cấp cho rất nhiều lời khuyên tốt, nhưng DC được xa quá thuyết phục rằng con đường của mình làm việc là cách duy nhất đúng, mọi thứ khác là "khiếm khuyết". Nếu bạn muốn một số ví dụ, hãy xem phản hồi của anh ấy trên Nhóm Yahoo của JSLint.
Zilk

30
Sử dụng === thay vì == là lời khuyên tốt nếu bạn bối rối khi gõ động và chỉ muốn nó "thực sự" bằng. Những người trong chúng ta hiểu cách gõ động có thể tiếp tục sử dụng == cho các tình huống mà chúng tôi biết chúng tôi muốn truyền, như trong 0 == '' hoặc 0 == '0'.
thomasrutter

20
Vâng == và === không phải là về gõ động. == không loại coersion, đó là một con thú khác. Nếu bạn biết rằng bạn muốn truyền sang chuỗi / số / vv, thì bạn sẽ làm điều đó một cách rõ ràng.
Rene Saarsoo

15
Tôi nghĩ phần đáng sợ nhất =='\n\t\r ' == 0=> true...: D
Shrikant Sharat

189

Các hàm là công dân hạng nhất trong JavaScript:

var passFunAndApply = function (fn,x,y,z) { return fn(x,y,z); };

var sum = function(x,y,z) {
  return x+y+z;
};

alert( passFunAndApply(sum,3,4,5) ); // 12

Các kỹ thuật lập trình chức năng có thể được sử dụng để viết javascript thanh lịch .

Đặc biệt, các hàm có thể được truyền dưới dạng tham số, ví dụ Array.filter () chấp nhận gọi lại:

[1, 2, -1].filter(function(element, index, array) { return element > 0 });
// -> [1,2]

Bạn cũng có thể khai báo một hàm "riêng tư" chỉ tồn tại trong phạm vi của một hàm cụ thể:

function PrintName() {
    var privateFunction = function() { return "Steve"; };
    return privateFunction();
}

3
Có ba cách để tạo các hàm trong javascript: function sum (x, y, z) {return (x + y + z); } và var sum = new Hàm ("x", "y", "z", "return (x + y + z);"); là những cách khác.
Marius

6
Khái niệm về chức năng như dữ liệu chắc chắn giành được điểm lớn trong cuốn sách của tôi.
Jason Bunting

Tôi vừa cập nhật mẫu để hiển thị cách sử dụng chức năng "riêng tư" chỉ tồn tại trong phạm vi của một chức năng cụ thể.
Chris Pietschmann

new Function()cũng ác như eval. Không được dùng.
Nicolás

11
không chắc đây là một tính năng ẩn ... giống như một tính năng cốt lõi.
Claudiu

162

Bạn có thể sử dụng toán tử in để kiểm tra xem khóa có tồn tại trong một đối tượng không:

var x = 1;
var y = 3;
var list = {0:0, 1:0, 2:0};
x in list; //true
y in list; //false
1 in list; //true
y in {3:0, 4:0, 5:0}; //true

Nếu bạn thấy các đối tượng bằng chữ quá xấu, bạn có thể kết hợp nó với mẹo hàm không tham số:

function list()
 { var x = {};
   for(var i=0; i < arguments.length; ++i) x[arguments[i]] = 0;
   return x
 }

 5 in list(1,2,3,4,5) //true

22
Không thông minh, kiểm tra xem có khóa hay không, nếu giá trị là. x trong danh sách; chỉ hoạt động vì x [1]! = null, không phải vì giá trị 1 ở đó.
Armin Ronacher

1
Tôi đã không sử dụng kỹ thuật ina trong khi đó vì vậy tôi quên rằng tôi thực sự đã sử dụng các đối tượng trước đây. Cảm ơn vì sự đúng đắn của bạn.
Đánh dấu Cidade

34
Ngoài ra, hãy cẩn thận: toán tử trong cũng kiểm tra chuỗi nguyên mẫu! Nếu ai đó đã đặt một thuộc tính có tên '5' trên Object.prototype, ví dụ thứ hai sẽ trả về đúng ngay cả khi bạn gọi '5 trong danh sách (1, 2, 3, 4)' ... Bạn nên sử dụng hasOwnProperty phương thức: list (1, 2, 3, 4) .hasOwnProperty (5) sẽ trả về false, ngay cả khi Object.prototype có thuộc tính '5'.
Martijn

3
Đối với giải pháp chung nhất, một giải pháp có thể kiểm tra xem một đối tượng có thuộc tính riêng hay không, ngay cả khi nó được đặt tên là "hasOwnProperty", bạn phải tìm mọi cách: Object.prototype.hasOwnProperty.call (đối tượng, tên) ;
Kris Kowal

1
@Kris, trừ khi có ai đó ghi đè lên Object.prototype.hasOwnProperty;)
Nick

153

Gán giá trị mặc định cho các biến

Bạn có thể sử dụng logic hoặc toán tử ||trong biểu thức gán để cung cấp giá trị mặc định:

var a = b || c;

Các abiến sẽ nhận được giá trị của cchỉ nếu bfalsy (nếu là null, false, undefined, 0, empty string, hay NaN), nếu không asẽ nhận được giá trị của b.

Điều này thường hữu ích trong các hàm, khi bạn muốn đưa ra một giá trị mặc định cho một đối số trong trường hợp không được cung cấp:

function example(arg1) {
  arg1 || (arg1 = 'default value');
}

Ví dụ dự phòng IE trong trình xử lý sự kiện:

function onClick(e) {
    e || (e = window.event);
}

Các tính năng ngôn ngữ sau đây đã có với chúng tôi trong một thời gian dài, tất cả các triển khai JavaScript đều hỗ trợ chúng, nhưng chúng không phải là một phần của đặc tả cho đến ECMAScript Phiên bản thứ 5 :

các debuggertuyên bố

Được mô tả trong: § 12.15 Tuyên bố trình gỡ lỗi

Tuyên bố này cho phép bạn đặt các điểm dừng theo chương trình trong mã của mình chỉ bằng cách:

// ...
debugger;
// ...

Nếu trình gỡ lỗi có mặt hoặc hoạt động, nó sẽ khiến nó bị hỏng ngay lập tức, ngay trên dòng đó.

Mặt khác, nếu trình gỡ lỗi không có mặt hoặc hoạt động thì câu lệnh này không có hiệu lực quan sát được.

Chuỗi chữ đa dòng

Được mô tả trong: § 7.8.4 Chuỗi ký tự

var str = "This is a \
really, really \
long line!";

Bạn phải cẩn thận vì ký tự bên cạnh \ phải là dấu kết thúc dòng, nếu bạn có một khoảng trắng sau \ví dụ, mã sẽ trông giống hệt nhau, nhưng nó sẽ tăng a SyntaxError.


28
Không, nếu nó là null, nếu nó được coi là sai. a = 0 | | 42; sẽ cung cấp cho bạn 42. Điều này có thể so sánh với Python hoặc, không phải C # ?? nhà điều hành. Nếu bạn muốn hành vi C #, hãy thực hiện a = (b === null)? c: b;
Armin Ronacher

Nó cũng hoạt động trong Visual Studio, nếu bạn phát triển trên ASP.NET :)
chakrit

2
Tôi ước có đúng | | chỉ cho không xác định. Hôm nay tôi đã bị cắn bởi 0, vì tôi muốn tạo mô phỏng phương thức quá tải, do đó, đối số cuối cùng là tùy chọn và thay vào đó sẽ sử dụng giá trị mặc định.
egaga

+1 thủ thuật này được sử dụng bởi đoạn mã Google Analytics mặc định. `var _gaq = _gaq | | []; `; nó ngăn người dùng quá nhiệt tình ghi đè lên tác phẩm của chính họ.
Yahel

2
Tôi không biết về kỹ thuật chuỗi chữ đa dòng. Thật tuyệt vời, cảm ơn.
Charlie Hoa

145

JavaScript không có phạm vi chặn (nhưng nó đã đóng nên chúng ta gọi nó là chẵn?).

var x = 1;
{
   var x = 2;
}
alert(x); // outputs 2

3
Đó là một thứ tốt. Đó là một sự khác biệt thực sự quan trọng từ hầu hết các ngôn ngữ C như.
Martin Clarke

9
Bạn luôn có thể thực hiện "var tmp = function () {/ * block scope * /} ();". Cú pháp là xấu, nhưng nó hoạt động.
Joeri Sebrechts

3
Hoặc bạn có thể sử dụng "cho phép" nếu chỉ có Firefox: stackoverflow.com/questions/61088/ Khăn
Eugene Yokota

10
hoặc chỉ: (hàm () {var x = 2;}) (); cảnh báo (typeof x); // không xác định
Pim Jager

@Pim: JSLint nói: "Di chuyển lời mời vào các ô có chứa hàm.". Cùng với "Dự kiến ​​chính xác một khoảng
trắng

144

Bạn có thể truy cập các thuộc tính đối tượng với []thay vì.

Điều này cho phép bạn tra cứu một thuộc tính khớp với một biến.

obj = {a:"test"};
var propname = "a";
var b = obj[propname];  // "test"

Bạn cũng có thể sử dụng điều này để lấy / đặt thuộc tính đối tượng có tên không phải là định danh hợp pháp.

obj["class"] = "test";  // class is a reserved word; obj.class would be illegal.
obj["two words"] = "test2"; // using dot operator not possible with the space.

Một số người không biết điều này và cuối cùng sử dụng eval () như thế này, đây là một ý tưởng thực sự tồi tệ :

var propname = "a";
var a = eval("obj." + propname);

Điều này khó đọc hơn, khó tìm lỗi hơn (không thể sử dụng jslint), thực thi chậm hơn và có thể dẫn đến khai thác XSS.


eval là xấu xa, mặc dù hiếm khi cần thiết
Doug Domeny

Tôi không bao giờ sử dụng eval và nhớ khi tôi phát hiện ra điều này. Nó làm tôi rất hạnh phúc.

Tóm lại, các thuộc tính đối tượng có thể được truy cập thông qua cả ký hiệu dấu chấm và ký hiệu con
Russ Cam

9
Thật thú vị khi lưu ý rằng tham chiếu chấm thực sự là cú pháp đường cho ngoặc. foo.bar, theo thông số kỹ thuật nào, hành xử giống như foo["bar"]. cũng lưu ý rằng tất cả mọi thứ là một thuộc tính chuỗi. ngay cả khi bạn truy cập mảng, array[4]4 được chuyển đổi thành một chuỗi (một lần nữa, ít nhất là theo thông số ECMAScript v3)
Claudiu

Tôi đoán mọi lập trình viên JS nên biết điều này.
Cem Kalyoncu

144

Nếu bạn đang tìm kiếm một tài liệu tham khảo JavaScript phù hợp về một chủ đề nhất định, hãy bao gồm từ khóa "mdc" trong truy vấn của bạn và kết quả đầu tiên của bạn sẽ từ Trung tâm nhà phát triển Mozilla. Tôi không mang theo bất kỳ tài liệu tham khảo ngoại tuyến hoặc sách nào bên mình. Tôi luôn sử dụng thủ thuật từ khóa "mdc" để trực tiếp đến những gì tôi đang tìm kiếm. Ví dụ:

Google: mdc sắp xếp mảng javascript
(trong hầu hết các trường hợp bạn có thể bỏ qua "javascript")

Cập nhật: Mozilla Developer Center đã được đổi tên thành Mozilla Developer Network . Thủ thuật từ khóa "mdc" vẫn hoạt động, nhưng chúng ta có thể phải bắt đầu sử dụng "mdn" ngay sau đó .


50
Wow, tài nguyên tuyệt vời. Tốt hơn ngay lập tức so với w3schools ...
DisgruntledGoat

11
Bạn thậm chí không cần Google, nếu bạn đang ở trên Firefox: chỉ cần nhập "mảng mdc" vào thanh địa chỉ và nhấn Enter.
Sasha Chedygov

2
phần tốt nhất là làm thế nào câu hỏi tràn ngăn xếp này ở trang đầu tiên của kết quả :)
Jiaaro

5
Một propo này: thúc đẩy , một sáng kiến ​​SEO cơ sở để thúc đẩy kết quả MDC hơn nữa trong kết quả tìm kiếm của Google.
Yahel

3
Bây giờ là trung tâm tài liệu MDN, vì vậy từ khóa 'mdc' vẫn còn hiệu lực :)
Aleadam

143

Có lẽ một chút rõ ràng đối với một số ...

Cài đặt Fireorms và sử dụng console.log ("xin chào"). Vì vậy, tốt hơn nhiều so với việc sử dụng cảnh báo ngẫu nhiên (); mà tôi nhớ đã làm rất nhiều năm trước.


12
Chỉ cần đừng quên xóa các câu lệnh console trước khi phát hành mã của bạn cho những người khác có thể chưa cài đặt Fireorms.
Chris Noe

161
chức năng nhật ký (tin nhắn) {if (console) console.log (tin nhắn) khác cảnh báo (tin nhắn)}
Josh

4
Thậm chí tốt hơn, báo cáo nhật ký trước với ';;;' và sau đó minify chăm sóc nó cho bạn. (Ít nhất, mô-đun Perl tôi sử dụng có tính năng đó và tuyên bố nó là phổ biến.)
Kev

10
Josh: Điều đó sẽ không hoạt động vì giao diện điều khiển không được xác định. Bạn có thể kiểm tra bảng điều khiển typeof! == "không xác định" hoặc window.console.
Eli Gray

23
Luôn bao gồm: if (typeof ('console') == 'không xác định') {console = {log: function () {}}; } sau đó bạn có thể tiếp tục sử dụng console.log và nó không làm gì cả.
gregmac

120

Phương pháp riêng tư

Một đối tượng có thể có phương thức riêng.

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;

    // A private method only visible from within this constructor
    function calcFullName() {
       return firstName + " " + lastName;    
    }

    // A public method available to everyone
    this.sayHello = function () {
        alert(calcFullName());
    }
}

//Usage:
var person1 = new Person("Bob", "Loblaw");
person1.sayHello();

// This fails since the method is not visible from this scope
alert(person1.calcFullName());

16
Đó không thực sự là một chức năng riêng tư - đó là một biến chức năng trong phạm vi cục bộ.
Keith

6
Đúng nhưng theo tất cả các định nghĩa hoạt động tôi có thể nghĩ đó là một phương pháp. Đó là một khối mã với một tên có quyền truy cập vào trạng thái thể hiện và chỉ có thể được nhìn thấy bởi thể hiện đó. Định nghĩa của bạn về một phương pháp riêng tư là gì?
Allain Lalonde

14
@Zach, chính xác! Thật dễ dàng, sau khi dành nhiều năm làm việc với các ngôn ngữ OO dựa trên lớp, để quên rằng chúng chỉ là một triển khai các khái niệm OO. Tất nhiên, các thư viện khác nhau cố gắng nhồi nhét OO dựa trên lớp gần như vào JS cũng không giúp được gì ...
Shog9

5
Chỉ cần tự hỏi, person1 có một Blog Luật? ;-)
travis

4
+1 cho tài liệu tham khảo phát triển bị bắt giữ
Domenic

99

Cũng được đề cập trong "Javascript: The Good Parts" của Crockford:

parseInt()là nguy hiểm. Nếu bạn truyền cho nó một chuỗi mà không thông báo cho nó về cơ sở thích hợp, nó có thể trả về các số không mong muốn. Ví dụ parseInt('010')trả về 8, không phải 10. Chuyển một cơ sở cho parseInt làm cho nó hoạt động chính xác:

parseInt('010') // returns 8! (in FF3)
parseInt('010', 10); // returns 10 because we've informed it which base to work with.

13
Khi làm mã đánh giá, luôn luôn tìm cái này. Rời khỏi ", 10" là một lỗi phổ biến không được chú ý trong hầu hết các thử nghiệm.
Doug Domeny

Tôi đã bị đốt cháy bởi vấn đề cơ số nhiều năm trước và chưa bao giờ quên một cái gì đó phản trực giác như vậy. Một điều tuyệt vời để chỉ ra vì nó sẽ khiến bạn tự hỏi một lúc.
JamesEggers

4
Tại sao không sử dụng Math.floorhay Number? 10 === Math.floor("010"); 10 === Number("010");phao:42 === Math.floor("42.69"); 42.69 === Number("42.69");
chỉ ai đó

1
@Infinity Nếu chưa có câu trả lời được đăng, bạn nên. Tôi không biết nó chỉ đơn giản như thế này để ghi đè hành vi chức năng tích hợp. Tất nhiên, nó sẽ khiến người ta nhìn kỹ hơn một chút vào bất kỳ gói mã nào họ mượn từ các trang web khác. parseIntChức năng vô hại đó có thể dễ dàng được thực hiện để làm một cái gì đó không quá vô hại.
tàu khu trục bob

6
@Infinity: còn việc xác định lại fn để làm nổi bật 'lỗi mã hóa' thì sao? __parseInt = parseInt; parseInt = function (str, base) { if (!base) throw new Error(69, "All your base belong to us"); return __parseInt(str, base); }
JBRWilkinson

97

Hàm là các đối tượng và do đó có thể có các thuộc tính.

fn = hàm (x) {
   // ...
}

fn.foo = 1;

fn.next = hàm (y) {
  //
}

13
Đây là một mẹo rất hữu ích. Ví dụ: bạn có thể đặt các giá trị mặc định làm thuộc tính của hàm. Ví dụ: myfunc.delay = 100; Sau đó, người dùng có thể thay đổi giá trị mặc định và tất cả các lệnh gọi hàm sẽ sử dụng giá trị mặc định mới. Ví dụ: myfunc.delay = 200; myfunc ();
BarelyFitz

Hữu ích ... và nguy hiểm!
palswim

Có vẻ cẩu thả, Tại sao sử dụng điều này thay vì một biến?
instantsetsuna

1
@instantsetsuna: Tại sao có một biến riêng biệt khác? Như thường lệ, điều này có nghĩa là "sử dụng nó khi thích hợp / hữu ích" ;-)
VolkerK

91

Tôi phải nói rằng các chức năng tự thực hiện.

(function() { alert("hi there");})();

Vì Javascript không có phạm vi chặn , bạn có thể sử dụng chức năng tự thực thi nếu bạn muốn xác định các biến cục bộ:

(function() {
  var myvar = 2;
  alert(myvar);
})();

Ở đây, myvarkhông can thiệp hoặc làm ô nhiễm phạm vi toàn cầu và biến mất khi chức năng chấm dứt.


2
Điều này hữu ích cho việc gì? Bạn nhận được kết quả tương tự từ việc đặt cảnh báo bên ngoài chức năng.
Khoai tâyEngineer

7
Đó không phải là về cảnh báo, mà là về việc xác định và thực hiện tất cả một chức năng cùng một lúc. Bạn có thể có chức năng tự thực thi đó trả về một giá trị và truyền hàm dưới dạng param cho hàm khác.
ScottKoon

5
@Paul nó tốt cho đóng gói.
Mike Robinson

22
Nó cũng tốt cho phạm vi khối.
Jim Hunziker

24
Vâng, tôi gửi tất cả .jscác tệp của mình vào một chức năng tự thực hiện ẩn danh và đính kèm bất cứ thứ gì tôi muốn có thể truy cập trên toàn cầu vào windowđối tượng. Ngăn chặn ô nhiễm không gian tên toàn cầu.
cdmckay

83

Biết có bao nhiêu tham số được mong đợi bởi một hàm

function add_nums(num1, num2, num3 ){
    return num1 + num2 + num3;
}
add_nums.length // 3 is the number of parameters expected.

Biết có bao nhiêu tham số được nhận bởi hàm

function add_many_nums(){
    return arguments.length;
}    
add_many_nums(2,1,122,12,21,89); //returns 6

23
Không bao giờ biết về phần đầu tiên. Đẹp!
mcjabberz

1
Tương tự như vậy, bạn có thể tìm ra có bao nhiêu đối số mà một hàm đang mong đợi function.length.
Xavi

6
@Xavi là phần đầu tiên của câu trả lời
pramodc84

79

Dưới đây là một số điều thú vị:

  • So sánh NaNvới bất cứ điều gì (thậm chí NaN) luôn luôn là sai, bao gồm ==, <>.
  • NaN Viết tắt của Không phải là Số nhưng nếu bạn hỏi loại đó thực sự sẽ trả về một số.
  • Array.sort có thể có chức năng so sánh và được gọi bởi trình điều khiển giống như quicksort (phụ thuộc vào việc thực hiện).
  • Biểu thức chính quy "hằng số" có thể duy trì trạng thái, giống như điều cuối cùng mà chúng khớp.
  • Một số phiên bản của JavaScript cho phép bạn truy cập $0, $1, $2thành viên trên một regex.
  • nulllà không giống như bất cứ điều gì khác. Nó không phải là một đối tượng, boolean, một số, một chuỗi, cũng không undefined. Nó hơi giống như một "thay thế" undefined. (Ghi chú:typeof null == "object" :)
  • Trong bối cảnh ngoài cùng, this mang lại đối tượng [Toàn cầu] không thể đặt tên khác.
  • Khai báo một biến với var , thay vì chỉ dựa vào khai báo tự động của biến đó mang lại cho bộ thực thi cơ hội thực sự tối ưu hóa quyền truy cập vào biến đó
  • Các with trúc sẽ phá hủy các tối ưu hóa như vậy
  • Tên biến có thể chứa các ký tự Unicode.
  • JavaScript biểu thức chính quy không thực sự thường xuyên. Chúng dựa trên biểu thức chính của Perl và có thể xây dựng các biểu thức với các biểu tượng cần một thời gian rất, rất dài để đánh giá.
  • Các khối có thể được dán nhãn và sử dụng làm mục tiêu của break. Vòng lặp có thể được dán nhãn và sử dụng làm mục tiêu của continue.
  • Mảng không thưa thớt. Đặt phần tử thứ 1000 của một mảng trống khác sẽ điền vào nó undefined. (phụ thuộc vào việc thực hiện)
  • if (new Boolean(false)) {...} sẽ thực thi {...}khối
  • Công cụ biểu thức chính quy của Javascript là cụ thể triển khai: ví dụ: có thể viết biểu thức chính quy "không di động".

[cập nhật một chút để đáp lại những bình luận tốt; vui lòng xem bình luận]


5
null thực sự là một đối tượng (đặc biệt). typeof nulltrả về "đối tượng".
Ates Goral

4
Bạn cũng có thể lấy đối tượng [Toàn cầu] từ bất kỳ đâu như thế này: var glb = function () {return this; } ();
Zilk

2
Đối tượng toàn cầu trong javascript trong trình duyệt là đối tượng cửa sổ. Khi trong phạm vi toàn cầu đang làm: window.a == a;
Pim Jager

8
"Mảng không thưa thớt" phụ thuộc vào việc thực hiện. Nếu bạn đặt giá trị của [1000] và nhìn vào [999], thì đúng vậy undefined, nhưng đó chỉ là giá trị mặc định bạn nhận được khi tìm kiếm một chỉ mục không tồn tại. Nếu bạn đã kiểm tra [2000], điều đó cũng có thể undefined, nhưng điều đó không có nghĩa là bạn đã phân bổ bộ nhớ cho nó. Trong IE8, một số mảng dày đặc và một số thì thưa thớt, tùy thuộc vào cảm giác của công cụ JScript tại thời điểm đó. Đọc thêm tại đây: blog.msdn.com/jscript/archive/2008/04/08/ trên
Chris Nielsen

2
@Ates và @SF: typeof trả về "đối tượng" cho một loạt các loại khác nhau. Nhưng một khi bạn biết nó hoạt động như thế nào và loại nào xác định là "đối tượng", thì ít nhất nó đáng tin cậy và nhất quán trong việc thực hiện.
thomasrutter

77

Tôi biết tôi đến bữa tiệc muộn, nhưng tôi không thể tin rằng +tính hữu dụng của nhà điều hành đã không được đề cập ngoài việc "chuyển đổi bất cứ thứ gì thành số". Có lẽ đó là một tính năng ẩn tốt như thế nào?

// Quick hex to dec conversion:
+"0xFF";              // -> 255

// Get a timestamp for now, the equivalent of `new Date().getTime()`:
+new Date();

// Safer parsing than parseFloat()/parseInt()
parseInt("1,000");    // -> 1, not 1000
+"1,000";             // -> NaN, much better for testing user input
parseInt("010");      // -> 8, because of the octal literal prefix
+"010";               // -> 10, `Number()` doesn't parse octal literals 

// A use case for this would be rare, but still useful in cases
// for shortening something like if (someVar === null) someVar = 0;
+null;                // -> 0;

// Boolean to integer
+true;                // -> 1;
+false;               // -> 0;

// Other useful tidbits:
+"1e10";              // -> 10000000000
+"1e-4";              // -> 0.0001
+"-12";               // -> -12

Tất nhiên, Number()thay vào đó , bạn có thể thực hiện tất cả điều này bằng cách sử dụng , nhưng +toán tử này đẹp hơn nhiều!

Bạn cũng có thể xác định giá trị trả về số cho một đối tượng bằng cách ghi đè valueOf()phương thức của nguyên mẫu . Bất kỳ chuyển đổi số nào được thực hiện trên đối tượng đó sẽ không dẫn đến NaN, nhưng giá trị trả về của valueOf()phương thức:

var rnd = {
    "valueOf": function () { return Math.floor(Math.random()*1000); }
};
+rnd;               // -> 442;
+rnd;               // -> 727;
+rnd;               // -> 718;

Bạn có thể làm đơn giản 0xFF, vv, không cần +"0xFF".
nyuszika7h

9
@ Nyuszika7H: bạn đang thiếu điểm, điều này đang ép buộc các nguyên thủy và đối tượng khác vào các con số. Tất nhiên bạn chỉ có thể viết 0xFF, giống như cách bạn có thể viết 1thay vì +true. Tôi đề nghị rằng bạn có thể sử dụng +("0x"+somevar)thay thế parseInt(somevar, 16), nếu bạn muốn.
Andy E

75

" Các phương thức mở rộng trong JavaScript " thông qua thuộc tính nguyên mẫu.

Array.prototype.contains = function(value) {  
    for (var i = 0; i < this.length; i++) {  
        if (this[i] == value) return true;  
    }  
    return false;  
}

Điều này sẽ thêm một containsphương thức cho tất cả Arraycác đối tượng. Bạn có thể gọi phương thức này bằng cú pháp này

var stringArray = ["foo", "bar", "foobar"];
stringArray.contains("foobar");

18
Đây thường được coi là một ý tưởng tồi, bởi vì mã khác (không phải của bạn) có thể đưa ra các giả định về đối tượng Array.
Chris Noe

39
Nó cũng thường được coi là một ý tưởng tồi để đưa ra các giả định về đối tượng Array. :(
mí mắt

Uhmmmm .. bổ sung mảng javascript 1.6? Chỉ số? Tiếng chuông nào?
Breton

2
@Breton: Nó không phải là một cái gì đó cụ thể cho lớp Array, nó chỉ là một ví dụ. Tôi sử dụng điều này để mở rộng Ngày mới (). ToString (); phương pháp, cho phép sử dụng một chuỗi mặt nạ. Bất kỳ đối tượng nào cũng có thể được mở rộng và tất cả các phiên bản của nó đều có phương thức mới.
Esteban Küber

1
@Mathias: đây không phải là về DOM.
heo

60

Để xóa đúng một thuộc tính khỏi một đối tượng, bạn nên xóa thuộc tính thay vì chỉ đặt nó thành không xác định :

var obj = { prop1: 42, prop2: 43 };

obj.prop2 = undefined;

for (var key in obj) {
    ...

Thuộc tính prop2 vẫn sẽ là một phần của phép lặp. Nếu bạn muốn loại bỏ hoàn toàn prop2 , thay vào đó bạn nên làm:

delete obj.prop2;

Thuộc tính prop2 sẽ không còn xuất hiện khi bạn lặp qua các thuộc tính.


3
Lưu ý rằng câu lệnh xóa không phải là không có các quirks dành riêng cho trình duyệt. Chẳng hạn, điều này sẽ thất bại với một lỗi lớn nếu bạn thử nó trong IE và đối tượng không phải là đối tượng JS gốc (ngay cả khi xóa một thuộc tính bạn tự thêm vào). Nó cũng không có ý định xóa một biến, như trong việc xóa myvar; nhưng tôi nghĩ rằng nó hoạt động trong một số trình duyệt. Các mã trong câu trả lời trên có vẻ khá an toàn mặc dù.
thomasrutter

Nhân tiện, không xác định cũng có thể là một biến! Hãy thử var
undinite

57

with.

Nó hiếm khi được sử dụng, và thẳng thắn, hiếm khi hữu ích ... Nhưng, trong trường hợp hạn chế, nó có công dụng của nó.

Ví dụ: đối tượng bằng chữ khá tiện dụng để nhanh chóng thiết lập các thuộc tính trên một đối tượng mới . Nhưng nếu bạn cần thay đổi một nửa các thuộc tính trên một đối tượng hiện có thì sao?

var user = 
{
   fname: 'Rocket', 
   mname: 'Aloysus',
   lname: 'Squirrel', 
   city: 'Fresno', 
   state: 'California'
};

// ...

with (user)
{
   mname = 'J';
   city = 'Frostbite Falls';
   state = 'Minnesota';
}

Alan Storm chỉ ra rằng điều này có thể hơi nguy hiểm: nếu đối tượng được sử dụng làm bối cảnh không một trong các thuộc tính được gán, nó sẽ được giải quyết trong phạm vi bên ngoài, có thể tạo hoặc ghi đè một biến toàn cục. Điều này đặc biệt nguy hiểm nếu bạn đã quen viết mã để làm việc với các đối tượng trong đó các thuộc tính có giá trị mặc định hoặc trống không được xác định:

var user = 
{
   fname: "John",
// mname definition skipped - no middle name
   lname: "Doe"
};

with (user)
{
   mname = "Q"; // creates / modifies global variable "mname"
}

Do đó, có lẽ nên tránh sử dụng withcâu lệnh cho bài tập đó.

Xem thêm: Có sử dụng hợp pháp cho câu lệnh JavaScript với JavaScript không?


29
Sự khôn ngoan thông thường với statment là phải tránh. Nếu đối tượng người dùng không có một trong các thuộc tính bạn đã đề cập, biến bên ngoài phạm vi giả của khối sẽ được sửa đổi. Đó là cách nói dối. Thêm thông tin tại yuiblog.com/blog/2006/04/11/with-statement-considered-harmful
Alan Storm

1
Shog, sự phản đối không phải là về các biến sai chính tả, họ đang xem xét một khối mã và có thể nói chắc chắn bất kỳ dòng cụ thể nào trong khối đó làm gì. Vì các đối tượng Javascript rất năng động, bạn không thể nói chắc chắn thuộc tính / thành viên nào có tại bất kỳ thời điểm nào.
Alan Storm

2
Amen - nếu tôi thấy câu lệnh "with" trong bất kỳ JS nào tôi tìm thấy, tôi sẽ loại bỏ nó và đặt câu hỏi cho nhà phát triển đã viết nó để đảm bảo rằng anh ta biết tại sao nó không phải là một điều tốt để sử dụng nó ... "tính năng ẩn?" Giống như "tính năng gớm ghiếc".
Jason Bunting

1
xem xét một chuỗi abcd phức tạp hơn "với (abc) {d.foo = bar;} là mạnh mẽ và không dễ bị lỗi. Chìa khóa là để điều chỉnh gốc một cấp. Và viết sai tên biến? Bạn đang giới thiệu một lỗi nếu bạn làm điều đó bất cứ nơi nào bạn làm điều đó, bất kể "với".
annakata

4
Douglas Crockford gần đây đã nói "với" là một trong những phần tồi tệ nhất của JavaScript trong .NET Rocks! tệp âm thanh.
lõi

51

Các phương thức (hoặc hàm) có thể được gọi trên đối tượng không thuộc loại mà chúng được thiết kế để làm việc. Điều này thật tuyệt khi gọi các phương thức gốc (nhanh) trên các đối tượng tùy chỉnh.

var listNodes = document.getElementsByTagName('a');
listNodes.sort(function(a, b){ ... });

Mã này gặp sự cố vì listNodeskhông phải là mộtArray

Array.prototype.sort.apply(listNodes, [function(a, b){ ... }]);

Mã này hoạt động vì listNodesđịnh nghĩa đủ các thuộc tính giống như mảng (toán tử []) được sử dụng bởi sort().


43

Kế thừa nguyên mẫu (được phổ biến bởi Douglas Crockford) hoàn toàn cách mạng hóa cách bạn nghĩ về vô số thứ trong Javascript.

Object.beget = (function(Function){
    return function(Object){
        Function.prototype = Object;
        return new Function;
    }
})(function(){});

Đó là một kẻ giết người! Đáng tiếc làm sao hầu như không ai sử dụng nó.

Nó cho phép bạn "quên" các thể hiện mới của bất kỳ đối tượng nào, mở rộng chúng, trong khi duy trì liên kết thừa kế nguyên mẫu (trực tiếp) với các thuộc tính khác của chúng. Thí dụ:

var A = {
  foo : 'greetings'
};  
var B = Object.beget(A);

alert(B.foo);     // 'greetings'

// changes and additionns to A are reflected in B
A.foo = 'hello';
alert(B.foo);     // 'hello'

A.bar = 'world';
alert(B.bar);     // 'world'


// ...but not the other way around
B.foo = 'wazzap';
alert(A.foo);     // 'hello'

B.bar = 'universe';
alert(A.bar);     // 'world'

42

Một số người sẽ gọi đây là vấn đề của hương vị, nhưng:

aWizz = wizz || "default";
// same as: if (wizz) { aWizz = wizz; } else { aWizz = "default"; }

Toán tử ba có thể bị xiềng xích để hành động như Scheme's (cond ...):

(cond (predicate  (action  ...))
      (predicate2 (action2 ...))
      (#t         default ))

có thể được viết như...

predicate  ? action( ... ) :
predicate2 ? action2( ... ) :
             default;

Điều này rất "chức năng", vì nó phân nhánh mã của bạn mà không có tác dụng phụ. Vì vậy, thay vì:

if (predicate) {
  foo = "one";
} else if (predicate2) {
  foo = "two";
} else {
  foo = "default";
}

Bạn có thể viết:

foo = predicate  ? "one" :
      predicate2 ? "two" :
                   "default";

Hoạt động tốt với đệ quy, quá :)


Tôi thích cú pháp vị ngữ bạn đưa ra. Tôi chưa bao giờ nghĩ đến việc xâu chuỗi như thế. khéo léo.
Allain Lalonde

2
Uh ... JavaScript có câu lệnh switch (). :-)
staticsan

Tôi không phải là một fan hâm mộ lớn của các câu lệnh chuyển đổi - chúng là một tạo tác của C, không phải lập trình chức năng. Trong ví dụ của tôi, một câu lệnh chuyển đổi vẫn sẽ cần ba câu lệnh riêng biệt, tất cả bắt đầu bằng "foo =" - sự lặp lại không cần thiết rõ ràng.
Andrey Fedorov

14
Tôi, cho một, chào mừng các nhà điều hành ternary.
thomasrutter

8
Khi đọc lại, tôi muốn chỉ ra rằng đây không phải là "làm cho mã trông giống ngôn ngữ khác", mà thực sự đơn giản hóa ý nghĩa ngữ nghĩa của mã: khi bạn đang cố gắng nói "đặt foo thành một trong ba những thứ ", đó là một tuyên bố nên bắt đầu bằng" foo = ... ", không phải" nếu ".
Andrey Fedorov

41

Số cũng là đối tượng. Vì vậy, bạn có thể làm những thứ tuyệt vời như:

// convert to base 2
(5).toString(2) // returns "101"

// provide built in iteration
Number.prototype.times = function(funct){
  if(typeof funct === 'function') {
    for(var i = 0;i < Math.floor(this);i++) {
      funct(i);
    }
  }
  return this;
}


(5).times(function(i){
  string += i+" ";
});
// string now equals "0 1 2 3 4 "

var x = 1000;

x.times(function(i){
  document.body.innerHTML += '<p>paragraph #'+i+'</p>';
});
// adds 1000 parapraphs to the document

CHÚA ƠI! Tôi không biết về toString (cơ số) ...
Ates Goral

1
Việc thực hiện đó timeskhông hiệu quả: Math.floorđược gọi mỗi lần thay vì chỉ một lần.
heo

33

Làm thế nào về việc đóng trong JavaScript (tương tự như các phương thức ẩn danh trong C # v2.0 +). Bạn có thể tạo một hàm tạo một hàm hoặc "biểu thức".

Ví dụ về việc đóng cửa :

//Takes a function that filters numbers and calls the function on 
//it to build up a list of numbers that satisfy the function.
function filter(filterFunction, numbers)
{
  var filteredNumbers = [];

  for (var index = 0; index < numbers.length; index++)
  {
    if (filterFunction(numbers[index]) == true)
    {
      filteredNumbers.push(numbers[index]);
    }
  }
  return filteredNumbers;
}

//Creates a function (closure) that will remember the value "lowerBound" 
//that gets passed in and keep a copy of it.
function buildGreaterThanFunction(lowerBound)
{
  return function (numberToCheck) {
    return (numberToCheck > lowerBound) ? true : false;
  };
}

var numbers = [1, 15, 20, 4, 11, 9, 77, 102, 6];

var greaterThan7 = buildGreaterThanFunction(7);
var greaterThan15 = buildGreaterThanFunction(15);

numbers = filter(greaterThan7, numbers);
alert('Greater Than 7: ' + numbers);

numbers = filter(greaterThan15, numbers);
alert('Greater Than 15: ' + numbers);

1
Tôi không chắc chắn, nhưng có thể trả về (numberToCheck> lowBound) không? đúng sai; chỉ đơn giản là trở lại (numberToCheck> lowBound); chỉ cố gắng để tăng sự hiểu biết của tôi ...
davids ngủs

4
Tôi muốn nói các hàm ẩn danh trong C # tương đương với các bao đóng, không phải theo cách khác :)
vava

11
Đóng cửa và chức năng ẩn danh là các khái niệm riêng biệt, riêng biệt. Các chức năng đó có thể được tạo mà không được đặt tên là có các chức năng ẩn danh. Rằng một biến trong phạm vi 'tạo' được liên kết với hàm đã tạo là một bao đóng. Nói tóm lại, một bao đóng giống như một biến toàn cục ẩn.
slebetman

1
Đúng. Chỉ khi các phương thức ẩn danh sử dụng một biến từ phạm vi tạo thì nó mới tương tự như một bao đóng. Tôi đã cập nhật tiếng Anh về câu trả lời. Nó vẫn để lại một cái gì đó được mong muốn, nhưng tôi không biết tiếng Anh chính xác.
Tyler

2
Tôi không nghĩ đây là ví dụ tốt nhất hoặc dễ hiểu nhất về việc đóng cửa là gì. Chỉ cần nói. Điểm đóng cửa là ngay cả khi một loạt các biến xuất hiện 'đi ra khỏi phạm vi', chúng vẫn có thể có sẵn cho một hàm được xác định ban đầu trong phạm vi đó. Trong ví dụ trên, điều đó có nghĩa là biến lowBound vẫn có thể truy cập được bằng hàm bên trong, ẩn danh đó ngay cả khi hàm ngoài, buildGTHERThanFunction, chấm dứt.
thomasrutter

32

Bạn cũng có thể mở rộng (kế thừa) các lớp và ghi đè các thuộc tính / phương thức bằng cách sử dụng chuỗi nguyên mẫu Spoon16 được ám chỉ.

Trong ví dụ sau, chúng ta tạo một lớp Pet và định nghĩa một số thuộc tính. Chúng tôi cũng ghi đè phương thức .toString () được kế thừa từ Object.

Sau đó, chúng ta tạo một lớp Dog mở rộng Pet và ghi đè phương thức .toString () một lần nữa thay đổi hành vi của nó (đa hình). Ngoài ra, chúng tôi thêm một số thuộc tính khác cho lớp con.

Sau đó, chúng tôi kiểm tra chuỗi thừa kế để cho thấy rằng Dog vẫn thuộc loại Dog, loại Pet và loại Object.

// Defines a Pet class constructor 
function Pet(name) 
{
    this.getName = function() { return name; };
    this.setName = function(newName) { name = newName; };
}

// Adds the Pet.toString() function for all Pet objects
Pet.prototype.toString = function() 
{
    return 'This pets name is: ' + this.getName();
};
// end of class Pet

// Define Dog class constructor (Dog : Pet) 
function Dog(name, breed) 
{
    // think Dog : base(name) 
    Pet.call(this, name);
    this.getBreed = function() { return breed; };
}

// this makes Dog.prototype inherit from Pet.prototype
Dog.prototype = new Pet();

// Currently Pet.prototype.constructor
// points to Pet. We want our Dog instances'
// constructor to point to Dog.
Dog.prototype.constructor = Dog;

// Now we override Pet.prototype.toString
Dog.prototype.toString = function() 
{
    return 'This dogs name is: ' + this.getName() + 
        ', and its breed is: ' + this.getBreed();
};
// end of class Dog

var parrotty = new Pet('Parrotty the Parrot');
var dog = new Dog('Buddy', 'Great Dane');
// test the new toString()
alert(parrotty);
alert(dog);

// Testing instanceof (similar to the `is` operator)
alert('Is dog instance of Dog? ' + (dog instanceof Dog)); //true
alert('Is dog instance of Pet? ' + (dog instanceof Pet)); //true
alert('Is dog instance of Object? ' + (dog instanceof Object)); //true

Cả hai câu trả lời cho câu hỏi này là các mã được sửa đổi từ một bài viết MSDN tuyệt vời của Ray Djajadinata.


31

Bạn có thể bắt ngoại lệ tùy thuộc vào loại của họ. Trích dẫn từ MDC :

try {
   myroutine(); // may throw three exceptions
} catch (e if e instanceof TypeError) {
   // statements to handle TypeError exceptions
} catch (e if e instanceof RangeError) {
   // statements to handle RangeError exceptions
} catch (e if e instanceof EvalError) {
   // statements to handle EvalError exceptions
} catch (e) {
   // statements to handle any unspecified exceptions
   logMyErrors(e); // pass exception object to error handler
}

LƯU Ý: Các mệnh đề bắt có điều kiện là một phần mở rộng Netscape (và do đó Mozilla / Firefox) không phải là một phần của đặc tả ECMAScript và do đó không thể dựa vào ngoại trừ trên các trình duyệt cụ thể.


29
Tôi không thể giúp nó: bắt (tôi nếu bạn)
Ates Goral

6
Đọc ghi chú từ trang MDC mà bạn đã trích dẫn: các mệnh đề bắt có điều kiện là một phần mở rộng Netscape (và do đó Mozilla / Firefox) không phải là một phần của đặc tả ECMAScript và do đó không thể dựa vào ngoại trừ trên các trình duyệt cụ thể.
Jason S

31

Off đỉnh đầu của tôi...

Chức năng

argument.callee đề cập đến hàm lưu trữ biến "argument", vì vậy nó có thể được sử dụng để lặp lại các hàm ẩn danh:

var recurse = function() {
  if (condition) arguments.callee(); //calls recurse() again
}

Điều đó hữu ích nếu bạn muốn làm một cái gì đó như thế này:

//do something to all array items within an array recursively
myArray.forEach(function(item) {
  if (item instanceof Array) item.forEach(arguments.callee)
  else {/*...*/}
})

Các đối tượng

Một điều thú vị về các thành viên đối tượng: họ có thể có bất kỳ chuỗi nào như tên của họ:

//these are normal object members
var obj = {
  a : function() {},
  b : function() {}
}
//but we can do this too
var rules = {
  ".layout .widget" : function(element) {},
  "a[href]" : function(element) {}
}
/* 
this snippet searches the page for elements that
match the CSS selectors and applies the respective function to them:
*/
for (var item in rules) {
  var elements = document.querySelectorAll(rules[item]);
  for (var e, i = 0; e = elements[i++];) rules[item](e);
}

Dây

String.split có thể lấy các biểu thức chính quy làm tham số:

"hello world   with  spaces".split(/\s+/g);
//returns an array: ["hello", "world", "with", "spaces"]

String.replace có thể lấy một biểu thức chính quy làm tham số tìm kiếm và hàm làm tham số thay thế:

var i = 1;
"foo bar baz ".replace(/\s+/g, function() {return i++});
//returns "foo1bar2baz3"

Những điều bạn đề cập ... Chúng có được thực hiện trong tất cả các trình duyệt không?
cllpse

4
Không. Tôi khá chắc chắn rằng khảm thiếu hầu hết trong số họ.
jsight

2
Các tính năng javascript, vâng, chúng được triển khai trong tất cả các trình duyệt chính (IE6 / 7, FF2 / 3, Opera 9+, Safari2 / 3 và Chrome). document.querySelector ALL chưa được hỗ trợ trong tất cả các trình duyệt (đó là phiên bản W3C của JQuery $ () và Prototype's $$ ())
Leo

6
arguments.calleekhông được chấp nhận và sẽ ném và ngoại lệ trong ECMAScript 5.
Hello71

không hoàn toàn đúng Khóa đối tượng không thể (hoặc đúng hơn là không nên) sử dụng chuỗi "hasOwnProperty" làm tên, vì điều đó sẽ ghi đè lên phương thức đối tượng được xây dựng.
Breton

29

Bạn có thể sử dụng các đối tượng thay vì chuyển đổi hầu hết thời gian.

function getInnerText(o){
    return o === null? null : {
        string: o,
        array: o.map(getInnerText).join(""),
        object:getInnerText(o["childNodes"])
    }[typeis(o)];
}

Cập nhật: nếu bạn lo lắng về các trường hợp đánh giá trước là không hiệu quả (tại sao bạn lo lắng về hiệu quả này sớm trong thiết kế chương trình ??) thì bạn có thể làm điều gì đó như sau:

function getInnerText(o){
    return o === null? null : {
        string: function() { return o;},
        array: function() { return o.map(getInnerText).join(""); },
        object: function () { return getInnerText(o["childNodes"]; ) }
    }[typeis(o)]();
}

Điều này phù hợp hơn để gõ (hoặc đọc) hơn là một công tắc hoặc một đối tượng, nhưng nó bảo tồn các lợi ích của việc sử dụng một đối tượng thay vì một công tắc, chi tiết trong phần bình luận bên dưới. Phong cách này cũng làm cho nó trở nên đơn giản hơn để biến điều này thành một "lớp" thích hợp một khi nó phát triển đủ.

update2: với các phần mở rộng cú pháp được đề xuất cho ES.next, điều này trở thành

let getInnerText = o -> ({
    string: o -> o,
    array: o -> o.map(getInnerText).join(""),
    object: o -> getInnerText(o["childNodes"])
}[ typeis o ] || (->null) )(o);

3
Đó là cách Python có được mà không có câu lệnh chuyển đổi.
outis

2
Vấn đề là nó luôn luôn đánh giá tất cả các trường hợp.
Kornel

@yheL điều này đúng, nhưng nó mang lại một số lợi ích: Nó sạch hơn về mặt logic: Các trường hợp là các chuỗi được tra cứu trên một hashtable, không phải là các biểu thức mà mỗi cái phải được đánh giá cho bằng nhau cho đến khi một giá trị trở lại đúng. Vì vậy, trong khi nhiều "giá trị" được ước tính, thì ít "khóa" hơn được ước tính. Các đối tượng có thể được tạo động và sửa đổi để có khả năng mở rộng sau này, được phản ánh để in UI hoặc tạo tài liệu và thậm chí được thay thế bằng chức năng "tra cứu" động, tốt hơn so với các trường hợp sao chép / dán. Không có sự nhầm lẫn về phá vỡ, thông qua hoặc giá trị mặc định. Có thể được tuần tự hóa JSON ...
Breton

@yheL oh yeah, và một lần nữa cho điều có khả năng mở rộng, một đối tượng thậm chí có thể dễ dàng được đưa vào một tệp cấu hình hoặc dữ liệu bên ngoài, một sự thay đổi đơn giản hơn so với câu lệnh chuyển đổi - Nhưng tầm thường nếu được thiết kế với một đối tượng trong tâm trí với.
Breton

Tôi biết đây là một mục muộn, nhưng trừ khi bạn có một số logic kiểm tra loại tùy chỉnh, khi nào thì một mảng sẽ hoạt động với ví dụ của bạn? var arr = []; typeof arr; // object
keeganwatkins

25

Hãy chắc chắn sử dụng phương thức hasOwnProperty khi lặp qua các thuộc tính của đối tượng:

for (p in anObject) {
    if (anObject.hasOwnProperty(p)) {
        //Do stuff with p here
    }
}

Điều này được thực hiện để bạn sẽ chỉ truy cập các thuộc tính trực tiếp của anObject và không sử dụng các thuộc tính nằm dưới chuỗi nguyên mẫu.


23

Biến riêng với Giao diện chung

Nó sử dụng một mẹo nhỏ gọn gàng với định nghĩa chức năng tự gọi. Mọi thứ bên trong đối tượng được trả về đều có sẵn trong giao diện công cộng, trong khi mọi thứ khác là riêng tư.

var test = function () {
    //private members
    var x = 1;
    var y = function () {
        return x * 2;
    };
    //public interface
    return {
        setx : function (newx) {
            x = newx;
        },
        gety : function () {
            return y();
        }
    }
}();

assert(undefined == test.x);
assert(undefined == test.y);
assert(2 == test.gety());
test.setx(5);
assert(10 == test.gety());

1
đây được gọi là mẫu mô-đun, như được đặt tên bởi Eric Miraglia tại yuiblog.com/blog/2007/06/12/module-potype Tôi nghĩ rằng tên này là sai lệch, nên được gọi là Mẫu Singleton hoặc đại loại như thế. Tôi cũng có thể thêm rằng các phương thức công khai cũng có thể gọi các phương thức công khai khác bằng cách sử dụng đối tượng 'this'. Tôi sử dụng mẫu này mọi lúc trong mã của mình để giữ mọi thứ ngăn nắp và sạch sẽ.
mikeycgto
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.