kiểm tra lỗi typeof trong JS


153

Trong JS, dường như không thể kiểm tra xem một đối số được truyền cho hàm có thực sự thuộc loại 'lỗi' hoặc một trường hợp Lỗi không.

Ví dụ: điều này không hợp lệ:

typeof err === 'error'

vì chỉ có 6 loại có thể (ở dạng chuỗi):

Toán tử typeof trả về thông tin kiểu dưới dạng chuỗi. Có sáu giá trị có thể typeoftrả về:

"số", "chuỗi", "boolean", "đối tượng", "hàm" và "không xác định".

MSDN

Nhưng nếu tôi có một trường hợp sử dụng đơn giản như thế này:

function errorHandler(err) {

    if (typeof err === 'error') {
        throw err;
    }
    else {
        console.error('Unexpectedly, no error was passed to error handler. But here is the message:',err);
    }
}

Vì vậy, cách tốt nhất để xác định xem một đối số có phải là một trường hợp Lỗi không?

là người instanceofđiều hành của bất kỳ trợ giúp?


10
Có, sử dụngerr instanceof Error
colecmc

2
@colecmc sẽ không có vấn đề gì nếu lỗi có thể xuất phát từ mã trong khung hoặc cửa sổ khác? Trong trường hợp đó, sẽ có các đối tượng Lỗi nguyên mẫu khác nhau và instanceof sẽ không hoạt động như mong đợi. (xem developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
mẹo

@Doin, tôi không nghĩ vậy. Nó sẽ chỉ xác nhận các đối tượng lỗi thực tế.
colecmc

1
@colecmc, tôi nghĩ bạn sẽ thấy rằng nếu bạn đã ném errvào (giả sử) một iframe, nhưng sau đó chuyển nó đến cửa sổ cha mẹ để bàn giao, bạn sẽ nhận được (err instanceof Error) === false. Đó là bởi vì iframe và cửa sổ cha của nó có các Errornguyên mẫu đối tượng khác nhau, khác biệt . Tương tự như một đối tượng như obj = {};ý muốn , khi được chuyển đến một chức năng đang chạy trong một cửa sổ khác, tức là (obj instanceof Object)===false. (Thậm chí tệ nhất, trong IE, nếu bạn giữ một tham chiếu đến obj sau khi cửa sổ của nó bị phá hủy hoặc điều hướng, cố gắng gọi nguyên mẫu đối tượng fns như obj.hasOwnProperty()sẽ ném lỗi!)
Doin

Làm thế nào để bạn kiểm tra các loại lỗi tho? tức là catch((err)=>{if (err === ENOENT)trả về ENOENT is not definedlỗi?
oldboy

Câu trả lời:


261

Bạn có thể sử dụng instanceoftoán tử (nhưng xem cảnh báo bên dưới!).

var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

Ở trên sẽ không hoạt động nếu lỗi được ném vào một cửa sổ / khung / iframe khác với nơi kiểm tra đang xảy ra. Trong trường hợp đó, instanceof Errorkiểm tra sẽ trả về false, ngay cả đối với một Errorđối tượng. Trong trường hợp đó, cách tiếp cận dễ nhất là gõ vịt.

if (myError && myError.stack && myError.message) {
  // it's an error, probably
}

Tuy nhiên, gõ vịt có thể tạo ra dương tính giả nếu bạn có các đối tượng không có lỗi có chứa stackmessagethuộc tính.


1
@ AurélienRibon Nó hoạt động tốt với một ReferenceErrorví dụ. Bạn đang kiểm tra ReferenceErrorđối tượng toàn cầu . Hãy thử điều này: try { foo } catch (e) { console.log(e instanceof Error) }Nó đăng nhập true. Nếu bạn đang cố kiểm tra ReferenceErrorđối tượng toàn cầu vì một số lý do, bạn có thể sử dụngError.isPrototypeOf(ReferenceError)
Trott

1
@ AurélienRibon (Uh, đồng thời, vâng, không chắc chắn nếu bạn nói "Điều này sẽ không hoạt động với ReferenceError" không chính xác hoặc nếu bạn chỉ chỉ ra "Điều này sẽ không hoạt động với đối tượng ReferenceError toàn cầu" Điều này hoàn toàn chính xác, mặc dù tôi đang gặp khó khăn khi đưa ra một tình huống mà người ta sẽ kiểm tra điều đó, nhưng điều đó có thể nói nhiều hơn về sự thiếu trí tưởng tượng của tôi hơn là tính hợp lệ của trường hợp sử dụng).
Trott

Haha, xin lỗi về những kẻ đó, tôi đã bị mắc một lỗi lạ trong đó tất cả các ReferenceErrortrường hợp của tôi không phải là trường hợp Error. Điều này là do một cuộc gọi đến vm.runInNewContext()trong nút, nơi tất cả các nguyên mẫu chuẩn được xác định lại. Tất cả các kết quả của tôi không phải là trường hợp của các đối tượng tiêu chuẩn. Tôi đã tìm kiếm trong SO về điều này, và rơi vào chủ đề này :)
Aurelien Ribon

1
Bạn có thể thửconst error = (err instanceof Error || err instanceof TypeError) ? err : new Error(err.message ? err.message : err);
Aamir Afridi

Làm thế nào để bạn kiểm tra nếu nó là instanceofmột loại lỗi cụ thể tho?
oldboy

25

Tôi đã hỏi câu hỏi ban đầu - câu trả lời của @ Trott chắc chắn là tốt nhất.

Tuy nhiên, với JS là một ngôn ngữ động và có quá nhiều môi trường thời gian chạy JS, instanceoftoán tử có thể thất bại đặc biệt là trong phát triển front-end khi vượt qua các ranh giới như iframe. Xem: https://github.com/mrdoob/three.js/issues/5886

Nếu bạn ổn với việc gõ vịt, điều này sẽ tốt:

let isError = function(e){
 return e && e.stack && e.message;
}

Cá nhân tôi thích các ngôn ngữ gõ tĩnh, nhưng nếu bạn đang sử dụng ngôn ngữ động, tốt nhất nên nắm lấy ngôn ngữ động cho ngôn ngữ đó, thay vì buộc nó hoạt động như ngôn ngữ gõ tĩnh.

nếu bạn muốn chính xác hơn một chút, bạn có thể làm điều này:

   let isError = function(e){
     return e && e.stack && e.message && typeof e.stack === 'string' 
            && typeof e.message === 'string';
    }

3
Tôi thích phiên bản này khi viết một chức năng tiện ích hoặc thư viện. Nó không ràng buộc người dùng vào một bối cảnh toàn cầu cụ thể và cũng xử lý đúng các lỗi được khử lưu từ JSON.
cười khúc khích

cảm ơn, vâng trong nhiều trường hợp, nếu nó có vẻ như là một lỗi, chúng ta có thể coi như là một lỗi. trong một số trường hợp, gõ vịt là hoàn toàn chấp nhận được, trong một số trường hợp không thể chấp nhận được, trong trường hợp này, hoàn toàn ổn.
Alexander Mills

Tôi đã thực hiện một số gỡ lỗi bằng cách sử dụng trình gỡ lỗi, và ngăn xếp và thông báo thực sự có vẻ là hai thuộc tính không phải gốc trong các trường hợp Lỗi.
Alexander Mills

1
@Trott bạn có thể muốn biết về lỗi instanceofvận hành trong một số trường hợp, xem bài viết được liên kết.
Alexander Mills

1
Đây thực sự là đơn giản nhất để nó hoạt động với các loại lỗi khác nhau (ví dụ Error, ReferenceError...). Và trong môi trường của tôi, sự instanceofthất bại thảm hại trong nhiều hoàn cảnh.
Alexis Wilke

10
var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

Chỉ có vấn đề với điều này là

myError instanceof Object // true

Một thay thế cho điều này sẽ là sử dụng thuộc tính constructor.

myError.constructor === Object // false
myError.constructor === String // false
myError.constructor === Boolean // false
myError.constructor === Symbol // false
myError.constructor === Function // false
myError.constructor === Error // true

Mặc dù cần lưu ý rằng trận đấu này rất cụ thể, ví dụ:

myError.constructor === TypeError // false

2

Bạn có thể sử dụng Object.prototype.toStringđể dễ dàng kiểm tra nếu một đối tượng là một Error, nó cũng sẽ hoạt động cho các khung khác nhau.

function isError(obj){
    return Object.prototype.toString.call(obj) === "[object Error]";
}

function isError(obj){
    return Object.prototype.toString.call(obj) === "[object Error]";
}
console.log("Error:", isError(new Error));
console.log("RangeError:", isError(new RangeError));
console.log("SyntaxError:", isError(new SyntaxError));
console.log("Object:", isError({}));
console.log("Array:", isError([]));


1

Bạn có thể sử dụng obj.constructor.name để kiểm tra "lớp" của một đối tượng https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Feft_names_in_VELes

Ví dụ

var error = new Error("ValidationError");
console.log(error.constructor.name);

Dòng trên sẽ ghi "Lỗi" là tên lớp của đối tượng. Điều này có thể được sử dụng với bất kỳ lớp nào trong javascript, nếu lớp đó không sử dụng thuộc tính có tên "name"


Điều này không đáng tin cậy khi rút gọn mã và sử dụng các lớp con lỗi
felixfbecker

1

Cảm ơn @Trott cho mã của bạn, tôi chỉ sử dụng cùng một mã và thêm vào một ví dụ làm việc theo thời gian thực vì lợi ích của người khác.

<html>
<body >

<p>The **instanceof** operator returns true if the specified object is an instance of the specified object.</p>



<script>
	var myError = new Error("TypeError: Cannot set property 'innerHTML' of null"); // error type when element is not defined
	myError instanceof Error // true
	
	
	
	
	function test(){
	
	var v1 = document.getElementById("myid").innerHTML ="zunu"; // to change with this
	
	try {
		  var v1 = document.getElementById("myidd").innerHTML ="zunu"; // exception caught
		  } 
		  
	catch (e) {
		  if (e instanceof Error) {
			console.error(e.name + ': ' + e.message) // error will be displayed at browser console
		  }
  }
  finally{
		var v1 = document.getElementById("myid").innerHTML ="Text Changed to Zunu"; // finally innerHTML changed to this.
	}
	
	}
	
</script>
<p id="myid">This text will change</p>
<input type="button" onclick="test();">
</body>
</html>


0

Hoặc sử dụng điều này cho các loại lỗi khác nhau

function isError(val) {
  return (!!val && typeof val === 'object')
    && ((Object.prototype.toString.call(val) === '[object Error]')
      || (typeof val.message === 'string' && typeof val.name === 'string'))
}
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.