2013-03-02 136 views
19

我有一個JavaScript函數對象;Javascript函數對象的屬性

var addNum = function(num1, num2) { 
     return num1 + num2; 
} 

現在,如果我嘗試訪問

addNum.divide() 

我想了解上面的代碼原型鏈。我在上面的例子中看到,addNum將被搜索divide(),接着是Function.prototype,最後是Object.prototype。

但我的問題是,在上面的例子中,如何addNum會被搜索鴻溝()

是否指的是這樣;

var addNum = function(num1, num2) { 

this.divide = function(){} 

      return num1 + num2; 
    } 

我也不懂行的,它說addNum將搜索鴻溝()

請幫助我瞭解的一樣。

+0

我在Chrome中運行代碼,它說:Uncaught TypeError:Object function(num1,num2){ return num1 + num2; }沒有方法'divide' – andri 2013-03-02 12:04:34

+0

您確定這不是一個架構問題嗎?實際上,分隔不會是addNum的子功能。相反,他們會有一個父類/對象,他們可以共享變量和屬性並對它們進行數學運算? – 2013-03-02 12:16:31

+0

我在http://doctrina.org/Javascript-Objects-Prototypes.html上讀到這一行 – testndtv 2013-03-02 12:40:33

回答

48

我不確定這會回答你的問題,但可能會給你一些見解。考慮以下示例:

var Person = (function() { 
    var Person = function (name) { 
     this.name = name; 
    } 

    Person.greet = function() { 
     console.log("Hello!"); 
    } 

    Person.prototype = { 
     greet: function() { 
      console.log('Hello, my name is ' + this.name); 
     } 
    }; 
    return Person; 
})(); 

var bob = new Person("Bob"); 

Person.greet(); // logs "Hello!" 
bob.greet(); // logs "Hello, my name is Bob 

函數對象「Person」具有一個直接的'greet'屬性,它是一個Function。 OOP明智,你幾乎可以認爲這是一個靜態方法,可以直接從Person函數(Person.greet())調用。一旦你從Person構造函數中「實例化」了一個person對象,那麼這個新對象「bob」現在就引用了它來自Person.prototype對象的方法。現在,當您調用bob.greet()時,它將使用原型對象中的問候函數。

希望有所幫助。

+0

我喜歡這個例子,它很好地解釋了原型繼承的可能性,也許如果你會添加另外一點,這也解釋了你現在也可以擴展'Function'構造函數來進一步顯示Javascript的可能性和原型背後的想法遺產。 – gmaliar 2013-03-02 12:28:25

+0

謝謝你的例子。但是爲什麼Person.prototype.constructor會得到歡迎,但Person不會呢?如果你將它們鍵入控制檯 – Martian2049 2018-03-09 11:36:54

1

不,你的最後一個代碼纔有意義,如果你使用addNum作爲一個構造函數:

var instance = new addNum(); 
instance.divide(); 

但是,因爲函數是對象,下面是有效的:

var addNum = function(num1, num2) { 
     return num1 + num2; 
} 
addNum.divide = function() {} 

在這案件divide將是addNum本身的財產,而不是其原型之一。

+0

其實我在http://doctrina.org/Javascript-Objects-Prototypes.html上閱讀了這個 – testndtv 2013-03-02 12:36:42

+0

是的,沒錯。我更新了最後一句以澄清一點。 – 2013-03-02 12:42:41

0

要理解原型繼承起初有點模糊,但認爲它顧名思義,也有JavaScript的一些原型,功能就是其中之一。

無論何時創建新函數,都可以使用typeof命令檢查其類型。你的情況:

var a = function(a,b) { return a + b; } 

它將返回"function"所以有兩種方法可以添加到您的a變量的詳細方法。就像@Keith Morris所建議的那樣,創建一個新的構造函數並將其方法返回並返回。這也是首選的方式,因爲那樣你就不會用原型方法來污染基本對象,原型方法會擴展到由它們表示的每個對象。

意義,如果我不是這樣做:

Function.prototype.divide = function(a, b) { return a/b; } 

我現在可以做a.divide(2, 1);,它會返回2。但是,例如,如果我使用jQuery並執行jQuery.divide(2,1),我還會得到2,因爲它試圖在函數的直接範圍內找到它。如果不是,它會轉到它的原型。

希望這解釋給你更好一點。

17

正如你自己所說:你有一個功能對象。函數是在JS對象,就像對象常量數組,或其他任何東西:一個功能可以分配的屬性和方法的意願:

