ECMAScript
中构造函数可以用来创建特定类型的对象。像Object
和Array
这样的原生构造函数,在运行时会自动出现在执行环境中。此外,也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。例如,可以使用构造函数模式将前面的例子重写。如下:
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
return this.name;
};
}
var p1 = new Person("Ann" , 23 , "actress");
var p2 = new Person("Rose" , 23 , "writer");
当我看到上面的内容的时候,我震惊了。javascript
中调用函数可以创建一个新的对象?使用new
操作符,然后调用函数就可以了?
虽然这种方式很奇怪(相对于java
,c#
而言),但是,的确可以。
因为根据以往的经验,函数中的this
是当前的执行环境变量。一般来说,如果是在网页上的全局环境里面调用函数,则函数内部的this
对象就是window
对象。但是,这里的this
好像是一个新的类型(Person
?)的对象。为什么?
下面是我的小测验,查看一下通过这种方式调用函数,是不是真的改变了this
对象。
1 使用
new
调用构造函数的代码:
console.log("<>>>before this是 Window 类型吗? " + (this instanceof Window));
function Person(name, age, job) {
console.log("inner this是 Window 类型吗? " + (this instanceof Window));
console.log("inner this是 Person 类型吗? " + (this instanceof Person));
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
return this.name;
};
}
var p1 = new Person("Ann", 23, "actress");
// todo: 使用了 new 操作符
console.log("outer this是 Window 类型吗? " + (this instanceof Window));
console.log("outer this是 Person 类型吗? " + (this instanceof Person));
// 在浏览器运行的输出结果如下
/**
<pre>
// todo: 在浏览器运行的输出结果如下 :
<>>>before this是 Window 类型吗? true
inner this是 Window 类型吗? false
inner this是 Person 类型吗? true
outer this是 Window 类型吗? true
outer this是 Person 类型吗? false
</pre>
*/
2 不使用
new
,直接调用构造函数的代码:
console.log("<>>>before this是 Window 类型吗? " + (this instanceof Window));
function Person(name, age, job) {
console.log("inner this是 Window 类型吗? " + (this instanceof Window));
console.log("inner this是 Person 类型吗? " + (this instanceof Person));
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
return this.name;
};
}
var p1 = Person("Ann", 23, "actress"); // 注意:这里没有 new
console.log("outer this是 Window 类型吗? " + (this instanceof Window));
console.log("outer this是 Person 类型吗? " + (this instanceof Person));
/*
<pre>
// todo: 在浏览器运行的输出结果如下 :
<>>>before this是 Window 类型吗? true
inner this是 Window 类型吗? true
inner this是 Person 类型吗? false
outer this是 Window 类型吗? true
outer this是 Person 类型吗? false
</pre>
*/
同样的代码,只是在调用的时候,一次使用了new
操作符来调用Person()
函数,一次没有。然后输出的效果并不相同。
从log
可以看到:
- 在函数外部,
this
一直是Window
类型的对象。(在全局环境中调用的)[即使函数内部的this
不是Window
类型。] - 在函数内部:
- 如果当前函数被
new funcName(args);
的方式调用,this
为当funcName
类型的对象; - 如果当前函数没有使用
new
操作符调用,只是普通调用(var result = funcName(args);
),则this
是Window
类型的对象。
- 如果当前函数被
所以,通过构造函数模式确实创建了一个新的对象,而且,这个对象有自己的类型,可以被类型识别到了。
总结:
- 任何函数,不使用
new
去调用,就是普通的函数调用,函数中的this
是当前函数调用的执行环境变量。(谁调用我,我的this
就是谁。)。 - 任何函数,使用
new
去调用,就成了构造函数,函数会创建一个新的对象类型,新的对象类型名就是当前函数名,函数中的this
类型也就是这个新的对象类型。