彻底理解new操作符

思考一下如果需要在开发中创建一系列相似的对象,我们应该如何操作呢?

普通创建

使用字面量的方式多次创建对象

var person1 = {
  name: 'obj1',
  age: 18,
  height: 188,
}
var person2 = {
  name: 'obj2',
  age: 28,
  height: 180,
}
var person3 = {
  name: 'obj3',
  age: 38,
  height: 170,
}

这种方式有一个很大的弊端:创建同样的对象时,需要编写重复的代码,那怎么解决?继续往下看 ↓↓↓

工厂函数创建

我们可以封装一个函数,这个函数用于帮助我们创建一个对象,我们只需要重复调用这个函数即可,这就是工厂函数,工厂模式其实是一种常见的设计模式

function createPerson(name, age, height) {
  var obj = {}
  obj.name = name
  obj.age = age
  obj.height = height
  obj.running: function () {
    console.log(name + "在running");
  },
  obj.jumping: function () {
    console.log(name + "在jumping");
  },
  return obj
}

const person1 = createPerson('Alice', 25, 170);
person1.running(); // 输出: Alice在running
person1.jumping(); // 输出: Alice在jumping

const person2 = createPerson('Bob', 30, 180);
person2.running(); // 输出: Bob在running
person2.jumping(); // 输出: Bob在jumping

这种方式是有效的,但它还有一个缺点:每次调用 createPerson 时,都会为每个新对象创建新的 runningjumping 方法实例,如果创建大量对象可能会浪费内存。那怎么解决?继续往下看 ↓↓↓

构造函数创建

JavaScript为了支持面向对象编程,引入了new操作符,使得开发者能够通过构造函数创建并初始化对象

  • 构造函数也称为构造器(constructor),通常是我们在创建对象时会调用的函数
  • 构造函数是一个普通的函数,命名以大写字母开头,这个函数被new操作符来调用了,那么这个函数就称为是一个构造函数
function Person(name, age, height) {
  this.name = name;
  this.age = age;
  this.height = height;
  this.running = function() {
    console.log(name + "在running");
  };
  this.jumping = function() {
    console.log(this.name + "在jumping");
  };
}

const person1 = new Person('Alice', 25, 170);
person1.running(); // 输出: Alice在running
person1.jumping(); // 输出: Alice在jumping

const person2 = new Person('Bob', 30, 180);
person2.running(); // 输出: Bob在running
person2.jumping(); // 输出: Bob在jumping

通过工厂函数和构造函数代码对比可以看出:

  • new操作符肯定创建了一个空对象
  • new操作符肯定 return了一个对象
  • this绑定到了新对象上

但构造函数和new还是没有解决工厂函数每次都会创建新的 runningjumping 方法实例的问题,那么继续往下看 ↓↓↓

构造函数和原型

原型和原型链构成了 JavaScript 的继承机制,使得对象能够共享属性和方法,继承具体学习这篇文章:https://juejin.cn/post/7399986979735781391

function Person(name, age, height) {
  this.name = name;
  this.age = age;
  this.height = height;
}

Person.prototype.running = function() {
  console.log(this.name + "在running");
};

Person.prototype.jumping = function() {
  console.log(this.name + "在jumping");
};

const person1 = new Person('Alice', 25, 170);
person1.running(); // 输出: Alice在running
person1.jumping(); // 输出: Alice在jumping

const person2 = new Person('Bob', 30, 180);
person2.running(); // 输出: Bob在running
person2.jumping(); // 输出: Bob在jumping

这时我们会思考为什么定义在构造函数Person.prototype原型的方法,通过new创建出来的person1person2对象可以访问到?

可想而知这肯定是new操作符内部做了操作:
它将新对象的 __proto__ 属性设置为构造函数的 prototype 属性
person1.__proto__ = Person.prototype

图示如下
在这里插入图片描述

总结

  1. 创建一个空对象:使用 new 关键字时,首先会创建一个空对象
    • const obj = { }
  2. 设置原型:新对象的原型(__proto__)会被设置为构造函数的 prototype 属性
    • obj.__proto__ = Constructor.prototype
  3. 绑定 this:构造函数中的 this 会绑定到新创建的对象上
    • const result = Constructor.apply(obj, args)
  4. 执行构造函数:执行构造函数中的代码,this 指向新创建的对象
  5. 返回对象:如果构造函数没有显式返回对象,new 表达式会自动返回新创建的对象
    • return typeof result === 'object' && result !== null ? result : obj

手写new

function myNew(constructor, ...args) {
    // 1. 创建一个新的空对象
    const obj = {};
    
    // 2. 将新对象的 __proto__ 属性设置为构造函数的 prototype 属性
    obj.__proto__ = constructor.prototype;

    // 3. 调用构造函数,并将 this 绑定到新对象
    const result = constructor.apply(obj, args);

    // 4. 如果构造函数返回的是对象,则返回该对象,否则返回新对象
    return typeof result === 'object' && result !== null ? result : obj;
}

function Person(name, age) {
    this.name = name;
    this.age = age;
}

const john = myNew(Person, 'John', 30);
console.log(john.name); // 输出: John
console.log(john.age);  // 输出: 30

扩展ES6

ES6中,引入了 class 关键字,我们可以使用它来创建一系列的对象,这让面向对象编程变得更加直观和易于理解

class Person {
  constructor(name, age, height) {
    this.name = name;
    this.age = age;
    this.height = height;
  }
  running() {
    console.log(this.name + "在running");
  }
  jumping() {
    console.log(this.name + "在jumping");
  }
}

const person1 = new Person('Alice', 25, 170);
person1.running(); // 输出: Alice在running
person1.jumping(); // 输出: Alice在jumping

const person2 = new Person('Bob', 30, 180);
person2.running(); // 输出: Bob在running
person2.jumping(); // 输出: Bob在jumping
  • 21
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值