跳至正文

JavaScript入门教程笔记(14)-实例对象与 new 命令

1 对象是什么

对象是单个实物的抽象。通常有一个模板表示共同特征,然后对象根据这个模板生成。

典型的面向对象编程语言(比如C++和Java),都有“类”(class)这个概念。所谓“类”就是对象的模板,对象就是“类”的实例。但是JavaScript的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)。

2 构造函数

JavaScript使用构造函数(constructor)作为对象的模板。所谓“构造函数”,就是专门用来生成实例对象的函数。它是对象的模板,描述了实例对象的基本结构。

构造函数其实是一个普通的函数,但是有自己的特征和用法。

var Person = function() {
    this.age = 30;
}

上面代码中,Person就是一个构造函数。为了与普通函数区别,构造函数名字的第一个字母通常大写。

构造函数的特点有两个。
- 函数内部使用了this关键字,代表所要生成的对象实例。
- 生成对象的时候,必须使用new命令。

3 new命令

3.1 基本用法

new命令的作用,就是执行构造函数,返回一个实例对象。

var Person = function() {
    this.age = 30;
};

var p = new Person();
p.age // 30

上面代码中,通过new命令让构造函数Person生成一个实例对象,保存在变量p中。构造函数内部的this,代表新生成的实例对象。

new命令本身就可以执行构造函数,所以后面的构造函数可以带括号,也可以不带括号。下面两行代码是等价的,但为了表示这是函数调用,推荐使用括号。

var p = new Person(); // 推荐的写法
var p = new Person; // 不推荐的写法

如果忘了使用new命令,直接调用构造函数会发生什么呢?

这种情况下,构造函数变成普通函数,并不会生成实例对象。而且,这时this代表全局对象,还将造成一些意想不到的结果。

var Person = function() {
    this.age = 30;
};

var p = Person();
p // undefined
age // 30

上面代码中,调用Person构造函数时,忘了加上new命令,结果,变量p变成了undefined,而age属性变成了全局变量。

3.2 new命令的原理

使用new命令时,内部将依次执行下面的步骤。
1. 创建一个空对象,作为将要返回的对象实例。
2. 将这个空对象的原型,指向构造函数的prototype属性。
3. 将这个空对象赋值给函数内部的this关键字。
4. 开始执行构造函数内部的代码。

也就是说,构造函数内部,this指向的是一个新生成的空对象,所有this操作,都发生在这个空对象上。

new命令简化的内部流程,可以用下面的代码表示。

function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) {
  // 将 arguments 对象转为数组
  var args = [].slice.call(arguments);
  // 取出构造函数
  var constructor = args.shift();
  // 创建一个空对象,继承构造函数的 prototype 属性
  var context = Object.create(constructor.prototype);
  // 执行构造函数
  var result = constructor.apply(context, args);
  // 如果返回结果是对象,就直接返回,否则返回 context 对象
  return (typeof result === 'object' && result != null) ? result : context;
}

// 实例
var man1 = _new(Person, '张三', 28);

3.3 new.target

函数内部可以使用new.target属性。如果当前函数是new命令调用,new.target指向当前函数,否则为undefined。

function f() {
    console.log(new.target === f);
}
f() // false
new f() // true

注:本文适用于ES5规范,原始内容来自 JavaScript 教程,有修改。

标签:

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注