Skip to content

构造函数模式 ​

本节目标:理解“构造函数模式”的核心思路,并能把它用于实际开发或面试表达。

说明:原 OneNote 中有图片引用,但图片未包含在导出目录中;本页保留了可用的文字与代码内容。 方式

function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function () {
    console.log(this.name);
  }
}
var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('Greg', 27, 'Doctor');

不同点 构造函数模式与工厂模式的不同:从代码执行记忆

  1. 创建新实例,必须要用new操作符
  2. 构造函数始终以一个大写字母开头
  3. 没有显式地创建对象
  4. 直接将属性和方法赋给了this对象
  5. 没有return语句

创建步骤

==首先创建了一个新的空对象;==

==将对象的====proto====指向函数的== ==prototype====对象,这样就可以区分实例类型了。使用的是====Object.create()====方法;==

==让函数的== ==this== ==指向这个对象:通过====apply()====的方式调用;==
==执行构造函数的代码来为这个新对象添加属性;==

==判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。==

==为什么函数都有p====rototype====对象:== ==所有函数可以当作构造函数来使用====,通过====new 操作符来创建对象====,原型对象可以保存实例的共享属性。==

==与工厂模式的区别在于:==

==隐式创建的对象会以构造函数的原型对象为原型,这样这个对象的====constructor====就会指向了构造函数,所以可以区分实例的类型。==

==同时,构造函数中指定属性代码的执行都使用====apply====绑定了其中的====this====为我们这个创建的对象;==

**实现****:**
function objectFactory() {
    let newObject = null,
        constructor = Array.prototype.shift.call(arguments),
        result = null;
    // 参数判断
    if (typeof constructor !== "function") {
        console.error("type error");
        return;
    };
    // 新建一个空对象,对象的原型为构造函数的 prototype 对象
    newObject = Object.create(constructor.prototype);
    // 将 this 指向新建对象,并执行函数
    result = constructor.apply(newObject, arguments);
    // 判断返回对象
    let flag = result && (typeof result === "object" || typeof result === "function");
    // 判断返回结果
    return flag ? result : newObject;
}
// 使用方法
objectFactory(构造函数, 初始化参数)

构造函数与普通函数区别

  • 主要区别:调用方式的不同;
  • 次要区别:命名规范上,构造函数的首字母大写;
  • 任何函数,只要通过new操作符调用,那它就是构造函数;
  • 构造函数如果不通过new操作符调用,那它和普通函数一样;
  • 构造函数不使用new调用时,要注意其中this的指向问题;
  • 可以使用call()(或者apply())在某个特殊对象的作用域中调用Person构造函数(构造函数借用:借用构造函数的对象拥有了构造函数实例的属性)。

创建对象的完成度一、对象识别 使用构造函数创建对象,意味着可以将实例标识为自定义的类型,即实例的constructor属性会指向构造函数,可以识别对象,这弥补了工厂模式的不足。

  • 识别方法:通过实例的constructor(构造函数)属性,如下所示。
person1.constructor == Person; // true
person2.constructor == Person; // true
  • 通过instanceof操作符,检测对象类型要更可靠一些。
person1 instanceof Object // true
person1 instanceof Person // true
person2 instanceof Object // true
person2 instanceof Person // true

以上面这种方式定义的构造函数是定义在Global对象(浏览器中是Window对象)中的。

构造函数的问题

  • 所创建的对象无法共享属性,因而重复占用内存,造成浪费。

ECMAScript中的函数是对象,因此每次为实例赋予一个值为方法的属性,相当于调用new Function()实例化一个函数对象,以这种方式创建函数,会导致不同的作用域链和标识符解析。因此,不同实例上的同名函数是不相等的,以下可证明 console.log(person1.sayName == person2.sayName);//false

  • 况且有this对象在,根本不用在执行代码前就把函数绑定到特定对象上面。在实例的作用域下调用函数,函数中的this自然会指向实例。

因此,可以通过把函数定义转移到构造函数外部来解决这个问题。

由于sayName包含的是一个指向函数的指针,因此person1和person2对象就可以共享了。 样做确实解决了两个函数做同一件事的问题,但在全局作用域中定义函数没有封闭性可言了。

本站总访问 — 次