2015-10-04 41 views
19

Tôi đang đào sâu vào chuỗi nguyên mẫu Javascript.
Để ghi lại những phát hiện của mình, tôi đã rút ra những chương trình sau đây:Function.prototype là một hàm

enter image description here

Mặc dù hầu hết các khái niệm rõ ràng, tôi là trái với chỉ hai câu hỏi liên quan. Thay vì tách chúng ra, tôi đoán rằng việc tập trung chúng vào câu hỏi này có thể tốt hơn:

  1. Có lý do nào để Function.prototype có chức năng kiểu thay vì đối tượng?
    typeof Function.prototype; //"function"
  2. Là một 'hàm duy nhất' trong JS vì nó không có đặc tính nguyên mẫu giống như các hàm khác không? (Là có một 'tên' được chấp nhận chung để chỉ nó?)
+0

thông báo rằng 'chức năng Person() {} typeof Person.prototype // "đối tượng"' – Saar

+1

chức năng cũng là đối tượng –

+2

Object.getPrototypeOf (Function.prototype) === Object.prototype –

Trả lời

18

Lý do là the ES5 spec nói như vậy:

Đối tượng Chức năng nguyên mẫu là chính nó một đối tượng Function (nó [[Lớp ]] là "Hàm", khi được gọi, chấp nhận bất kỳ đối số nào và trả về không xác định.

Lưu ý nó phổ biến trong ES5 để làm nguyên mẫu của một số lớp một thành viên của lớp đó:

Tôi nghĩ nó đã được chuẩn hóa như vậy vì nguyên mẫu của một lớp có thuộc tính nội tại của lớp đó, như là các thể hiện của lớp đó. Và nếu nó looks like a duck nó sẽ hoạt động như một con vịt. Vì vậy, việc gọi các phương thức của nguyên mẫu trên bản thân nguyên mẫu thay vì trên một cá thể cũng sẽ hoạt động.

Tuy nhiên, ES6 không thích điều này. Vì vậy, nó đã thay đổi hành vi cho những người:

  • Boolean.prototype là một đối tượng thông thường không có [[BooleanData]].
  • Error.prototype là một đối tượng thông thường không có khe cắm bên trong [[ErrorData]].
  • Number.prototype là một đối tượng thông thường không có khe cắm bên trong [[NumberData]].
  • Date.prototype là một đối tượng thông thường không có khe cắm bên trong [[DateValue]].
  • String.prototype là một đối tượng thông thường không có khe cắm bên trong [[StringData]].
  • RegExp.prototype là một đối tượng bình thường không có [[RegExpMatcher]] hay bất kỳ vị trí nội bộ nào khác của đối tượng thể hiện RegExp.

Và cũng cho "lớp học" mới (ES6 đối tượng không còn có một [[Lớp]]):

  • Symbol.prototype là một đối tượng thường không có [[SymbolData]] nội khe.
  • TypedArray.prototype là một đối tượng bình thường không có [[ViewingArrayBuffer]] hay bất kỳ vị trí nào khác của các vị trí nội bộ cụ thể đối với các đối tượng thể hiện TypedArray.
  • Map.prototype là một đối tượng thông thường không có [[MapData]] khe bên trong.
  • Set.prototype là một đối tượng thông thường không có [[SetData]] khe bên trong.
  • WeakMap.prototype là một đối tượng thông thường không có khe cắm bên trong [[WeakMapData]].
  • WeakSet.prototype là một đối tượng thông thường không có khe cắm bên trong [[WeakSetData]].
  • ArrayBuffer.prototype là một đối tượng thông thường không có [[ArrayBufferData]] cũng như [slot ArrayBufferByteLength]] bên trong.
  • DataView.prototype là một đối tượng thông thường không có [[DataView]], [[ViewingArrayBuffer]], [[ByteLength]], cũng không phải [[ByteOffset]].
  • GeneratorFunction.prototype là một đối tượng bình thường không có [[Mã ECMAScript]] hoặc bất kỳ vị trí nào khác của các khe trong được liệt kê trong Table 27 hoặc Table 56.
  • Promise.prototype là một đối tượng bình thường không có [[PromiseState]] cũng như bất kỳ vị trí nội bộ nào khác của các trường hợp Promise.

Tuy nhiên, các hành vi cũ vẫn còn đối với những người:

  • Function.prototype là chính nó một built-in đối tượng chức năng.
  • Array.prototype là một đối tượng kỳ lạ của Array và có các phương thức nội bộ được chỉ định cho các đối tượng đó.

Vì vậy bây giờ lý do là tương thích ngược:

Chức năng đối tượng nguyên mẫu được quy định là một đối tượng chức năng để đảm bảo khả năng tương thích với mã ECMAScript đã được tạo ra trước khi đặc tả ECMAScript năm 2015.

Lưu ý điều này không làm cho Function.prototype một chức năng đặc biệt. Chỉ nhà xây dựng có prototype property: trường hợp

Chức năng có thể được sử dụng như một nhà xây dựng có một tài sản prototype .

Có nhiều ví dụ về hàm phi constructor ngoài Function.prototype, chẳng hạn như

  • Methods in Math đối tượng:

    typeof Math.pow; // "function 
    'prototype' in Math.pow; // false 
    
  • Một số đối tượng chủ:

    typeof document.createElement('object'); // "function 
    'prototype' in document.createElement('object'); // false 
    
  • Trong ES6, mũi tên chức năng:

    typeof (x => x * x); // "function 
    'prototype' in (x => x * x); // false 
    
