前端开发系列038-基础篇之new关键字

本文介绍JavaScript 语言中 new 关键字调用构造函数的内部执行细节和模拟实现。

在 JavaScript 语言中,我们通过 new 关键字来调用构造函数以创建实例对象,或者是通过 new关键字来调用类以实例化,class是ES6新增的特性,可以理解为它和构造函数是一样的。

在下面的代码中,我们先提供了构造函数Person,然后设置原型对象并创建了实例对象 p。

/* 01-提供构造函数 */
function Person(name, age) {
    this.age = age;
    this.name = name;
    this.showName = function() {
        console.log("姓名:" + this.name);
    }
    this.showAge = function() {
        console.log("年龄:" + this.age);
    }
}

/* 02-设置原型对象 */
Person.prototype.showInfo = function() {
    this.showName();
    this.showAge();
}

/* 03-创建实例对象 */
let p = new Person("Yong", 16);

/* 04-测试代码 */
console.log(p);
p.showInfo();

/*  打印输出结果:
Person {
  age: 16,
  name: 'Yong',
  showName: [Function],
  showAge: [Function] 
}
姓名:Yong
年龄:16
*/

构造函数的代码如果换成是Class,那结果也是一样的。这里我们需要关注下当使用 new 关键字 来调用构造函数或者类的时候都做了些什么,也就是内部的实现细节,下面通过代码注释的方式来对这些细节进行说明。

/* 01-提供构造函数 */
function Person(name, age) {
    /* [1] 创建空对象 */
    /* 模拟:let o = {} */

    /* [2] 设置原型对象访问 */
    /* 模拟:o.__proto__ = Person.prototype; */

    /* [3] 修改 this 指向空对象 */
    /* 模拟:this = o */

    /* [4] 通过 this 来设置实例属性 */
    this.age = age;
    this.name = name;

    /* [5] 通过 this 来设置实例方法 */
    this.showName = function() {
        console.log("姓名:" + this.name);
    }
    this.showAge = function() {
        console.log("年龄:" + this.age);
    }

    /* [6] 默认总是返回内部新创建的对象(this) */
    /* 如果主动 return , 若跟的是引用类型则直接返回,值类型则忽略 */
    /* 模拟:return this */
}

/* 02-设置原型对象 */
Person.prototype.showInfo = function() {
    this.showName();
    this.showAge();
}

/* 03-创建实例对象 */
let p = new Person("Yong", 16);

最后,再花点时间来封装个函数以模拟new 关键字的功能,列出给定代码和测试数据。

/* 01-模拟 new 关键字 */
function mockNew() {
    /* [1]-获取构造器 */
    /* 说明:arguments类数组执行删除操作,接收删除后的元素 */
    let Constructor = [].shift.call(arguments);

    /* [2]-创建空对象 */
    let o = {};

    /* [3]-设置新对象的原型指向构造函数的原型对象 */
    /* 注意:默认 o.__proto__ 指向的是 Object.prototype */
    o.__proto__ = Constructor.prototype;

    /* [4] 把剩余的参数传递给构造函数(class) */
    /* 关键:执行函数Constructor(arguments),并绑定内部的 this */
    let instance = Constructor.apply(o, arguments);

    /* [5] 处理返回值 */
    /* 说明:如果是引用类型的数据那么就直接返回,否则总是返回内部新创建的对象 o */
    return instance instanceof Object ? instance : o;
}


/* 02-提供构造函数(首字母大写区分) */
function Person(name, age) {
    this.age = age;
    this.name = name;
    this.showName = function() {
        console.log("姓名:" + this.name);
    }
    this.showAge = function() {
        console.log("年龄:" + this.age);
    }
}

/* 03-设置原型对象 */
Person.prototype.showInfo = function() {
    this.showName();
    this.showAge();
}

/* 04-测试代码 */
let p1 = mockNew(Person, "Yong", 16);
let p2 = mockNew(Person, "Yi", 18);
console.log(p1, p2);
// Person { age: 16, name: 'Yong', showName: [Function], showAge: [Function] }
// Person { age: 18, name: 'Yi', showName: [Function], showAge: [Function] }

p1.showInfo();
/* 姓名:Yong 年龄:16 */

posted on 2022-12-12 10:01  文顶顶  阅读(53)  评论(0编辑  收藏  举报

导航