Attributes in Functions - JavaScript

0

I was noticing that $ of jQuery is a function, but if I do $. I can access several other functions, which are attributes of the $ function. How can a function have attributes that are accessible out of context through . ?

    
asked by anonymous 11.07.2018 / 00:20

2 answers

2

If you do this will work:

function Guilherme() {
    console.log('Chamou o Foo');
}

Guilherme.falar = function (msg) {
     console.log('Guilherme diz:', msg);
};

Guilherme();

Guilherme.falar('olá mundo');
Guilherme.falar('Tchau!');

This is because when you use the expression function JavaScript creates an object, JavaScript is practically all accessible as an object (later I will improve that part of the explanation).

You can also create a simple object with prototype would be like classes in other languages (I will not talk about ES6 now because it will escape the intention of the question), for example an example of a "jQuery own yours", like this:

(function () {
    function $(seletor) {
       //Checa se é um objeto
       if (this instanceof $) {
           this.elementos = document.querySelectorAll(seletor);
           this.length = this.elementos.length;
       } else {
          //Se chamar 'new $' vai direto, se chamar $() então a propria função instancia o objeto e retorna ele
          return new $(seletor);
       }
    }

    $.prototype = {
        "length": 0,
        "html": function () {
             if (this.length) return this.elementos[0].innerHTML;
        },
        "text": function () {
             if (this.length) return this.elementos[0].textContent;
        }
    };

    window.$ = $;
})();

console.log("html retornado:", $("#test").html() );
console.log("texto retornado:",  $("#test").text() );
<div id="test">
Olá mundo <b>novo</b>!
</div>
If you want to "extend" existing object types, such as String or Number , you can use .prototype , so you have access to this and you can get the value:

String.prototype.foobar = function () {
     console.log('String.foobar pegou:', this);
};

Number.prototype.foobar = function () {
     console.log('Number.foobar pegou:', this);
};

var testestr = "exemplo de string";
var testenum = 2018;

testestr.foobar();
testenum.foobar();
    
11.07.2018 / 04:09
1

In JavaScript functions have similarities to objects. The word "attributes" is not correct here, but "properties", and therefore functions can have properties that in case they are functions are called "methods".

So you can create a function with whatever name you want, including the name of $ as jQuery did. You can then add properties or methods to that specific function (to that specific instance) or the prototype of a function, which makes these methods and properties available to all functions of that prototype.

Look at the example where I create two functions, and different ways of adding properties and adding properties "globally" to all functions

// declaração da função
function $_$(seletor) {
  return [...document.querySelectorAll(seletor)];
}

// declaração de outra função
function qqCoisa() {
  return 'Qualquer coisa...';
}

// adicionar uma propriedade à instância
$_$.descricao = 'Uma função minha...';

console.log($_$.descricao); // Uma função minha...
console.log(qqCoisa.descricao); // "undefined" - nada, esta função não tem esta propriedade

Function.prototype.metodoGlobal = function() {
  return 'Eu sou global...';
}

console.log($_$.metodoGlobal()); // Eu sou global...
console.log(qqCoisa.metodoGlobal()); // Eu sou global...

What happens in jQuery is that you create a single, more specific instance that receives a series of methods. And to be able to have the internal context (use this and give you values that only affect that instance) you have to use the new function constructor.

Example:

const $_$ = (function() {

  // defenição da função principal que retorna a instância para se poder usar outros métodos encadeados
  function $_$_proto(seletor) {
    this.conteudo = [...document.querySelectorAll(seletor)];
    return this;
  }

  // um método adicionado ao protótipo para que todas as intâncias venham com ele
  $_$_proto.prototype.buscarTags = function() {
    return this.conteudo.map(el => el.tagName.toLowerCase());
  }

  // a função "fábrica" que retorna uma nova instância (com o seu "this" único) para se poder consumir
  return function(seletor) {
    return new $_$_proto(seletor);
  }
})();


console.log($_$('.teste').buscarTags()); // ["div", "p"]
<div class="teste">Uma div</div>
<p class="teste">Um p</p>
    
11.07.2018 / 09:17