1. 函数是新对象的构造函数
当您调用 时new FuncName
,该函数充当构造函数,并且this
inside 的值指向正在构造的对象(而不是函数本身)。当您删除时new
,this
变成undefined
,回退到全局对象(除非您处于严格模式)。
2. 函数也是对象
每个函数都是 的一个实例Function
,因此函数本身就是对象并且可以有自己的属性。this.propName
在函数体内无法访问这些属性,只能使用funcName.propName
. 那是因为this
函数内部永远不是函数对象本身(除非你强迫它是,with bind
,,call
或apply
)。
我希望以上两个主题都能帮助您了解函数的工作原理。至于你的最后一个问题:CrockfordcreateObject
是一种实现继承的不同方式,基本上是Object.create
在符合 ES5 的浏览器中做的。它允许一个对象直接从另一个对象继承,而不需要您手动创建一个新的构造函数,设置它的prototype
属性(这是一个函数对象的属性示例),并使用new
. Crockford 更喜欢这一点,并表示他不再使用new
这种方法。
针对您在聊天中提出的问题,这里尝试通过示例来解释什么是函数以及它们的作用。
函数可以只是...函数
你打电话给他们,他们会做一些事情:
function alertThis(what) {
alert(what)
}
alertThis("alerting something");
您还可以传递它们的值,并让它们返回值
function timesTwo(num) {
return num * 2;
}
timesTwo(2); // 4
它们可以被传递并返回任何东西,包括对象......
function createPerson(firstName, lastName) {
return {
firstName : firstName,
lastName : lastName
}
}
var john = createPerson('John', 'Doe');
john.lastName; // "Doe"
...和其他功能:
function timesN(n) {
return function(num) {
return n * num;
}
}
var timesThree = timesN(3);
timesThree(5); // 15
函数是对象
函数可以像任何普通对象一样被传递和返回。那是因为它们是对象。像任何对象一样,它们可以具有属性:
function countCalls() {
countCalls.timesCalled++;
}
countCalls.timesCalled = 0;
countCalls();
countCalls();
countCalls.timesCalled; // 2
函数的一个非常重要的默认属性是prototype
. 这是一个特殊的属性,我们会看到为什么。
函数可以充当新对象的构造函数
函数的行为可以像常规 OO 语言中的类构造函数一样。当用 调用时new
,它们会创建某个“类”的新对象。这个新对象this
在函数内部被调用,并自动返回:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
var john = new Person('John', 'Doe');
john.firstName; // "John"
john instanceof Person; // true
...除非您故意返回其他内容:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
var fakePerson = {
firstName : firstName,
lastName : lastName
};
return fakePerson;
}
var notPerson = new Person('John', 'Doe');
notPerson.firstName; // "John"
notPerson instanceof Person; // false
// Note: the object called 'this' inside the function is created, but
// after the function is called there is no outside reference to it.
构造函数创建的对象知道谁创建了它们,并且可以看到它们的prototype
属性
回到一个真实的人:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// Add something to the Person prototype
Person.prototype.sayHi = function() {
return "hi, I'm " + this.firstName;
}
var john = new Person('John', 'Doe');
john.sayHi(); // "Hi, I'm John"
john.constructor; // Person
对象john
可以sayHi()
,因为它可以访问其构造函数prototype
属性中的所有内容。但它不能直接看到 Person 的其他属性(只能通过自己的constructor
属性):
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
Person.timesCalled++;
// There is no 'this.timesCalled', only Person.timesCalled
}
Person.timesCalled = 0;
var john = new Person('John', 'Doe');
john.timesCalled; // undefined - john cannot be called, Person can
john.constructor.timesCalled; // 1