JS面向对象编程(二):构造函数

1、什么是构造函数?

  构造函数 ,是一种特殊的方法。主要用来为对象成员变量赋初始值,总与new运算符一块儿使用在建立对象的语句中,对于JavaScript的内置对象Number()、String()、Boolean()、Object()、Array()、Function()、Date()、RegExp()、Error()等都是构造函数;
bash

构造函数的特色:

  1. 构造函数的首字母大写,用来区分于普通函数
  2. 内部使用的this对象,来指向即将要生成的实例对象
  3. 使用New来生成实例对象

举个栗子:

function Person(name, age, job){ 
     this.name = name; 
     this.age = age; 
     this.job = job; 
     this.sayHello = function(){ 
        console.log(this.name+":Hello!"); 
     }; 
} 
var person1 = new Person("lilei", 26, "Teacher"); //实例对象 person1
var person2 = new Person("xiaom", 27, "Doctor");  //实例对象 person2
复制代码

  构造函数与其余函数的惟一区别,就在于调用它们的方式不一样。构造函数毕竟也是函数,不存在定义构造函数的特殊语法。任何函数,只要经过 new 操做符来调用,那它就能够做为构造函数函数

2、构造函数与对象

  上一节咱们说到在JavaScript中,几乎全部的事物都是对象:对象只是带有属性和方法的特殊数据类型
  可是基本类型值不是对象,于是从逻辑上讲它们不该该有方法,实际上咱们建立 String 类型时后台自动作了一些处理:this

  1. 建立 String 类型的一个实例;
  2. 在实例上调用指定的方法;
  3. 销毁这个实例。
var s1 = new String("some text"); 
var s2 = s1.substring(2); 
s1 = null; 
复制代码

  基本类型值不是对象,只有引用类型是对象,可是 咱们可让String成为引用类型:spa

var s1 = new String("some text"); 
复制代码

  当咱们手动new一个字符串s1的时候,s1既是String又是引用类型,因此他是一个对象prototype

  引用类型与基本包装类型的主要区别就是对象的生存期。使用 new 操做符建立的引用类型的实例, 在执行流离开当前做用域以前都一直保存在内存中。而自动建立的基本包装类型的对象,则只存在于一 行代码的执行瞬间,而后当即被销毁;设计

3、建立实例对象

要建立 Person 的新实例,必须使用 new 操做符,调用构造函数建立对象通过了如下几个过程:指针

  1. 建立一个新对象;
  2. 将构造函数的做用域赋给新对象(所以 this 就指向了这个新对象);
  3. 执行构造函数中的代码(为这个新对象添加属性);
  4. 返回新对象;

  在前面例子中,person1 和 person2分别保存着Person的一个不一样的实例。这两个对象都有一个constructor(构造函数) 属性,该属性指向 Person:code

console.log(person1.constructor == Person); //true 
console.log(person2.constructor == Person); //true 
复制代码

4、判断对象类型

  在JS中判断一个变量的类型常常会用 typeof 运算符,可是在使用 typeof 运算符来判断引用类型时,不管引用的是什么类型的对象,它都返回"object"。因此在判断对象的类型时咱们可使用 instanceof 运算符:对象

console.log(person1 instanceof Object); //true 
复制代码

5、 构造函数缺点

  使用构造函数时每一个方法都要在每一个实例上从新建立一遍:ip

function Person(name, age, job){ 
     this.name = name; 
     this.age = age; 
     this.job = job; 
     this.sayHello = function(){ 
        console.log(this.name+":Hello!"); 
     }; 
     //this.sayHello = new Function('console.log(this.name+":Hello!")')
} 
复制代码

new Function与声明函数在逻辑上是同样的,因此每次实例化Person对象时,sayHello 方法也是一个新实例,因此:

console.log(person1.sayName == person2.sayName); //false 
复制代码

注意:person1.sayName 与person1.sayName()不同,person1.sayName()是指函数返回值,person1.sayName是指函数自己;

  建立两个完成一样任务的 Function 实例的确没有必要,所以,咱们能够经过把函数定义转移到构造函数外部来解决这个问题。例如:

function Person(name, age, job){ 
     this.name = name; 
     this.age = age; 
     this.job = job; 
     this.sayHello = sayHello; 
} 
function sayHello(){ 
      console.log(this.name+":Hello!"); 
} 
复制代码

   这样将 sayName 属性设置成指向全局函数 sayName() 的指针。sayName()只被实例化一次; 可是若是对象须要定义不少方法,那么就要定义不少个全局函数。并且在全局做用域中定义的函数实际上只被某个对象调用,这样不符合全局函数的理念。咱们这个自定义的引用类型也丝毫没有封装性可言。好在这些问题能够经过使用原型模式来解决。因此下一节《 prototype(原型)》


文章参考:

《JavaScript 高级程序设计》中文译本 第三版

相关文章
相关标签/搜索