js中对象的创建及理解
初学 JavalScrip 时,它的自由让人很不适应,特别是对于对象的创建,很是疑惑:它没有类的概念(初学时了解的水平),也没有构造函数, 而更不能理解的是,它的实例是通过 new 函数得到的。直到看了《JavaScrip高级程序设计》之后,才恍然大悟,特此总结,希望能给那些初学者一点解惑之光,若有不足之处,还请斧正。
用 C# 创建对象
首先,我们看一下,在 C# 中怎么创建一个对象
定义类
1
2
3
4
5
6
7
8
9
10
11
12
13
14// 类的定义
public class Person
{
// 定义属性
public String Name {get;set;}
public int Age {get;set;}
// 构造函数
public Person(string name,int age)
{
this.Name = name;
this.Age = age;
}
}创建C#对象
1
Person person = new Person('zhangsan',18);
上面就是 C# 创建对象的过程
用 js 创建对象
现在我们再来看一下 js 中如何创建对象(ES5中构造函数方式)
定义函数
1
2
3
4
5fuction Person(name,age)
{
this.name = name;
this.age = age;
}创建 js 对象
1
2// const ES6 中的声明
const person = new Person('lisi',19);
js 创建对象原理分析
要理解 js 中创建对象为什么可以 new 函数得到,我们需要追本溯源,一步一步了解 js 中创建对象的演变
最开始是 new Object 形式
1
2
3
4
5
6
7
8
9var person = new Object();
person.name = 'lisi';
person.age = 19
// 或者
var person = {
name: 'lisi',
age: 19
}然后是工厂模式
1
2
3
4
5
6function createPerson(name, age){
var o = new Object();
o.name = name;
o.age = age;
return o;
}随着演变,出现了构造函数模式
1
2
3
4
5// 定义构造函数时,首字母建议大写,用于区别一般函数
function Person(name, age){
this.name = name;
this.age = age;
}分析
对比工厂模式和构造函数模式,我们可以看到有如下区别
后者没有显式地创建对象
直接将属性和方法赋给了 this 对象
没有 return 语句
创建新实例的时候,必须用 new
构造函数在创建对象的时候,其实经过了下面步骤:
- 创建一个新对象
- 将构造函数的作用域赋给新对象(因此 this 指向了新的对象)
- 执行构造函数的代码(为这个新对象添加属性)
- 返回新对象
通过上面分析,我们就很容易地理解了,为什么 new 一个函数可以创建对象
将构造函数当作函数
构造函数与其他函数的唯一区别,就在于调用它们的方式不同。不过,构造函数毕竟也是函数,不存在定义构造函数的特殊语法。任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数;而任何函数,如果不通过 new 操作符来调用,那它跟普通函数也不会有什么两样。不过直接调用的时候,它就是向上下文的 this 添加字段。
构造函数方式的问题
使用构造函数的主要问题,就是每个方法都要在每个实例上重新创建一遍。
例如有如下构造函数
1 | function Person(name, age, job){ |
当实例化多个 Person 后,每个实例中的 sayName 不是同一个,上面的定义可以等价为:
1
2
3
4
5
6function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = new Function("alert(this.name)"); // 与声明函数在逻辑上是等价的
}
然而,创建两个完成同样任务的 Function 实例的确没有必要;况且有 this 对象在,根本不用在执行代码前就把函数绑定到特定对象上面。因此,大可像下面这样,通过把函数定义转移到构造函数外部来解决这个问题。
1 | function Person(name, age, job){ |
我们把 sayName()函数的定义转移到了构造函数外部。而在构造函数内部,我们将 sayName 属性设置成等于全局的 sayName 函数。这样一来,由于 sayName 包含的是一个指向函数的指针。
最优的对象声明方式
既然分析了 js 创建对象的原理,那么现在就必须要分享一下,什么是最优的对象声明方式了。原理部分直接省略,此处只给出最终的答案——动态原型模式:
1 | function Person(name, age, job){ |