Javascript 函数对象的属性

IT技术 javascript oop prototype prototypal-inheritance
2021-01-30 13:31:20

我有一个 JavaScript 函数对象;

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

现在,如果我尝试访问

addNum.divide()

我想了解上述代码的原型链。我在上面的例子中读到,addNum 将搜索divide(),然后是Function.prototype,最后是Object.prototype。

但我的问题是在上面的例子中,如何在 addNum 中搜索divide()

它是指类似的东西吗?

var addNum = function(num1, num2) {

this.divide = function(){}

            return num1 + num2;
    }

我无法理解它说 addNum 将被搜索divide() 的那一行

请帮助我理解相同。

5个回答

我不确定这会回答你的问题,但可能会给你一些见解。考虑以下示例:

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”属性,它是一个函数。在 OOP 方面,您几乎可以将其视为可以直接从 Person 函数 (Person.greet()) 调用的静态方法。一旦你从 Person 构造函数“实例化”了一个 person 对象,这个新对象“bob”现在从 Person.prototype 对象引用它的方法。现在当你调用 bob.greet() 时,它使用原型对象中的 greet 函数。

希望有帮助。

我喜欢这个例子,它真的很好地解释了原型继承的可能性,也许如果你再添加一点也解释了你现在也可以扩展Function构造函数来进一步展示 Javascript 的可能性和原型继承背后的想法。
2021-03-21 13:31:20
谢谢你的例子。但是为什么 Person.prototype.constructor 得到了问候,而 Person 却没有呢?如果你在控制台中输入它们
2021-04-10 13:31:20

正如您自己所说:您有一个函数object函数是 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();

在这种情况下,被引用的函数对象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

或者,也许这更清楚:方法/属性调用如何解析为 JS 中的值的简单方案:

[      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)。要知道这不是推荐的,实际上改变“原生”原型通常是不受欢迎的。仍然:

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,如果失败,它最终会抛出一个错误。

不久前,我在这个主题上发布了很长的答案:

是什么让 my.class.js 如此之快?(处理原型链)
javascript 中的对象和函数(函数回顾<=> 对象<=> 构造函数)
JavaScript 中“类”定义的这三种模式有什么区别?(更多信息,仍然)
Javascript - 动态更改函数的内容(模糊地涉及匿名函数,分配给变量和属性并更改它们的上下文)

我是第二版。
2021-04-07 13:31:20

您可以创建divide为 [sort of a]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...

但这是不可取的。最好创建一个构造函数:

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;}
   }
}

阅读的东西

不,您的最后addNum一段代码仅在您用作构造函数时才有意义

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

但是,由于函数是对象,因此以下内容是有效的:

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

在这种情况下divideaddNum它是它自身的一个属性,而不是它的一个原型的属性

是的,这是正确的。我更新了最后一句话以澄清一点。
2021-03-21 13:31:20

对原型继承的理解起初有些晦涩,但顾名思义,JavaScript 中有一些原型,Function 就是其中之一。

每当您创建一个新函数时,您都可以使用该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因为它试图在函数的直接范围内找到它。如果没有,它将转到它的原型。

希望这能更好地向你解释它。