2015-02-08 17 views
5

Cố gắng lấy mức trung bình của một mảng.Tại sao hàm trung bình giảm của tôi trả về NaN?

Array.prototype.average = function() { 
    var sum = 0; 
    this.reduce(function(a, b) { 
     sum = a + b; 
    }); 
    return sum/this.length; 
}; 

[2, 15, 7].average(); 

Tại sao average gọi lại trả lời NaN?

+1

Từ mã của bạn, người ta sẽ cho rằng bạn đang nhắm mục tiêu một trình duyệt hiện đại. Tôi sẽ đề nghị sử dụng 'Object.defineProperty' để mở rộng' Array.prototype'. (và thử nghiệm rằng phương thức không tồn tại trước tiên). Bạn thậm chí có thể làm cho mã chung chung hơn để làm việc '(gọi/áp dụng)' với các đối tượng khác. – Xotic750

Trả lời

10

Chương trình của bạn không hoạt động vì, a có giá trị tích lũy từ cuộc gọi hàm trước đó. Lần đầu tiên, hai giá trị đầu tiên của mảng sẽ được sử dụng. Vì vậy, sum sẽ trở thành 17 (2 + 15). Vì bạn không trả lại bất cứ thứ gì từ hàm này, theo mặc định, undefined sẽ được trả lại và sẽ được sử dụng làm giá trị cho a, trong cuộc gọi tiếp theo. Vì vậy, việc đánh giá đi như thế này

a: 2,   b: 15 => 17 
a: undefined, b: 7 => NaN 

Vì vậy, sum sẽ có NaN, vì undefined + 7 làm cho nó như vậy. Bất kỳ thao tác số nào trên NaN, sẽ luôn cung cấp NaN, đó là lý do tại sao NaN/this.length, cung cấp cho bạn NaN. Bạn có thể sửa chương trình của mình, chỉ bằng cách trả về giá trị hiện tại của sum bất cứ khi nào hàm được gọi, để cuộc gọi hàm tiếp theo, a sẽ có giá trị tích lũy thích hợp.

Array.prototype.average = function() { 
    var sum = 0; 
    this.reduce(function(a, b) { 
     sum = a + b; 
     return sum; 
    }); 
    return sum/this.length; 
}; 

Nhưng chúng tôi không tận dụng sức mạnh và tính linh hoạt của reduce tại đây. Dưới đây là hai điểm quan trọng cần xem xét khi sử dụng reduce.

  1. reduce chấp nhận tham số thứ hai cho biết giá trị ban đầu sẽ được sử dụng. Bất cứ khi nào có thể, hãy xác định điều đó.

  2. Tham số đầu tiên trong hàm được chuyển đến reduce tích lũy kết quả và cuối cùng sẽ được trả lại, hãy tận dụng điều đó. Không cần phải sử dụng một biến riêng biệt để theo dõi kết quả.

Vì vậy, mã của bạn sẽ trông tốt hơn như thế này

Array.prototype.average = function() { 

    var sum = this.reduce(function(result, currentValue) { 
     return result + currentValue 
    }, 0); 

    return sum/this.length; 

}; 

console.log([2, 15, 7].average()); 
# 8 

reduce thực sự hoạt động như thế này. Nó lặp qua mảng và chuyển giá trị hiện tại làm tham số thứ hai cho hàm và kết quả được tích lũy hiện tại làm tham số đầu tiên và giá trị được trả về từ hàm sẽ được lưu trữ trong giá trị tích lũy.Vì vậy, số tiền thực sự tìm thấy như thế này

result: 0 , currentValue: 2 => 2 (Initializer value `0`) 
result: 2 , currentValue: 15 => 17 
result: 17, currentValue: 7 => 24 

Kể từ khi nó chạy ra các giá trị từ mảng, 24 sẽ được trả lại như là kết quả của reduce, đó sẽ được lưu trữ trong sum.

6

hàm addition ẩn danh của bạn không trả lại bất kỳ giá trị, reduce làm việc với chức năng mà trả về một giá trị:

Hãy thử:

Array.prototype.average = function() { 
    var sum = this.reduce(function (a, b) { 
     return a + b; 
    }, 0); 
    return sum/this.length; 
}; 

khả năng khác là mảng của bạn có chứa các chuỗi thay vì con số, do đó bạn có thể muốn ép chúng thành các số với return (+a) + (+b); như thể bạn có "10.0""20.0", việc thêm chúng lại với nhau cung cấp cho "10.020.0", được chia cho bất kỳ số nào một lần nữa cho số NaN.

1

Bất kỳ giá trị nào được trả lại từ giảm, nó trở thành thông số đầu tiên trong cuộc gọi tiếp theo, vì vậy bạn phải trả lại một cái gì đó. Ngoài ra, nếu bạn đang mở rộng nguyên mẫu về mục đích, hãy đảm bảo kiểm tra sự tồn tại trước tiên để bạn không ghi đè phương pháp của người khác.

Không cần phải tạo bất kỳ biến nào khác trong phần thân hàm vì tất cả có thể được thực hiện trong một dòng.

if(!Array.prototype.average) { 
    Array.prototype.average = function() { 
    return this.reduce(function(a, b){ return a + b; })/this.length; 
    }; 
} 

Cũng lưu ý rằng tham số thứ hai của giảm không hữu ích khi tính tổng số, không tổng hợp chính xác một tập hợp số.

Có biết thêm về MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

2

Bạn đã có câu trả lời cho câu hỏi của bạn được cung cấp bởi những người khác, nhưng tôi đã nghĩ tôi chỉ muốn mở rộng trên bình luận của tôi với một ví dụ.

if (!Array.prototype.average) { 
 
    Object.defineProperty(Array.prototype, 'average', { 
 
     value: function() { 
 
      if (typeof this === 'undefined' || this === null) { 
 
       throw new TypeError('Cannot convert argument to object'); 
 
      } 
 

 
      var object = Object(this); 
 

 
      return [].reduce.call(object, function (result, currentValue) { 
 
       return +(currentValue) + result; 
 
      }, 0)/object.length; 
 
     } 
 
    }); 
 
} 
 

 
var out = document.getElementById('out'); 
 

 
out.textContent += [2, 15, 7].average() + '\n'; 
 
out.textContent += [].average.call({ 
 
    0: '2', 
 
    1: '15', 
 
    2: '7', 
 
    length: 3 
 
}) + '\n'; 
 
out.textContent += [].average.call('123') + '\n';
<pre id="out"></pre>

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