我最近一直在做很多研究,但还没有得到一个非常好的答案.我在某处读到当JavaScript引擎遇到函数语句时会创建一个新的Function()对象,这会让我相信它可能是一个对象的子对象(从而成为一个对象).所以我给Douglas Crockford发了电子邮件,答案是:
不完全是因为函数语句不调用编译器.
但它产生了类似的结果.
另外,据我所知,除非已将实例化为新对象,否则不能在函数构造函数上调用成员.所以这不起作用:
function myFunction(){ this.myProperty = "Am I an object!"; } myFunction.myProperty; // myFunction is not a function myFunction().myProperty; // myFunction has no properties
但是,这将有效:
function myFunction(){ this.myProperty = "Am I an object!"; } var myFunctionVar = new myFunction(); myFunctionVar.myProperty;
这只是一个语义问题......在整个编程世界中,对象何时真正成为一个对象,以及它如何映射到JavaScript?
关于函数和构造函数没有什么神奇之处.JavaScript中的所有对象都是......好吧,对象.但是有些对象比其他对象更特殊:即内置对象.差异主要在于以下几个方面:
物体的一般处理.例子:
数字和字符串是不可变的(⇒常量).没有定义任何方法在内部更改它们 - 总是生成新对象作为结果.虽然它们有一些固有的方法,但您无法更改它们或添加新方法.任何这样做的尝试都将被忽略.
null
并且undefined
是特殊对象.任何在这些对象上使用方法或定义新方法的尝试都会导致异常.
适用的运营商.JavaScript不允许(重新)定义运算符,因此我们坚持使用可用的东西.
数字与算术运算符一种特殊的方式:+
,-
,*
,/
.
字符串有一种特殊的方式来处理连接运算符:+
.
函数有一种特殊的方式来处理"call"操作符:()
和new
操作符.后者具有如何使用prototype
构造函数的属性的先天知识,构造一个具有与原型的适当内部链接的对象,并在其上调用构造函数this
正确设置.
如果您查看ECMAScript标准(PDF),您将看到所有这些"额外"功能被定义为方法和属性,但其中许多功能不能直接供程序员使用.其中一些将在标准ES3.1的新版本中公开(截至2008年12月15日的草案:PDF).一个属性(__proto__
)已在Firefox中公开.
现在我们可以直接回答您的问题.是的,函数对象具有属性,我们可以随意添加/删除它们:
var fun = function(){/* ... */}; fun.foo = 2; console.log(fun.foo); // 2 fun.bar = "Ha!"; console.log(fun.bar); // Ha!
这个功能实际上做了什么并不重要 - 它永远不会起作用,因为我们不称之为!现在让我们来定义它:
fun = function(){ this.life = 42; };
它本身不是构造函数,它是一个在其上下文中运行的函数.我们可以很容易地提供它:
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
运算符:
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
:
{}
创建了新的空对象().
它的内部原型属性设置为fun.prototype
.在我们的例子中,它将是一个空对象({}
)因为我们没有以任何方式修改它.
fun()
用这个新对象作为上下文调用.
我们的功能是修改新对象.通常它会设置对象的属性,但它可以做任何它喜欢的事情.
有趣的琐事:
因为构造函数只是一个对象,我们可以计算它:
var A = function(val){ this.a = val; }; var B = function(val){ this.b = val; }; var C = function(flag){ return flag ? A : B; }; // now let's create an object: var x = new (C(true))(42); // what kind of object is that? console.log(x instanceof C); // false console.log(x instanceof B); // false console.log(x instanceof A); // true // it is of A // let's inspect it console.log(x.a); // 42 console.log(x.b); // undefined // now let's create another object: var y = new (C(false))(33); // what kind of object is that? console.log(y instanceof C); // false console.log(y instanceof B); // true console.log(y instanceof A); // false // it is of B // let's inspect it console.log(y.a); // undefined console.log(y.b); // 33 // cool, heh?
构造函数可以返回覆盖新创建的对象的值:
var A = function(flag){ if(flag){ // let's return something completely different return {ford: "perfect"}; } // let's modify the object this.life = 42; }; // now let's create two objects: var x = new A(false); var y = new A(true); // let's inspect x console.log(x instanceof A); // true console.log(x.ford); // undefined console.log(x.life); // 42 // let's inspect y console.log(y instanceof A); // false console.log(y.ford); // perfect console.log(y.life); // undefined
正如你所看到的那样x
是A
原型和所有,而y
我们是从构造函数返回的"裸"对象.
你的理解是错误的:
myFunction().myProperty; // myFunction has no properties
它不起作用的原因是因为".myProperty"应用于"myFunction()"的返回值,而不是对象"myFunction".以机智:
$ js js> function a() { this.b=1;return {b: 2};} js> a().b 2 js>
请记住,"()"是一个运营商."myFunction"与"myFunction()"不同.instanciang with new时你不需要"返回":
js> function a() { this.b=1;} js> d = new a(); [object Object] js> d.b; 1
要回答您的具体问题,技术上的功能始终是对象.
例如,您可以随时执行此操作:
function foo(){ return 0; } foo.bar = 1; alert(foo.bar); // shows "1"
当Javascript函数使用this
指针时,它们的行为有点像其他OOP语言中的类.可以使用new关键字将它们实例化为对象:
function Foo(){ this.bar = 1; } var foo = new Foo(); alert(foo.bar); // shows "1"
现在,从其他OOP语言到Javascript的映射将很快失败.例如,Javascript中实际上没有类这样的东西 - 对象使用原型链来进行继承.
如果您打算在Javascript中进行任何重要的编程,我强烈推荐您通过电子邮件发送的Javascript: Crockford 的Good Parts.