首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在JavaScript中一个函数同时被认为是一个构造函数和一个对象?

为什么在JavaScript中一个函数同时被认为是一个构造函数和一个对象?
EN

Stack Overflow用户
提问于 2008-12-16 18:23:37
回答 8查看 4.2K关注 0票数 5

我最近对此做了大量的研究,但还没有得到一个很好的确切答案。我在某个地方读到,当JavaScript引擎遇到一个函数语句时,就会创建一个新的函数()对象,这会让我相信它可能是一个对象的子对象(从而成为一个子对象)。于是我给道格拉斯·克罗克福德发了邮件,他的回答是:

不完全正确,因为函数语句不调用编译器。 但它也产生了类似的结果。

而且,据我所知,除非函数构造函数已实例化为新对象,否则不能调用函数构造函数的成员。所以这是行不通的:

代码语言:javascript
复制
function myFunction(){
    this.myProperty = "Am I an object!";
}
myFunction.myProperty; // myFunction is not a function
myFunction().myProperty; // myFunction has no properties

然而,这将起作用:

代码语言:javascript
复制
function myFunction(){
    this.myProperty = "Am I an object!";
}
var myFunctionVar = new myFunction();
myFunctionVar.myProperty;

这只是语义学的问题..。在整个编程世界中,什么时候一个对象真正变成了一个对象,以及如何映射到JavaScript?

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2008-12-16 18:47:58

你的理解是错误的:

代码语言:javascript
复制
myFunction().myProperty; // myFunction has no properties

它不能工作的原因是".myProperty“被应用于返回的"myFunction()”值,而不是应用于对象"myFunction“。即:

代码语言:javascript
复制
$ js
js> function a() { this.b=1;return {b: 2};}
js> a().b
2
js> 

记住,"()“是一个运算符。"myFunction“与"myFunction()”不一样。当使用新的实例化时,不需要“返回”:

代码语言:javascript
复制
js> function a() { this.b=1;}
js> d = new a();
[object Object]
js> d.b;
1
票数 12
EN

Stack Overflow用户

发布于 2008-12-16 21:03:55

函数和构造函数没有什么神奇之处。JavaScript中的所有对象都是…好吧,物体。但有些对象比其他的更特殊:即内置对象。差别主要在于以下几个方面:

  1. 对物体的一般处理。例子:
    • 数字和字符串是不可变的(⇒常量)。没有定义任何方法来在内部更改它们--结果总是产生新的对象。虽然它们有一些固有的方法,但您不能改变它们,也不能添加新的方法。任何这样做的企图都将被忽视。
    • nullundefined是特殊的对象。对这些对象使用方法或定义新方法的任何尝试都会导致异常。

  1. 适用的操作人员。JavaScript不允许(重新)定义操作符,所以我们坚持使用可用的操作。
    • 数字对算术运算符有一种特殊的方式:+-*/
    • 字符串有一种特殊的方式来处理连接操作符:+
    • 函数有一种特殊的方法来处理"call“操作符:()new操作符。后者对如何使用构造函数的prototype属性、如何构造具有与原型的适当内部链接的对象以及如何调用构造函数函数来正确设置this具有先天的知识。

如果您查看ECMAScript标准(PDF格式),您将看到所有这些“额外”功能都被定义为方法和属性,但许多方法和属性对程序员来说并不直接可用。其中一些将在新修订的标准ES3.1 (截至2008年12月15日的草案:PDF格式)中披露。一个属性(__proto__)是已经在Firefox中公开了

现在我们可以直接回答你的问题了。是的,函数对象具有属性,我们可以随意添加/删除它们:

代码语言:javascript
复制
var fun = function(){/* ... */};
fun.foo = 2;
console.log(fun.foo);  // 2
fun.bar = "Ha!";
console.log(fun.bar);  // Ha!

它真的不重要的功能,实际上-它从来没有发挥,因为我们不叫它!现在让我们来定义它:

代码语言:javascript
复制
fun = function(){ this.life = 42; };

它本身不是一个构造函数,它是一个对其上下文进行操作的函数。我们可以很容易地提供:

代码语言:javascript
复制
var context = {ford: "perfect"};

// now let's call our function on our context
fun.call(context);

// it didn't create new object, it modified the context:
console.log(context.ford);           // perfect
console.log(context.life);           // 42
console.log(context instanceof fun); // false

如您所见,它向已经存在的对象添加了另一个属性。

为了使用我们的函数作为构造函数,我们必须使用new操作符:

代码语言:javascript
复制
var baz = new fun();

// new empty object was created, and fun() was executed on it:
console.log(baz.life);           // 42
console.log(baz instanceof fun); // true

如您所见,new使我们的函数成为一个构造函数。以下操作由new执行

  1. 创建了新的空对象({})。
  2. 它的内部prototype属性设置为fun.prototype。在我们的例子中,它将是一个空对象({}),因为我们没有以任何方式修改它。
  3. 使用这个新对象作为上下文调用fun()

修改新对象取决于我们的功能。通常,它设置对象的属性,但它可以做它喜欢做的任何事情。

有趣的琐事:

  • 因为构造函数只是一个对象,所以我们可以计算它: 变量A=函数(Val){ this.b .a= val;};var B=函数(Val){this.b.b= val;};var C=函数(标志){返回标志?A: B;};//现在让我们创建一个对象: var x= new (C(true))(42);//这是什么类型的对象?console.log(x.a);// false console.log(x.b);// false console.log(x.a);// true /它是A //让我们检查它的console.log(x.a);// 42 console.log(x.b);//未定义/现在让我们创建另一个对象:y var = new (C(false))(33);/这是哪种对象?console.log(y.a);// false console.log(y.b);//真console.log(y.a);// false //它是B/让我们检查它的console.log(Y.A);//未定义的console.log(Y.B);// 33 /酷,呵呵?
  • 构造函数可以返回重写新创建的对象的值: 变量A=函数(标志){if(标志){ //让我们返回完全不同的返回{ford:“完美”};} //让我们修改对象this.life = 42;};//现在让我们创建两个对象: var x=新A(false);var y=新A(真);//让我们检查x console.log(console.log);// true console.log(x.ford);//未定义console.log(x.life);// 42 //让我们检查y console.log(y instanceof A);// false console.log(y.ford);//完美console.log(y.life);//未定义 如您所见,x是带有原型和全部的A,而y是我们从构造函数返回的“裸”对象。
票数 13
EN

Stack Overflow用户

发布于 2008-12-16 18:41:14

要回答你的具体问题,从技术上讲,函数总是对象。

例如,您总是可以这样做:

代码语言:javascript
复制
function foo(){
  return 0;
}
foo.bar = 1;
alert(foo.bar); // shows "1"

Javascript函数在使用this指针时的行为有点像其他OOP语言中的类。它们可以用新关键字实例化为对象:

代码语言:javascript
复制
function Foo(){
  this.bar = 1;
}
var foo = new Foo();
alert(foo.bar); // shows "1"

现在,从其他OOP语言到Javascript的映射很快就会失败。例如,Javascript中实际上没有类这样的东西-对象使用原型链进行继承。

如果你要用Javascript做任何有意义的编程,我强烈推荐给你发邮件的克罗克福德的Javascript:好的部分

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/372202

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档