JavaScript 面向对象编程

面向对象编程——OOP(Object Oriented Programming)是一种程序设计思想,把对象作为程序的基本单元,对业务功能进行抽象和封装

构造函数 Constructor

构造函数是生成对象的模版,在 Java 等面向对象的编程语言中存在类(Class)的概念,用来编写对象的模版,但是 ES5 规范里并没有类的概念,而是基于构造函数和原型链来实现类和继承

构造函数的原理

ES5 并没有类和构造函数的语法,当一个普通的函数遇上关键字new,那神奇的事情就发生了,使用new关键字执行函数会触发构造运行。通过new关键字就使一个普通的函数变成了生成对象的模版,可以在函数内部通过this关键字在生成的对象实例上生成属性和方法,内部流程如下:

  • 首先new关键字会创建一个对象
  • 然后将对象的原型(__proto__)指向构造函数的prototype对象
  • 将函数的this就指向这个对象,执行函数,这时对this的赋值都会作用在创建的对象上
  • 函数执行完成,判断返回数据类型
    • 如果函数未声明返回值,或者声明的返回值为基本类型,那么返回值为this
    • 如果返回类型为引用类型,那么就返回这个对象,这样就失去了构造函数的本意。
function objectFactory() {
  // 创建对象
  const obj = new Object();

  const args = Array.prototype.slice.call(arguments);

  // 获取构造函数,设置原型链
  const Constructor = args.shift();
  obj.__proto__ = Constructor.prototype;

  // 调用构造函数为对象赋值
  const result = Constructor.apply(obj, args);

  // 返回对象
  return typeof result === "object" ? result : obj;
}
function A(x,y){
  this.x = x;
  this.y = y;
  this.toString = function(){
    return this.x + this.y;
  }
}

function B(x,y){
  this.x = x;
  this.y = y;
  this.toString = function(){
    return this.x + this.y;
  }
  return "Constructor return base Type";
}

function C(x,y){
  this.x = x;
  this.y = y;
  this.toString = function(){
    return this.x + this.y;
  }
  return {x:x,y:y};
}

A(1,2);// undefined;
var a = new A(1,2);
a.toString();// 3;

B(1,2);// "Constructor return base Type"
var b = new B(1,2);
b.toString();// 3;

C(1,2); // Object {x: 1, y: 2}
var c = new C(1,2);
c.toString();// "[object Object]"

在上面的例子中方法 A 和方法 B 中由于没有声明返回类型或者声明的返回类型为基本类型,所以声明了也白声明,返回的为新开辟的内存空间,即this所指向的部分; 在两个方法中均对toSting()方法进行覆盖,所以通过方法 A 和方法 B 生成的实例调用toString方法时指向的是我们自己声明的方法;

在方法 C 中因为返回类型是一个对象,那么生成的实例即为这个对象,覆盖的toString方法并没有生效,调用的仍然是继承自 Object 的toString方法;

由此可见我们声明的构造函数如果不通过new关键字调用那么就不是我们想要的效果,我可以通过以下两种方式处理这个问题:

一:使用严格模式,没有使用new关键字,严格模式下函数内部this不能指向全局对象,默认等于undefined,对undefined进制操作会报错

function A(x){
  'use strict';
  this.x = x;
}
A(1); //Uncaught TypeError: Cannot set property 'x' of undefined(…)

二:使用new.target属性;

new.target可以检查函数或者构造方法是否是通过new运算符调用,是的话会返回指向构造方法或函数的引用,普通执行的函数返回值是undefined

function Foo() {
  if (!new.target) throw "Foo() must be called with new";
  console.log("Foo instantiated with new");
}

results matching ""

    No results matching ""