lhlGitHub / trisome

前端大厂进攻学习资料库
21 stars 1 forks source link

new操作符的实现原理 #10

Open lhlGitHub opened 2 years ago

longweixia commented 2 years ago

1-1.使用场景

当需要创建多个对象的时候,如果循环会「重复创建」很多变量,占用内存。

如果用new生成,那么里面重复的属性是在「原型」上,就不用占用内存。

1-2.意义

节省代码,属于语法糖,可以拥有使用构造函数里面的所有「属性和方法」,并且还可以「拓展」。

1-3.实现步骤

1-4.代码实现

新建构造函数--用来new的函数

// 构造函数是一种特殊的方法:用来在创建对象时为对象成员变量赋初始值
function Dog(name){
  // 这里的this指向window,所以下面才需要重新将this指向自身,这样才能将属性挂载成功
  this.name = name
  this.say = function() {
    console.log("my name is" + this.name);
  }
}

手写new函数

function _new(fn,...arg){
  const obj = {};
  // 将构造函数的原型挂载到新对象上
  Object.setPrototypeOf(obj, fn.prototype)
  // 将this指向新对象,执行构造函数
  let result = fn.apply(obj, arg);
  return result instanceof Object ? result : obj
}

验证

var dog = _new(Dog, "caigou")
dog.say();// my name is caigou
13168335674 commented 2 years ago
function _new(target, ...args) {
    const obj = Object.create(target.prototype);
    const ret = target.apply(obj, args);
    return typeof ret === 'object' ? ret : obj;
}
zhanglongLee commented 2 years ago

new操作符的实现原理

new运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象

举个例子

// Otaku 御宅族,简称宅
function Otaku(name, age) {
    this.name = name
    this.age = age
}
// 重量
Otaku.prototype.weight = 80
Otaku.prototype.sayHi = function () {
    console.log(`I am ${this.name},age is ${this.age}.`);
}
let person = new Otaku("张三", 12)
console.log(person.name);//张三
console.log(person.age);//12
console.log(person.weight);//80
person.sayHi();// I am 张三,age is 12.

从这个例子中,我们可以看到person实例可以:

  1. 访问到 Otaku 构造函数的属性;
  2. 访问到 Otaku.prototype 中的属性或方法;

注意:加入构造函数有返回值,并且返回值是对象,则new操作符会返回该对象

// Otaku 御宅族,简称宅
function Otaku(name, age) {
    this.name = name
    this.age = age
    return{
        name:"哈哈",
        age:22
    }
}
// 重量
Otaku.prototype.weight = 80
Otaku.prototype.sayHi = function () {
    console.log(`I am ${this.name},age is ${this.age}.`);
}
let person = new Otaku("张三", 12)
console.log(person.name);//哈哈
console.log(person.age);//22
console.log(person.weight);//undefined
person.sayHi();//报错

实现一个new函数:

function objectFactory() {
    let obj = new Object()
    Constructor = Array.prototype.shift.call(arguments)// 将构造函数取出,arguments剩余的数据为传入的参数
    // 将原型指向obj
    obj.__proto__ = Constructor.prototype
    let result = Constructor.apply(obj, arguments)
    // 如果构造函数的返回值不为对象,则返回obj。否则返回该对象result
    return Object.prototype.toString.apply(result).includes("Object") ? result : obj
}

测试

// Otaku 御宅族,简称宅
function Otaku(name, age) {
    this.name = name
    this.age = age
}
// 重量
Otaku.prototype.weight = 80
Otaku.prototype.sayHi = function () {
    console.log(`I am ${this.name},age is ${this.age}.`);
}
// let person = new Otaku("张三", 12)
let person = objectFactory(Otaku, "张三", 12)
console.log(person.name);//张三
console.log(person.age);//12
console.log(person.weight);//80
person.sayHi();//I am 张三,age is 12.

参考链接