+2

Mẹ của javascript. Và khi tôi nghĩ nó không còn làm tôi ngạc nhiên nữa – slezica

2

Trong sự thay thế của một câu trả lời trước đó tôi không thể chờ đợi. Nhờ có Oriol. Đầu gãi là của tôi.

Liên quan đến câu hỏi đầu tiên, đối tượng Hàm không khác biệt đơn giản chỉ vì Function.prototype là một hàm. Xây dựng khác trong xây dựng sử dụng các đối tượng nguyên mẫu của loại hình riêng của họ. Điều thu hút sự chú ý đến trường hợp Function là toán tử typeof xử lý các đối tượng hàm một cách khác với các đối tượng khác bằng cách trả về "hàm" thay vì "đối tượng".

nhà xây dựng Toàn Cầu niêm yết mình là nhà xây dựng của các đối tượng nguyên mẫu của họ:

var BuiltIn = Function; // for example 
BuiltIn.prototype.constructor == BuiltIn // true 

là nhiều hay ít tài liệu. Các đối tượng nguyên mẫu được xây dựng trong các hàm tạo thường có các phương thức giao diện với công cụ javascript và không được tạo bằng cách sử dụng cuộc gọi javascript tới hàm tạo được liệt kê của nó khi nó xuất hiện tại thời điểm chạy: Function.prototype instanceof Function là sai với các kết quả tương tự cho các hàm dựng khác như Array, RegExp vv thử nghiệm.

Đối tượng Function toàn cầu là duy nhất, tuy nhiên, ở chỗ nó liệt kê chính nó như là nhà xây dựng riêng của mình (Function.constructor == Function là đúng), và rằng nó là một thể hiện của mình (Function instanceof Function cũng đúng). Kết quả sau chỉ ra rằng Function.prototype nằm trong chuỗi nguyên mẫu của Function. Function.prototype chính nó được tạo mẫu trên Object.prototype. Một lý do khác để suy nghĩ Function.prototype không phải là một đối tượng chức năng theo nghĩa thông thường (ngoài việc nói như vậy trong tài liệu) là nó không thể được gọi là một nhà xây dựng và ném một lỗi nếu một nỗ lực được thực hiện để làm như vậy. Quay trở lại Vì đặc tính nguyên mẫu của một hàm được sử dụng khi hàm được gọi là hàm tạo nên nó có ý nghĩa đối với Function.prototype không có thuộc tính này.

5

Trong câu trả lời cho câu hỏi của bạn:

1)Function.prototype là một loại chức năng bởi vì, theo ECMAScript 2015:

Đối tượng Chức năng nguyên mẫu là bản chất đối tượng% FunctionPrototype%. Đối tượng nguyên mẫu Function là chính nó là một đối tượng hàm dựng sẵn.

Đối tượng mẫu chức năng được xác định là đối tượng hàm để đảm bảo tính tương thích với mã ECMAScript được tạo trước thông số ECMAScript 2015.

Vì vậy, đối tượng mẫu Chức năng chỉ được định nghĩa là đối tượng Hàm để đảm bảo khả năng tương thích với các tiêu chuẩn ECMAScript cũ hơn. Hàm này không thực sự làm bất cứ điều gì:

Khi được gọi, hàm chấp nhận bất kỳ đối số nào và trả về không xác định.

http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-function-prototype-object

2) Về thuộc tính prototype:

Chức năng đối tượng nguyên mẫu không có một thuộc tính prototype.

Same Source

này là duy nhất vì tất cả các chức năng thường có một tài sản prototype, tuy nhiên kể từ khi đối tượng Function nguyên mẫu được chỉ định như một đối tượng Chức năng để duy trì khả năng tương thích, đó là hành vi không giống như rằng các chức năng thông thường.

Tôi đã tạo một JSFiddle với các xét nghiệm khác nhau trong trường hợp nó giúp mọi người:

http://jsfiddle.net/Ld0b39xz/

// We'll use 'Object.getPrototypeOf' to access [[prototype]] 

// As you know, [[prototype]] of Object.prototype returns 'null'. 
console.log(Object.getPrototypeOf(Object.prototype)); 
// null 

//////////////////////////////////////////////////////// 

// Let's take a closer look at Function.prototype 
console.log(Function.prototype); 
// Output: 
// function(){} 

// This is what the specs say should happen: 
// "The Function prototype object is itself a built-in function object." 

///////////////////////////////////////////////////// 

// Let's see if this function has a 'prototype' property. 
// All functions normally have a prototype property that initially 
// references an empty object...except this one. 
var fn = Function.prototype; 
console.log(fn.prototype); 
// Output: 
// undefined 

// This is expected, according to the specs: 
// "The Function prototype object does not have a prototype property." 

// It does have some properties such as 'name' and 'length', 
// but not 'prototype'. 

//////////////////////////////////////////////////////// 

// Let's see what [[prototype]] of Function.prototype returns. 
console.log(Object.getPrototypeOf(Function.prototype)); 
// Output: 
// Object{} 

// Again this is expected: 
// "The value of the [[Prototype]] internal slot of the 
// Function prototype object is the intrinsic object %ObjectPrototype%" 

///////////////////////////////////////////////////////// 

// Now lets see what the [[Prototype]] of this object is: 
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function.prototype))); 
// Output: 
// null 

// We've come full circle since all the statement above is 
// doing is looking for the prototoype of the native Object, 
// which we already know is 'null' from our first test. 
Các vấn đề liên quan