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

У меня есть объект функции JavaScript как;

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

Теперь, если я попытаюсь получить доступ

addNum.divide()

Я хотел понять цепочку прототипов для приведенного выше кода. Я читал, что в приведенном выше примере в addNum будет выполняться поиск по разделу(), за которым следует Function.prototype и, наконец, Object.prototype.

Но мой вопрос в приведенном выше примере, как можно было бы искать addNum для разделения ()

Относится ли это к чему-то вроде ;

var addNum = function(num1, num2) {

this.divide = function(){}

            return num1 + num2;
    }

Я не мог понять строку, в которой говорится, что addNum будет искать разделитель ()

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


person copenndthagen    schedule 02.03.2013    source источник
comment
Я запускаю ваш код в Chrome, и он говорит: Uncaught TypeError: Object function (num1, num2) { return num1 + num2; } не имеет метода "разделить"   -  person andri    schedule 02.03.2013
comment
Вы уверены, что это не архитектурная проблема? На самом деле, деление не было бы дочерней функцией addNum. Скорее у них был бы родительский класс/объект, и они могли бы совместно использовать переменные и свойства и выполнять над ними математические операции?   -  person Dominic    schedule 02.03.2013
comment
Я прочитал эту строку на doctrina.org/Javascript-Objects-Prototypes.html.   -  person copenndthagen    schedule 02.03.2013
comment
Итак, то, что вы предложили, верно? var addNum = function(num1, num2) { this.divide = function(){} return num1 + num2; } Думаю, да?   -  person Weishi Z    schedule 10.05.2016


Ответы (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 (Person.greet()). Как только вы «создаете экземпляр» объекта person из конструктора Person, этот новый объект «bob» теперь ссылается на свои методы из объекта Person.prototype. Теперь, когда вы вызываете bob.greet(), он использует функцию приветствия в объекте-прототипе.

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

person Keith Morris    schedule 02.03.2013
comment
Мне нравится этот пример, он действительно хорошо объясняет возможности наследования прототипов, возможно, если бы вы добавили еще один фрагмент, который также объясняет, что теперь вы также можете расширить конструктор Function, чтобы еще больше показать возможности Javascript и идею наследования прототипов. - person gmaliar; 02.03.2013
comment
спасибо за пример. но почему Person.prototype.constructor получает приветствие, а Person нет, пожалуйста? если вы наберете их в консоли - person Martian2049; 09.03.2018

Как вы сами сказали: у вас есть функция 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 (резюме функций ‹=> объекты ‹=> конструкторы)
В чем разница между этими тремя шаблонами определений классов в JavaScript? (еще немного информации)
Javascript — динамическое изменение содержимого функции (смутно затрагивает анонимный функции, присваиваемые переменным и свойствам и изменяющие их контекст)

person Elias Van Ootegem    schedule 02.03.2013
comment
I Второе изд. - person The Dembinski; 24.02.2017

Вы можете создать 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...

Но это не рекомендуется. Лучше создайте функцию конструктора:

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

Чтение

person KooiInc    schedule 02.03.2013

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

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

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

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

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

person Fabian Schmengler    schedule 02.03.2013
comment
Да все верно. Я обновил последнее предложение, чтобы немного пояснить его. - person Fabian Schmengler; 02.03.2013

Понимание прототипного наследования поначалу несколько неясно, но подумайте об этом, как следует из названия, в 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, потому что он пытается найти его в непосредственной области действия функции. Если нет, то он перейдет к его прототипу.

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

person gmaliar    schedule 02.03.2013