Helpex - Trao đổi & giúp đỡ Đăng nhập
49

// bad
class Listing extends React.Component {
  render() {
    return <div>{this.props.hello}</div>;
  }
}

// bad (relying on function name inference is discouraged)
const Listing = ({ hello }) => (
  <div>{hello}</div>
);

// good
function Listing({ hello }) {
  return <div>{hello}</div>;
}

Điều này được lấy từ hướng dẫn phong cách phản ứng Airbnb. Ai đó có thể vui lòng giải thích tại sao "dựa vào suy luận tên hàm không được khuyến khích"? Nó chỉ là một mối quan tâm về phong cách?

49 hữu ích 4 bình luận 8.6k xem chia sẻ
33

Tôi nghĩ rằng điều này cũng có thể liên quan đến hành vi không mong muốn mà bạn có thể gặp phải khi ngầm đặt một cái tên từ vựng cho những gì bạn có thể mong đợi là một hàm ẩn danh.

Ví dụ, ai đó đã hiểu chức năng mũi tên:

(x) => x+2;

Để có hàm thông thường tương đương:

function(x) {
  return x+2;
}

Sẽ khá dễ dàng để mong đợi mã này:

let foo = (x) => x+2;

Sau đó tương đương với:

let foo = function(x) {
  return x+2;
}

Trường hợp hàm vẫn ẩn danh và sẽ không có khả năng tự tham chiếu để thực hiện những việc như đệ quy.

Vì vậy, nếu sau đó, trong sự ngu dốt hạnh phúc của chúng tôi, chúng tôi đã có một cái gì đó như thế này xảy ra:

let foo = (x) => (x<2) ? foo(2) : "foo(1)? I should be a reference error";
console.log(foo(1));

Nó sẽ chạy thành công vì chức năng đó rõ ràng không phải là ẩn danh:

let foo = function foo(x) {
  return (x<2) ? foo(2) : "foo(1)? I should be a reference error";
}  

Điều này có thể trở nên trầm trọng hơn bởi thực tế là trong các tình huống khác mà Babel ngầm thêm tên vào các hàm ẩn danh, (mà tôi nghĩ thực sự là một chút tác dụng phụ của việc hỗ trợ các tên hàm ngầm ngay từ đầu, mặc dù tôi có thể sai trên đó), họ xử lý chính xác mọi trường hợp cạnh và ném lỗi tham chiếu vào nơi bạn mong đợi.

Ví dụ:

let foo = {
  bar: function() {}
} 

// Will surprisingly transpile to..

var foo = {
  bar: function bar() {}
}; 


// But doing something like:

var foo = {
  bar: function(x) {
    return (x<2) ? bar(2) : 'Whats happening!?';
  }
}

console.log(foo.bar(1));

// Will correctly cause a ReferenceError: bar is not defined

Bạn có thể kiểm tra 'chế độ xem đã biên dịch' trên DEMO nhanh này để xem cách Babel thực sự chuyển ngữ để duy trì hoạt động của một hàm ẩn danh.


Tóm lại, rõ ràng với những gì bạn đang làm thường là một ý tưởng hay vì bạn biết chính xác những gì mong đợi từ mã của mình. Không khuyến khích việc sử dụng cách đặt tên hàm ngầm có thể là một lựa chọn theo phong cách để hỗ trợ điều này trong khi vẫn ngắn gọn và dễ hiểu.

Và có lẽ là cẩu. Nhưng này, chuyến đi vui vẻ.

33 hữu ích 0 bình luận chia sẻ
25

CHỈNH SỬA # 2: Tìm thấy lý do AirBnbs trong hướng dẫn kiểu Javascript của họ

Đừng quên đặt tên cho biểu thức - các hàm ẩn danh có thể khiến việc xác định vấn đề khó khăn hơn trong ngăn xếp lệnh gọi của Lỗi ( Thảo luận )

Câu trả lời gốc bên dưới

MDN có một bản tóm tắt tốt về cách hoạt động của suy luận tên hàm , bao gồm hai cảnh báo:

Quan sát

<function>.namehành vi suy luận không chuẩn trong hai trường hợp sau:

  1. khi sử dụng trình thông dịch tập lệnh

Trình thông dịch tập lệnh sẽ đặt thuộc tính tên của hàm chỉ khi một hàm không có thuộc tính riêng được gọi là tên ...

  1. khi sử dụng công cụ js

Hãy cẩn thận khi sử dụng Function.name và các phép biến đổi mã nguồn, chẳng hạn như các phép biến đổi mã nguồn được thực hiện bởi trình nén JavaScript (bộ thu nhỏ) hoặc bộ obfuscators

....

Trong phiên bản không nén, chương trình chạy vào nhánh chân lý và ghi nhật ký 'foo' là một thể hiện của 'Foo' trong khi trong phiên bản nén, nó hoạt động khác và chạy vào nhánh khác. Do đó, nếu bạn dựa vào Function.name như trong ví dụ trên, hãy đảm bảo rằng đường dẫn xây dựng của bạn không thay đổi tên hàm hoặc không giả sử một hàm có một tên cụ thể.

Suy luận tên hàm là gì?

Các nametài sản trả về tên của một hàm, hoặc (trước khi triển khai ES6) một chuỗi rỗng cho các chức năng ẩn danh

