What JavaScript concept allows for the same name to be both a function and an object?

£可爱£侵袭症+ 提交于 2019-12-06 15:05:44

Every JavaScript function is also an object, just as every array is also an object. I don't think there is a special name for this, it's just how the language works.

You may be confusing two different things: what a function returns when you call it, vs. the function itself. Take your example:

planetEarth().sky;  // "blue"

This code does not rely on the function planetEarth being an object and having any properties. You're calling the function, so to make this code work the function would need to return an object.

Because a function is an object, you can also set properties directly on the function itself. The code below uses both of these features. This version of planetEarth() returns an object with sky and grass properties, so it works as in your example: you call the function to get an object with those properties.

The code also sets an exists property directly on the function, and you can access that property without calling the function:

function planetEarth() {
    // Return an object when this function is called
    return {
        sky: 'blue',
        grass: 'green'
    }
}

// Set a property directly on the function itself
planetEarth.exists = true;

// Test accessing the function's property
console.log( planetEarth.exists );

// Test accessing a property in the object that the function returns when called
console.log( planetEarth().sky );

jQuery makes use of both of these facilities. jQuery is a function that you can call. It returns a value commonly called a "jQuery object". That object has properties and methods, such as jQuery('#foo').show(). It also has "array-like" properties that you can access as you would any array, e.g. jQuery('#foo').length and jQuery('#foo')[0]. The jQuery function adds those properties to the value it returns.

At the same time, the jQuery library adds other properties and methods to the jQuery function itself. You access without calling the function, e.g. jQuery.ajax({...}).

A couple of other notes to help you understand the jQuery code. First, download the uncompressed version of jQuery. It looks like you are studying the compressed version, which has shortened names that won't make any sense.

Also, if you are wondering what jQuery.fn is, it is simply an alias for jQuery.prototype. Whenever you see jQuery.fn you can mentally substitute jQuery.prototype; learn how JavaScript prototypes work and you will understand jQuery.fn.

And now you may wonder why jQuery.fn exists at all. Why not use jQuery.prototype directly like other JavaScript code that uses prototypical inheritance? In fact, you could, and it would work the same as jQuery.fn. But the very first version of jQuery, back in 2006, didn't work this way. jQuery.fn was its own separate object, and every time you called the jQuery function, it copied all of the methods and properties from this object into the value it returned.

As you can guess, this was rather inefficient, so jQuery was changed to use .prototype so it could return an object that inherits all the methods such as .show() and .hide() instead of copying them all one by one. At the same time, jQuery.fn was kept around as an alias for jQuery.prototype to avoid breaking existing code.

This is a silent answer...

function f() {
  return {};
}

console.log(typeof f, typeof f());

This is how jQuery does it. f is a function but when it gets called it returns an object.

Interesting part: function is also an object. f instanceof Function and f instanceof Object are both valid. So, you can call a variable as a function and / or assign some properties because it is also an object.

f.test = 123;

First-Class Objects

In Javascript, functions are first-class objects. This means that functions are just another kind of object. You can put a function in a variable, you can return a function, you can make an array of functions, and all that. Functions are objects.

Consider a slight change in your attempt:

//Declare a function:
function planetEarth(){
    console.log('inside of a function now');
}

// Now add fields to it, since it is also an object
planetEarth.sky = 'blue';
planetEarth.grass = 'green';

// Test stuff
planetEarth(); // works
console.log(planetEarth.sky, planetEarth.grass); // works

You mention that you would like to use planetEarth().sky, but observe that while planetEarth is a function (and an object, as I said), planetEarth() is the result of calling planetEarth with no parameters. Therefore, whether you can or can't do planetEarth().sky does not depend on planetEarth as an object having the sky field, but rather depends on whatever you return from planetEarth having that field.

Bonus: did you know that functions can be declared very much like "normal" variables? See below:

// Both lines of code below are identical:
function myFunc() { ... }
var myFunc = function() { ... };

Perhaps looking at the code above will help you clear the confusion. The function is myFunc. myFunc() is simply the act of calling that function. If typeof myFunc() gives function, it is just a coincidence that the object that myFunc returned happened to also be a function.

jQuery is a function. Properties can be assigned to a defined function.

function planetEarth(options){
    console.log('inside of a function now', options);
    return window["planetEarth"];
}

var planetEarthOptions = {
    'sky': 'blue',
    'grass': 'green'
}

for (let prop in planetEarthOptions) {
  planetEarth[prop] = planetEarthOptions[prop];
}

window["planetEarth"] = planetEarth;

planetEarth("selector");

console.log(planetEarth.sky);

console.log(planetEarth().grass);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!