什么JavaScript概念允许同一个名称既是函数又是对象?

时间:2018-01-27 19:08:24

标签: javascript javascript-objects

我已经在网页设计/开发中使用了几年JavaScript,而且我所知道的一切都是自学成才的(我是一名设计专业和业余爱好者前锋让我成为追求我的全面开发人员事业)。在这样的背景下,我发现了一些我想要了解的东西,并且不知道它叫什么,它是如何工作的,或者它甚至可能是非常简单的东西。

我试图搜索有关此内容的更多信息(以防止我自己要求这样做),但是当我不确定它叫什么时,这很困难我甚至都在寻找...

我注意到在我使用的一些JavaScript库中,变量名称既可以是函数,也可以是对象。例如,jQuery库使用名称" jQuery"。使用typeof jQuery记录时,它是一个函数,typeof jQuery()是一个对象。我感兴趣的是,最初的想法会表明jQuery()将是一个函数,但它实际上是一个对象。

//jQuery:
ƒ (a,b){return new r.fn.init(a,b)}


//jQuery():
r.fn.init {} //Expanding this reveals functions inside of __proto__ (which is obviously a clue, but I need more info)

当我尝试做这样的事情时,我最终会覆盖名称(正如我所料):

//Declare an object:
var planetEarth = {
    'sky': 'blue',
    'grass': 'green'
}

//Now overwrite the object as a function:
function planetEarth(){
    console.log('inside of a function now');
}

这在JavaScript领域是可以理解的,所以我的问题是像jQuery这样的库如何同时实现这两者?

最终(使用上面的例子)我希望能够做到这样的事情:

planetEarth().sky; //"blue"

所以我的迂回问题只是这叫什么?

跟进我可以在哪里学习完成此操作的基础知识?

我已经找到了面向对象的JavaScript和类以及原型的资源,但我不确定这些概念中的任何一个(或两个)是否都是这样的。我发现的所有文章都不是从一开始就开始的,似乎总是跳进不必要的复杂例子。我不打算建立一个巨大的图书馆 - 我只想在最基础的层面上获得更多的经验。再次,这可能是非常简单的,我之前从未遇到过这个概念,所以我很感激被指向正确的方向,谢谢。

4 个答案:

答案 0 :(得分:4)

每个JavaScript函数也是一个对象,就像每个数组也是一个对象一样。我不认为这有一个特殊的名称,它只是语言的运作方式。

你可能会混淆两个不同的东西:当你调用它时函数返回什么,而不是函数本身。举个例子:

planetEarth().sky;  // "blue"

此代码不依赖于作为对象的函数planetEarth并具有任何属性。您已经调用函数,因此要使此代码正常工作,函数需要返回对象。

因为函数是一个对象,所以您也可以直接在函数本身上设置属性。下面的代码使用了这两个功能。此版本的planetEarth()返回一个具有skygrass属性的对象,因此它在您的示例中起作用:您调用该函数以获取具有这些属性的对象。

代码还直接在函数上设置exists属性,您可以在不调用函数的情况下访问该属性:



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使用这两种功能。 jQuery是您可以调用的函数。它返回一个通常称为" jQuery对象的值"。该对象具有属性和方法,例如jQuery('#foo').show()。它也有"阵列式的"您可以像访问任何数组一样访问的属性,例如jQuery('#foo').lengthjQuery('#foo')[0]jQuery函数将这些属性添加到它返回的值中。

同时,jQuery库为jQuery函数本身添加了其他属性和方法。您无需调用该函数即可访问,例如jQuery.ajax({...})

其他一些注释可帮助您理解jQuery代码。首先,下载uncompressed version of jQuery。看起来您正在研究压缩版本,该版本缩短了名称,但没有任何意义。

此外,如果您想知道jQuery.fn是什么,它只是jQuery.prototype的别名。每当你看到jQuery.fn,你就可以在精神上取代jQuery.prototype;了解JavaScript原型的工作原理,您将了解jQuery.fn

现在你可能想知道为什么 jQuery.fn存在。为什么不像使用原型继承的其他JavaScript代码一样直接使用jQuery.prototype?事实上,你可以,它的工作方式与jQuery.fn相同。但是,早在2006年,jQuery的第一个版本并没有以这种方式工作。 jQuery.fn是它自己的独立对象,每次调用jQuery函数时,它都会将此对象的所有方法和属性复制到它返回的值中。

正如您所猜测的那样,效率相当低,因此jQuery已更改为使用.prototype,因此它可以返回继承所有方法的对象,例如.show().hide()而不是一个一个地复制它们。与此同时,jQuery.fn被保留为jQuery.prototype的别名,以避免破坏现有代码。

答案 1 :(得分:3)

这是一个无声的答案......

function f() {
  return {};
}

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

这就是jQuery的工作方式。 f是一个函数,但是当它被调用时,它返回一个对象。

有趣的部分:功能也是一个对象。 f instanceof Functionf instanceof Object都有效。因此,您可以将变量作为函数调用和/或分配一些属性,因为它也是一个对象。

f.test = 123;

答案 2 :(得分:1)

头等对象

在Javascript中,函数是第一类对象。这意味着函数只是另一种对象。你可以把一个函数放在一个变量中,你可以返回一个函数,你可以创建一个函数数组,以及所有这些。函数是对象。

考虑一下你的尝试略有变化:

//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

你提到你想使用planetEarth().sky,但观察到虽然planetEarth是一个函数(和一个对象,正如我所说的),planetEarth()是调用planetEarth的结果{1}}没有参数。因此,您是否可以planetEarth().sky执行planetEarth并不依赖sky作为具有planetEarth字段的对象,而是取决于您从// Both lines of code below are identical: function myFunc() { ... } var myFunc = function() { ... }; 返回的内容那个领域。

Bonus:你知道函数可以像“普通”变量一样声明吗?见下文:

myFunc

或许查看上面的代码可以帮助您清除混乱。该函数是myFunc()typeof myFunc()只是调用该函数的行为。如果function给出了myFunc,那么View v_home, v_earning, v_rating, v_account; 返回的对象也是一个函数只是巧合。

答案 3 :(得分:0)

jQuery是一个功能。可以将属性分配给已定义的函数。



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