2013-03-02 144 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