var someAnonFunction = function(foo) 
{ 
    console.log(this); 
    console.log(this === someAnonFunction);//will be false most of the time 
}; 
someAnonFunction.x = 123;//assign property 
someAnonFunction.y = 312; 
someAnonFunction.divide = function() 
{ 
    console.log(this === someAnonFunction);//will be true most of the time 
    return this.x/this.y;//divide properties x & y 
}; 
someAnonFunction.divide(); 

在這種情況下,函數對象,通過引用已分配引用了名爲divide的匿名函數(當然,對匿名函數的引用被稱爲「鴻溝」)。所以這裏根本沒有原型參與。你要知道,你這樣自己說:所有的對象都可以追溯到Object.prototype,就試試這個:

console.log(someAnonFunction.toString === Function.prototype.toString);//functions are stringified differently than object literals 
console.log(someAnonFunction.hasOwnProperty === Object.prototype.hasOwnProperty);//true 

或者,也許這更是明確表示:方法/屬性調用是如何解析爲一個簡單的方案

[  F.divide  ]<=========================================================\ \ 
F[divide] ===> JS checks instance for property divide       | | 
/\ ||                   | | 
|| || --> property found @instance, return value-------------------------------| | 
|| ||                   | | 
|| ===========> Function.prototype.divide could not be found, check prototype | | 
||  ||                  | | 
||  ||--> property found @Function.prototype, return-----------------------| | 
||  ||                  | | 
||  ==========> Object.prototype.divide: not found check prototype?  | | 
||   ||                 | | 
||   ||--> property found @Object.prototype, return---------------------|_| 
||   ||                 |=| 
||   =======>prototype is null, return "undefined.divide"~~~~~~~~~~~~~~~|X| 
||                    \/
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< TypeError can't read property 'x' of undefined 

由此得出,如果你想上面的代碼中使用原型的工作,你必須增加一個原型各種各樣的(在這種情況下,Function.prototype):在JS的值。要知道這不是被推薦的,實際上改變「原生」的原型往往是不被接受的。仍然:

Function.prototype.divide = function (a, b) 
{ 
    a = +(a || 0);//coerce to number, use default value 
    b = +(b || 1) || 1;//division by zeroe is not allowed, default to 1 
    return a/b; 
}; 
function someFunction() 
{ 
    return 'someString'; 
}; 
var another = function(a, b) 
{ 
    return a + b; 
}; 
someFunction.divide(12, 6);//will return 2 
another.divide(12, 4);//3 

在這兩種情況下,所述功能對象,由名稱(someFunctionanother)引用將掃描名爲divide屬性,該屬性是找不到的。然後,它會掃描Function.prototype,發現這樣的屬性。
如果不是這樣,JS還會檢查Object.prototype,如果失敗了,它最終會拋出一個錯誤。

我已經發布了相當長的答案在等這個問題而回:

What makes my.class.js so fast?(與原型鏈交易)
Objects and functions in javascript(功能概括< =>對象< =>構造函數)
What are the differences between these three patterns of "class" definitions in JavaScript? (一些更多的信息,仍然)
Javascript - Dynamically change the contents of a function(隱約觸及匿名函數,分配給變量和屬性,並改變其上下文)

+3

upvote just ascii art – angabriel 2016-12-14 13:08:30

+0

I Second-ed-ed。 – 2017-02-24 00:09:35

2

您可以創建divide爲[不大不小的的] static方法:

var addNum = function(num1, num2) { 
    addNum.divide = function(){return num1/num2;}; 
    return num1 + num2; 
} 
// now you first have to run addNum 
var onethirds = addNum(1,3); //=> 4 
addNum.divide(); //=> 0.333333... 

但它是不可取的。更好地創造一個constructor功能:

function Pair(n1,n2){ 
    n1 = n1 || 1; 
    n2 = n2 || 1; 
    // create instance methods 
    this.add  = function(){return n1+n2;}; 
    this.divide = function(){return n1/n2;}; 
    this.multiply = function(){return n1*n2;} 
} 
var pair1 = new Pair(2,6) 
    ,pair2 = new Pair(1,2); 
pair1.add(); //=> 8 
pair2.divide(); //=> 0.5 
//etc. 

或多個原型方法(方法添加到構造函數的原型,而不是每個實例):

function Pair(n1,n2){ 
    this.n1 = n1 || 1; 
    this.n2 = n2 || 1; 
    // create prototype methods (once) 
    if (!Pair.prototype.add){ 
    var proto  = Pair.prototype; 
    proto.add  = function(){return this.n1+this.n2;}; 
    proto.divide = function(){return this.n1/this.n2;}; 
    proto.multiply = function(){return this.n1*this.n2;} 
    } 
} 

Reading stuff