欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript对象的创建初学

程序员文章站 2022-03-08 22:32:52
javascript最初被称之为一门玩具性语言,主要的功能用于表单提交时的验证。时至今日,仍然有一些人认为javascript非常简单,有过其他语言的人学起来似乎不用几小时看下文档就行。其实不然,j...

javascript最初被称之为一门玩具性语言,主要的功能用于表单提交时的验证。时至今日,仍然有一些人认为javascript非常简单,有过其他语言的人学起来似乎不用几小时看下文档就行。其实不然,javascript虽然是一门脚本语言,但是他有着自己特色,如果不去了解他与众不同的地方,那遇到的坑将数不胜数。而javascript中难点之一就是原型链,他也是javascript中继承实现的重要基础。

函数

在开始讲原型链之前,我们先来聊一聊javascript中的函数。

javascript有5种基本类型以及一种复杂数据类型object,object本质上由一组无序的名值对组成。

object其实是一种引用类型,在javascript中引用类型和其他如c#语言中的类有点像。我们可以把javascript中的引用类型假想成类,引用类型的值就是类的一个实例,即对象。

引用类型:

object array date regexp function

我们可以看到,其实函数也是一种引用类型,即每一个函数实例可以称之为一个对象。

创建对象

前面已经说到,在javascript中,对象本质就是一组名值对。那如何来创建对象呢?

方式一:使用object构造函数创建

var person = new object();
person.name = 'jack';
person.age = 18;
person.sayname = function () {
   console.log(this.name);
};

早期的开发人员经常使用这种模式创建对象,不过后来又兴起来一种更为简单直接的方式。

方式二:使用对象字面量的方式创建

这种方式你可能经常在使用,但是不知道这种创建方式的名字——对象字面量。

var person = {
  name: 'jack',
  age: 18,
  sayname: function () {
    console.log(this.name)
  }
};

当你使用上面两种方式创建单个对象时,无疑是很方便简单的,但是现实中往往不是那么的简单,很多时候,我们都会面临一些复杂的场景。如果我们需要创建多个对象,那么采用上述方法就会产生大量重复代码。

方式三:使用工厂模式创建

工厂模式是软件工程领域中一种广为人知的设计模式,通过这种模式我们可以避免在创建多个对象时产生大量重复代码。

function createperson (name, age) {
  var obj = new object();
  obj.name = name;
  obj.age = age;
  obj.sayname = function () {
    console.log(this.name);
  };

  return obj;
}

var person1 = createperson('jack', 20);
var person2 = createperson('tony', 22); 

方式四:使用构造函数模式创建

虽然工厂模式解决了创建多个相似对象的问题,但是这里却存在另一个问题。我们知道在程序中,当我们要对某个参数进行处理时,往往会先判断其类型或检查其值是否符合我们的要求。

通过工厂创建的方式,显然无法对其创建的对象进行识别。随着javascript的发展,另一种方式出现了——构造函数模式。

在本文开始讲函数的时候提到,每个函数都是function类型的一个实例,即函数是对象。函数不仅可以使用函数声明语法和函数表达式去定义,而且还可以使用function构造函数定义。

在javascript中,构造函数可以用来创建特点类型的对象,比如像object、array以及function这样的原生构造函数,当然我们亦可以创建自定义构造函数。

function person (name, age) {
  this.name = name;
  this.age = age;
  this.sayname = function () {
    console.log(this.name);
  };
}
var person1 = new person('jack', 20);
var person2 = new person('tony', 22);

观察上面的代码,我们可以发现这种写法有点像其他oop语言。

class person {
  private $name;
  private $age;

  public function __construct(name, age)
  {
    $this->name = name;
    $this->age = age;
  }

  public function sayname()
  {
    echo $this->name;
  }
}

在前面的例子当中,person1和person2两个对象都有一个constructor(构造函数)属性,该属性指向person。如此一来,便可以解决对象类型的问题。我们可以使用如下方式进行判断:

console.log(person1.constructor == person);  // true

方式五:使用原型模式创建

构造函数虽然好用,但是并非没有缺点。构造函数的主要问题,就是每个方法都要在每个实例上重新创建一遍。

让我们再看一下前面的例子:

function person (name, age) {
  this.name= name;
  this.age = age;
  this.sayname = new function('console.log(this.name)');
}

前面提供,每个函数其实就是一个对象,上面定义函数方法和之前是等价的。

面对这种情况,我们可以通过原型模式来解决。

首先我们要牢记三个概念:

构造函数(类似于oop中的类) 实例或对象,通过new 构造函数()创建(类似于oop中的对象) 原型对象,可以想象成所有通过new操作符产生的实例的原始对象,只要我们创建一个构造函数,那么就会生成一个原型对象。在构造函数内部也会创建一个prototype属性,该属性指向原型对象。

下面我们看看如何使用原型模式来重写上面的例子:

function person () {}

person.prototype.name = 'jack';
person.prototype.age = 18;
person.prototype.sayname = function () {
  console.log(this.name);
};

var person1 = new person();

首先我们创建了一个自定义构造函数,里面是空的,什么也没加。然后,我们通过其包含的属性prototype,为其原型对象添加属性和方法。最后我们通过new操作符,创建了一个person实例。这个时候,person1也拥有了name属性、age属性以及sayname方法。

看到这里,如果你是新手,肯定觉得一脸蒙蔽。产生这种现象的原因其实就是javascript的原型链,也就是本文的主题。

当我们访问person1的name属性时,javascript会现在person1实例中查找,如果找不到,就根据person1实例内部的一个指针[[prototype]](该指针指向原型对象),去寻找其原型对象,如果原型对象里面有,那么就会取这个值。

在这我们来回顾一下方式四中说道person1和person2两个对象都有一个constructor,该属性指向person构造函数。其实从这里可以看出,不是这两个实例中有constructor,而是在它们的原型对象中有这个指向构造函数的constructor属性。所以实例和构造函数是没有直接联系的。

方式六:组合使用构造函数模式和原型模式创建

如果仅仅使用原型模式去创建对象,这样又会造成一个问题。我们希望像name、age这样的属性,能够通过参数进行传递,所以大多数情况都是结合两种方式来创建对象的。

构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性

function person (name, age) {
    this.name = name;
    this.age = age;
}
person.prototype.sayname = function () {
  console.log(this.name);
};

var person1 = new person('jack', 18);