原问题:What is the 'new' keyword in JavaScript?
通常,JavaScript初学者在看过new
关键字的讲解之后会陷入迷惑之中。因为JavaScript不是一个OOP语言,而传统的new
关键字是用来创建一个对象的。接着,当看到很多书上讲到prototype
和prototype.constructor
的时候,更迷惑了:这个constructor
是几个意思?
现在由new
关键字为契机,说一下JavaScript中的对象和OOP。
虽然说JavaScript不是面向对象的编程语言,但程序总归还是在内存里运行的。不管编程语言有没有对象的概念,最终还是要跟内存打交道。
那么问题来了:一个JavaScript程序在内存中运行的时候,内存是怎样一种状况呢?
不走得太深,我们规定场景为:浏览器打开一个web页面,该页面中的JavaScript程序的运行情况。
一般情况下,内存中会是以下场景:
- window对象,全局的
- 栈,函数调用时使用
- 堆,使用
new
关键字申请
那么答案来了:new
关键字是用来申请内存的。
又重复一遍:JavaScript不是面向对象的编程语言。这句话中的面向对象指的是:封装、继承、多态。实际上这句话是废话,没有任何意义,建议以后忘掉它。
实际上JavaScript中处处都是对象——JSON对象。Object/Attribute, Function/Method的实例通通都是一个JSON对象。
与其他编程语言一样,使用new
关键字可以创建一个新对象,也就是一个Object的实例,一个JSON实例。
实例展示:JSFiddle
function Foo(){
this.bar = 'foo bar';
}
/** 在内存创建了一个新的JSON对象
*{
* bar: 'foo bar',
* __proto__: {
* constructor: {name: 'Foo', ...},
* __proto__
* }
*}
**/
var foo = new Foo();
console.log(JSON.stringify(foo)); // 输出: {"bar":"foo bar"}
// 输出: bar foo bar
for(var propName in foo) {
propValue = foo[propName]
console.log(propName,propValue);
}
其实没什么好深入的,就是在MCMAScript中对这个JSON对象有几个特别的规定:ECMAScript- Object
- prototype属性
- constructor属性
- hasOwnProperty(property)方法
- propertyIsEnumerable(property)方法
这几个特别属性和方法,请参考文档中的说明。其实这几个规定的目的,也是为了完善创建出来的JSON对象的属性列表,使其具有任意扩展、属性继承的效果。
使用prototype来任意扩展可访问的JSON属性,看一个例子:JSFiddle
function Foo(){
this.bar = 'foo bar';
}
Foo.prototype.b = 'foo bar b'; // 给Foo.prototype属性赋值
/** 在内存创建了一个新的JSON对象
*{
* bar: 'foo bar',
* __proto__: {
* b: 'foo bar b';
* constructor: {name: 'Foo', ...},
* __proto__
* }
*}
**/
var foo = new Foo();
debugger;
console.log(JSON.stringify(foo)); // 还是输出: {"bar":"foo bar"}
// 输出: bar foo bar
// b foo bar b
for(var propName in foo) {
propValue = foo[propName]
console.log(propName,propValue);
}
至于使用prototype实现继承效果,不详细解释。这里给出一般使用的extend()
方法的定义,再来一个使用实例:JSFiddle
var extend = function (Base) {
var Class = function () {
Base.apply(this, arguments);
}, F;
if (Object.create) {
Class.prototype = Object.create(Base.prototype);
} else {
F = function () {};
F.prototype = Base.prototype;
Class.prototype = new F();
}
Class.prototype.constructor = Class;
return Class;
};
如果不使用new
关键字,那就是函数调用。本质上就是执行内存中window
对象的代码。
而函数定义这个操作,本身就是给window
这个JSON对象添加成员。
比如
// 以下函数定义的实质是window.Foo = function{}
var Foo = function(){
this.A = 1;
this.B = 2;
};
Foo(); // 将会对`window`对象添加两个属性A和B。因为此时this指向的内存是`window`