Подтвердить что ты не робот

Свойства объектов функции Javascript

У меня есть объект функции 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()

Пожалуйста, помогите мне понять то же самое.

4b9b3361

Ответ 1

Я не уверен, что это ответит на ваш вопрос, но может дать вам некоторое представление. Рассмотрим следующий пример:

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

Объект функции "Лицо" имеет прямое свойство "greet", которое является функцией. ООП-мудрый, вы можете почти думать об этом как о статическом методе, который можно вызвать непосредственно из функции Person (Person.greet()). После того как вы "экземпляр" человек объект из конструктора Person, что новый объект "боб" в настоящее время ссылается на нее методы от объекта Person.prototype. Теперь, когда вы вызываете bob.greet(), он использует функцию greet в объекте прототипа.

Надеюсь, что это поможет.

Ответ 2

Как вы сами так говорите: у вас есть функция object. Функции - это объекты в JS, как и литералы Object, массивы или что-то еще: функции могут быть присвоены свойства и методы по желанию:

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 (ну, в любом случае ссылка на анонимную функцию называлась делением). Таким образом, здесь нет никакого прототипа. Имейте в виду, как вы сами так говорите: все объекты можно проследить до 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

В обоих случаях объект функции, на который ссылается имя (someFunction или another), будет сканироваться для свойства с именем divide, которое не найдено. Затем, однако, он сканирует Function.prototype, где такое свойство найдено.
Если бы это было не так, JS также проверила бы Object.prototype, если это не сработало, оно в конечном итоге вызовет ошибку.

Я опубликовал довольно длительные ответы на SO по этому вопросу некоторое время назад:

Что делает my.class.js так быстро? (имеет дело с цепочками прототипов)
Объекты и функции в javascript (recap of functions <= > objects <= > constructors)
Каковы различия между этими тремя шаблонами класса? определения в JavaScript? (еще немного информации)
Javascript - динамически изменять содержимое функции (неопределенно затрагивает анонимные функции, связанные с переменными и свойствами и изменяя их контекст)

Ответ 3

Вы можете создать divide как метод [вид 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;}
   }
}

Чтение материала

Ответ 4

Нет, ваш последний код имеет смысл только в том случае, если вы использовали addNum как функцию конструктора:

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

Однако, поскольку функции являются объектами, было бы справедливо следующее:

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

В этом случае divide будет свойством самого addNum, а не одного из его прототипов.

Ответ 5

Чтобы понять прототипное наследование, сначала несколько неясно, но подумайте об этом, как следует из названия, в 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 и do jQuery.divide(2,1), я также получаю 2, потому что он пытается найти его в непосредственной близости от функции. Если нет, то он перейдет к прототипу.

Надеюсь, это объяснит это вам немного лучше.