function doSomething() {}

console.log(doSomething.name); // logs "doSomething"

Các hàm được tạo với cú pháp mới Hàm (...) hoặc chỉ Hàm (...) có thuộc tính tên của chúng được đặt thành một chuỗi rỗng. Trong các ví dụ sau, các hàm ẩn danh được tạo, vì vậy tên trả về một chuỗi trống

var f = function() {};
var object = {
  someMethod: function() {}
};

console.log(f.name == ''); // true
console.log(object.someMethod.name == ''); // also true

Các trình duyệt triển khai các hàm ES6 có thể suy ra tên của một hàm ẩn danh từ vị trí cú pháp của nó . Ví dụ:

var f = function() {};
console.log(f.name); // "f"

Ý kiến

Cá nhân tôi thích các hàm (mũi tên) được gán cho một biến vì ba lý do cơ bản:

Thứ nhất, tôi không bao giờ sử dụngfunction.name

Thứ hai, trộn phạm vi từ vựng của các hàm được đặt tên với phép gán có vẻ hơi lỏng lẻo:

// This...
function Blah() {
   //...
}
Blah.propTypes = {
 thing: PropTypes.string
}
// ...is the same as...
Blah.propTypes = {
 thing: PropTypes.string
}
function Blah() {
   //...
}

// ALTERNATIVELY, here lexical-order is enforced
const Blah = () => {
   //...
}
Blah.propTypes = {
    thing: PropTypes.string
}

Và thứ ba, tất cả mọi thứ đều bình đẳng, tôi thích các hàm mũi tên hơn:

  • thông báo với người đọc rằng không có this, không, argumentsv.v.
  • trông đẹp hơn (imho)
  • hiệu suất (lần cuối tôi xem xét, các hàm mũi tên nhanh hơn một chút)

CHỈNH SỬA: Ảnh chụp nhanh bộ nhớ

Tôi đang nghe Podcast và một vị khách được kể về một tình huống là anh ta phải đối mặt với những hạn chế của việc sử dụng các hàm mũi tên với cấu hình bộ nhớ, tôi cũng đã từng ở trong tình huống tương tự trước đây.

Hiện tại, ảnh chụp nhanh bộ nhớ sẽ không bao gồm tên biến - vì vậy bạn có thể thấy mình đang chuyển đổi các hàm mũi tên thành các hàm được đặt tên chỉ để kết nối với trình biên dịch bộ nhớ. Trải nghiệm của tôi khá đơn giản và tôi vẫn hài lòng với các chức năng mũi tên.

Thêm vào đó, tôi chỉ sử dụng ảnh chụp nhanh bộ nhớ một lần, vì vậy tôi cảm thấy thoải mái khi bỏ qua một số "dụng cụ" để có độ rõ ràng (chủ quan) theo mặc định.

25 hữu ích 0 bình luận chia sẻ
4

Điều này là do:

const Listing = ({ hello }) => (
  <div>{hello}</div>
);

có tên được suy ra là Danh sách, trong khi có vẻ như bạn đang đặt tên cho nó, nhưng thực ra bạn không phải:

Thí dụ

// we know the first three ways already...

let func1 = function () {};
console.log(func1.name); // func1

const func2 = function () {};
console.log(func2.name); // func2

var func3 = function () {};
console.log(func3.name); // func3

cái này thì sao?

const bar = function baz() {
    console.log(bar.name); // baz
    console.log(baz.name); // baz
};

function qux() {
  console.log(qux.name); // qux
}
4 hữu ích 5 bình luận chia sẻ
2

Như bất kỳ hướng dẫn phong cách nào khác, Airbnb's là cố vấn và không phải lúc nào cũng có lý do.

nameThuộc tính hàm không được sử dụng cho bất kỳ việc gì ngoài việc gỡ lỗi trong ứng dụng phía máy khách vì tên gốc của hàm bị mất trong quá trình rút gọn. Đối với gỡ lỗi, nó sẽ trở nên kém hiệu quả hơn nếu một hàm không có tên có ý nghĩa trong ngăn xếp cuộc gọi, vì vậy sẽ có lợi nếu giữ nguyên nó trong một số trường hợp.

Một hàm namecó cả định nghĩa hàm like function Foo = () => {}và hàm có tên biểu thức giống như một mũi tên trong const Foo = () => {}. Điều này dẫn đến Foohàm có một tên nhất định Foo.name === 'Foo',.

Một số transpilers tuân theo đặc điểm kỹ thuật. Babel chuyển mã này thành ES5:

var Foo = function Foo() {};

Và TypeScript phá vỡ đặc điểm kỹ thuật:

var Foo = function () {};

Điều này không có nghĩa là biểu thức hàm được đặt tên là xấu và nên được khuyến khích. Miễn là một bộ chuyển tiếp tuân theo thông số kỹ thuật hoặc tên hàm không quan trọng, mối quan tâm này có thể được loại bỏ.

Vấn đề này có thể áp dụng cho các ứng dụng đã chuyển đổi. Nó phụ thuộc vào một bộ chuyển tiếp đang được sử dụng và sự cần thiết để giữ nametài sản chức năng . Vấn đề không tồn tại trong ES6 bản địa.

2 hữu ích 0 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ javascript reactjs ecmascript-6 eslint airbnb , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading