JavaScript的new关键字

标签 IT工具网 javascript

原问题:What is the ‘new’ keyword in JavaScript?

通常,JavaScript初学者在看过new关键字的讲解之后会陷入迷惑之中。因为JavaScript不是一个OOP语言,而传统的new关键字是用来创建一个对象的。接着,当看到很多书上讲到prototypeprototype.constructor的时候,更迷惑了:这个constructor是几个意思?

现在由new关键字为契机,说一下JavaScript中的对象和OOP。

内存和new

虽然说JavaScript不是面向对象的编程语言,但程序总归还是在内存里运行的。不管编程语言有没有对象的概念,最终还是要跟内存打交道。

那么问题来了:一个JavaScript程序在内存中运行的时候,内存是怎样一种状况呢?

不走得太深,我们规定场景为:浏览器打开一个web页面,该页面中的JavaScript程序的运行情况。

一般情况下,内存中会是以下场景:

  • window对象,全局的
  • 栈,函数调用时使用
  • 堆,使用new关键字申请

那么答案来了: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);
}

深入JavaScript对象

其实没什么好深入的,就是在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);
}

使用prorotype扩展属性

至于使用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;
};

使用prorotype继承属性

不使用new呢?

如果不使用new关键字,那就是函数调用。本质上就是执行内存中window对象的代码。

而函数定义这个操作,本身就是给window这个JSON对象添加成员。

比如

// 以下函数定义的实质是window.Foo = function{}
var Foo = function(){
  this.A = 1;
  this.B = 2;
};

Foo(); // 将会对`window`对象添加两个属性A和B。因为此时this指向的内存是`window`

相关文章:

javascript - 在 JavaScript 中为其命名空间字符串表示获取构造函数的最佳方法

java 产生指定范围的随机数

如何开始Node.js的学习

JavaScript的参数传递方式:传值or传引用

javascript - 如何在没有表单的情况下循环单选按钮组?

javascript - 从 html 页面抓取视频和图像

-bash: ./configure: Permission denied 的解决方案

java如何将String转换为enum

javascript - 检测 SPA 中的 URL 更改

javascript - Jquery 防止帖子上页面重新加载