Skip to content

[js] 第22天 你对new操作符的理解是什么?手动实现一个new方法 #76

Open
@haizhilin2013

Description

@haizhilin2013
Collaborator

第22天 你对new操作符的理解是什么?手动实现一个new方法

Activity

AnsonZnl

AnsonZnl commented on May 8, 2019

@AnsonZnl
Contributor

new 的理解

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

new步骤

模拟new操作前,要先知道new操作是发生了什么,就拿new Object()举例:

  1. 创建一个新对象
  2. 把新对象的原型指向构造函数的prototype
  3. 把构造函数里的this指向新对象
  4. 返回这个新对象

构造函数:

先准备一个构造函数来new使用。

function constructorFunction(name, age){
  this.name = name;
  this.age = age;
}
constructorFunction.prototype.say = function(){
  return 'Hello '+ this.name
}

原生new:

var obj = new constructorFunction('willian', 18)
console.log(obj.name, obj.age);//'willian', 18
console.log(obj.say())//Hello willian

模拟new

模拟的new 暂称为newNew (囡..囡 哈哈~)
使用:newNew(constructor, arg1, arg2, ..) 第0个参数传入构造函数,1~n个参数是构造函数的形参。
使用上面的构造函数试一下:

function newNew(){
 var newObj = {}
 // 1. 创建一个新对象
 var Con = [].shift.call(arguments)
 // 得到构造函数
 newObj.__proto__ = Con.prototype;
 // 2. 把新对象的原型指向构造函数的prototype
 var res = Con.apply(newObj, arguments)
 // 3. 把构造函数里的this指向新对象
 return typeof res === 'object' ? res : newObj;
 // 4. 返回新对象
}
var obj = newNew(constructorFunction, 'willian', 18)
console.log(obj.name, obj.age);//'willian', 18
console.log(obj.say())//Hello willian

得到和new 一样的答案,说明模拟成功。
你也可以F12 打开控制台试一试。
以上参考:

  1. JavaScript深入之new的模拟实现 mqyqingfeng/Blog#13
  2. https://blog.csdn.net/liwenfei123/article/details/80580883
BeADre

BeADre commented on May 8, 2019

@BeADre

function _new(Fn, ...arg) {
const obj = Object.create(Fn.prototype);
const obj1 = Fn.apply(obj, arg);
return obj1 instanceof Object ? obj1 : obj;
}

之前在github看另外一个人写的

tzjoke

tzjoke commented on May 29, 2019

@tzjoke
  1. 创建新对象
  2. 新对象原型[[prototype]] = 构造函数prototype
  3. this 指向新对象
  4. 执行构造函数
  5. 如果构造函数返回非空对象,就返回这个对象引用,不然返回创建的新对象
myprelude

myprelude commented on Jun 13, 2019

@myprelude
function myNew(fn){
  var obj = {};
  Object.setPrototypeOf(obj,fn.prototype)
  obj.apply(fn)
  return obj
}
bWhirring

bWhirring commented on Jul 9, 2019

@bWhirring
  1. 创建一个空对象,作为要返回的对象实例
  2. 将这个对象的原型,指向构造函数的prototype属性
  3. 将这个空对象赋值给函数内部的this关键字
  4. 开始执行构造函数内部的代码
function newF(obj) {
	const o = {},
		args = [].slice.call(arguments);
	o.__ptoto__ = obj.prototype;
	const res = obj.apply(o, args.slice(1));
	return typeof res === 'object' ? res : o
}
Vi-jay

Vi-jay commented on Jul 29, 2019

@Vi-jay
function customNew(fn) {
  const obj = {};
  return function (...args) {
    const res = fn.apply(obj, args);
    obj.__proto__ = Object.getPrototypeOf(fn);
    return typeof res === "object" ? res : obj
  }
}

function Foo(name) {
  this.name = name
}

console.log(customNew(Foo)(2));
NARUTOne

NARUTOne commented on Oct 11, 2019

@NARUTOne
/**
 * 模拟实现 new 操作符
 * @param  {Function} ctor [构造函数]
 * @return {Object|Function|Regex|Date|Error}      [返回结果]
 */
function newOperator(ctor){
    if(typeof ctor !== 'function'){
      throw 'newOperator function the first param must be a function';
    }
    // ES6 new.target 是指向构造函数
    newOperator.target = ctor;
    // 1.创建一个全新的对象,
    // 2.并且执行[[Prototype]]链接
    // 4.通过`new`创建的每个对象将最终被`[[Prototype]]`链接到这个函数的`prototype`对象上。
    var newObj = Object.create(ctor.prototype);
    // ES5 arguments转成数组 当然也可以用ES6 [...arguments], Aarry.from(arguments);
    // 除去ctor构造函数的其余参数
    var argsArr = [].slice.call(arguments, 1);
    // 3.生成的新对象会绑定到函数调用的`this`。
    // 获取到ctor函数返回结果
    var ctorReturnResult = ctor.apply(newObj, argsArr);
    // 小结4 中这些类型中合并起来只有Object和Function两种类型 typeof null 也是'object'所以要不等于null,排除null
    var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null;
    var isFunction = typeof ctorReturnResult === 'function';
    if(isObject || isFunction){
        return ctorReturnResult;
    }
    // 5.如果函数没有返回对象类型`Object`(包含`Functoin`, `Array`, `Date`, `RegExg`, `Error`),那么`new`表达式中的函数调用会自动返回这个新的对象。
    return newObj;
}

参考 https://juejin.im/post/5bde7c926fb9a049f66b8b52#heading-5

laixihong

laixihong commented on Dec 20, 2019

@laixihong
function _new(Fn,...args){
    // 创建对象
    let obj = {};
    // 对象的原型指向其构造函数对应的原型
    obj.proto = Fn.prototype;
    // 运行函数,且修改this指向实例
    obj1= Fn.apply(obj,args)
    // 返回对象
    return obj1 instanceof Object ? obj1:obj
}
0x3c

0x3c commented on Feb 21, 2020

@0x3c

new 操作会执行以下几步:

  • 创建一个对象
  • 对象[[ProtoType]] 指向构造函数 prototype
  • this 指向该对象
  • 执行函数
  • 如果函数没有返回一个引用值则返回该对象
function newFn(C, ...args) {
  const o = Object.create(C.prototype);
  const o2 = C.apply(o, args);
  return o2 instanceof Object ? o2 : o;
}
adi0754

adi0754 commented on Jun 8, 2020

@adi0754
function _new(target, ...res) {
    const obj = {};
    obj.__proto__ = target.prototype;
    const ret = target.apply(obj, res);
    return typeof ret === 'object' ? ret : obj;
}
blueRoach

blueRoach commented on Jun 10, 2020

@blueRoach

对一个实例new做了以下4件事

  1. 生成一个空对象
  2. 将此对象的原型对象(proto)指向实例的原型(prototype)
  3. 将此对象的this指向实例
  4. 返回一个此对象

实现方法,楼上大佬的

function _new(fn, ...arg){
      let obj = Object.create(fn.prototype) 
      // Object.create 1.创建一个对象 2.将参数对象指向生成对象的原型(__proto__) 3.返回该对象
      let obj1 = fn.apply(obj, arg) 
      return obj1 instanceof Object ? obj1 : obj 
      // 不是很理解为什么要对象才返回,当我传Date的时候不就跟new 不一致了吗
}
qiqingfu

qiqingfu commented on Jun 15, 2020

@qiqingfu
276378532

276378532 commented on Aug 20, 2020

@276378532
        // new 的实现原理
        // 创建一个新对象
        // 将新对象的_proto_指向构造函数的prototype对象
        // 将构造函数的作用域赋值给新对象 (也就是this指向新对象)
        // 执行构造函数中的代码(为这个新对象添加属性)
        // 返回新的对象

        function _new(fn,...arg){
            //将创建的对象的原型指向构造函数的原型 ==> 新对象.__proto__(原型) == fn.prototype
            const obj = Object.create(fn.prototype);
            // 将this指向新对象 
            const ret = fn.apply(obj,arg);
            //判断返回值 (如果构造函数本身有返回值且是对象类型,就返回本身的返回值,如果没有才返回新对象)
            return ret instanceof Object ? ret : obj;
        }
smile-2008

smile-2008 commented on Sep 22, 2020

@smile-2008

new 的理解

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

new步骤

模拟new操作前,要先知道new操作是发生了什么,就拿new Object()举例:

  1. 创建一个新对象
  2. 把新对象的原型指向构造函数的prototype
  3. 把构造函数里的this指向新对象
  4. 返回这个新对象

构造函数:

先准备一个构造函数来new使用。

function constructorFunction(name, age){
  this.name = name;
  this.age = age;
}
constructorFunction.prototype.say = function(){
  return 'Hello '+ this.name
}

原生new:

var obj = new constructorFunction('willian', 18)
console.log(obj.name, obj.age);//'willian', 18
console.log(obj.say())//Hello willian

模拟new

模拟的new 暂称为newNew (囡..囡 哈哈~)
使用:newNew(constructor, arg1, arg2, ..) 第0个参数传入构造函数,1~n个参数是构造函数的形参。
使用上面的构造函数试一下:

function newNew(){
 var newObj = {}
 // 1. 创建一个新对象
 var Con = [].shift.call(arguments)
 // 得到构造函数
 newObj.__proto__ = Con.prototype;
 // 2. 把新对象的原型指向构造函数的prototype
 var res = Con.apply(newObj, arguments)
 // 3. 把构造函数里的this指向新对象
 return typeof res === 'object' ? res : newObj;
 // 4. 返回新对象
}
var obj = newNew(constructorFunction, 'willian', 18)
console.log(obj.name, obj.age);//'willian', 18
console.log(obj.say())//Hello willian

得到和new 一样的答案,说明模拟成功。
你也可以F12 打开控制台试一试。
以上参考:

  1. mqyqingfeng/Blog#13
  2. https://blog.csdn.net/liwenfei123/article/details/80580883

+1

3 remaining items

zebratt

zebratt commented on Jan 19, 2021

@zebratt
function create(fun, ...args) {
  const obj = Object.create(fun.prototype);
  obj.constructor = fun;
  const res = fun.call(obj, ...args);

  return isPrimitive(res) ? obj : res;
}

const isPrimitive = (val) => Object(val) !== val;

function Apple(name, count){
  this.name = name
  this.count = count
}

var a = create(Apple, 'apple', 3)

console.log(a)

// Apple { constructor: [Function: Apple], name: 'apple', count: 3 }
overwatch555

overwatch555 commented on Mar 1, 2021

@overwatch555
    function Dog(name, age) {
        this.name = name
        this.age = age
    }

    let dog1 = new Dog('旺财', 2)



    function myNew() {
        let [Fn, ...args] = arguments
        let obj = Object.create(Fn.prototype)
        Fn.call(obj, ...args)    //借用Fn这个构造函数 给obj添加属性
        return obj
    }

    let dog2 = myNew(Dog, '二哈', 5)
    console.log(dog2)

    function myNew2() {
        let obj = {};
        let [fn, ...arg] = arguments;
        obj.__proto__ = fn.prototype;
        fn.call(obj, ...arg);
        return obj;
    }
WayneGongCN

WayneGongCN commented on Mar 1, 2021

@WayneGongCN

对一个实例new做了以下4件事

  1. 生成一个空对象
  2. 将此对象的原型对象(proto)指向实例的原型(prototype)
  3. 将此对象的this指向实例
  4. 返回一个此对象

实现方法,楼上大佬的

function _new(fn, ...arg){
      let obj = Object.create(fn.prototype) 
      // Object.create 1.创建一个对象 2.将参数对象指向生成对象的原型(__proto__) 3.返回该对象
      let obj1 = fn.apply(obj, arg) 
      return obj1 instanceof Object ? obj1 : obj 
      // 不是很理解为什么要对象才返回,当我传Date的时候不就跟new 不一致了吗
}

我的理解是这样的:

obj 和 obj1 原则上应该是同一个对象的引用。
obj1 是构造函数返回的值,但是通常我们不会在构造函数中写 return 语句。
所以当构造函数有返回值,且这个返回值是 Object 的实例,就优先返回这个值,否则就默认返回 obj。

378406712

378406712 commented on May 17, 2021

@378406712

实例化一个对象。

zxcdsaqwe123

zxcdsaqwe123 commented on Oct 11, 2021

@zxcdsaqwe123

实例化对象

amikly

amikly commented on Nov 9, 2021

@amikly

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

实现

function _new(constructor, ...arg) {
    // 1.创建一个空对象
    let obj = {};
    // 2.为步骤1新创建的对象添加属性__proto__,将该属性链接至构造函数的原型对象prototype
    obj.__proto__ = constructor.prototype;
    // 3.将步骤1新创建的对象作为this的上下文
    let res = constructor.apply(obj, arg);
    // 4.如果该函数没有返回对象,则返回this
    // return typeof res === "object" ? res : obj;
    return Object.prototype.toString.call(res) === "[object Object]"
        ? res
    : obj;
}

const Fun = function (name) {
    this.name = name;
};

console.log(_new(Fun, "Tom"));
flashyy

flashyy commented on Feb 17, 2022

@flashyy
  1. 创建(或者说构造)一个全新的对象。
  2. 这个新对象会被执行 [[ 原型 ]] 连接。
  3. 这个新对象会绑定到函数调用的 this。
  4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。
github-cxtan

github-cxtan commented on Feb 18, 2022

@github-cxtan

创建一个新对象
将构造函数中的this指向该对象
执行构造函数代码(给新对象添加属性和方法)
返回者着新对象
据此,我们初步实现模拟new的objectFactory方法:

function objectFactory(){
var obj=new Object();//创建一个新对象
var Constructor=[].shift.call(arguments);//取得该方法的第一个参数(并删除第一个参数),该参数是构造函数
obj.proto=Constructor.prototype;//将新对象的内部属性__proto__指向构造函数的原型,这样新对象就可以访问原型中的属性和方法
Constructor.apply(obj,arguments);//使用apply,将构造函数中的this指向新对象,这样新对象就可以访问构造函数中的属性和方法
return obj;//返回一个对象
}

ilss

ilss commented on Mar 8, 2022

@ilss

可以加入一些内存方面的理解

yxllovewq

yxllovewq commented on Mar 9, 2022

@yxllovewq

new的背后操作:

  1. 创建一个空对象_this
  2. 将类A的实例属性作为_this的属性
  3. 将类A的原型prototype作为_this的隐式原型
  4. 将_this返回
function A () {
  this.a = 1;
}
A.b = 2;
A.prototype.c = 3;

let a = new A();

// 模仿 new A
function newA () {
  let _this = Object.create(A.prototype);
  A.call(_this);
  return _this;
}
console.log(newA() instanceof A);
xiaoqiangz

xiaoqiangz commented on May 27, 2022

@xiaoqiangz

// 1 创建一个空对象
// 2 将新对象的原型指向构造函数的prototype
// 3 将this指向该对象
// 4 返回这个对象

// 模拟new方法
function newFn(fn, ...args) {
  // 1 , 2
  var o = Object.create(fn.prototype)
  // 1
  // var o = {}
  // // 2
  // o.__proto__ = fn.prototype
  // 3
  obj = fn.apply(o, args)
  //4 
  return obj instanceof Object ? obj : o
}

function constructorFunction(name, age){
  this.name = name;
  this.age = age;
}
constructorFunction.prototype.say = function(){
  return 'Hello '+ this.name
}
var news1 = newFn(constructorFunction, 'xq', '28')
console.log(news1)
console.log(news1.say())
xiaoxiaozhiya

xiaoxiaozhiya commented on May 31, 2022

@xiaoxiaozhiya
  1. 创建一个新的对象
  2. 指定对象的原型链
  3. 使得this指向空对象
  4. 如果函数没有返回对象, 表达式会返回对象
Sobrium

Sobrium commented on Sep 12, 2022

@Sobrium

1、对new操作符的理解
创建一个obj空对象,
使obj的__proto__指向构造函数的prototype
修改构造函数的this指向,使构造函数的this指向obj并执行构造函数
返回新创建的obj对象
2、手动实现
function myNew(){
let obj = {},
fn = [].shift.call(arguments);
obj.proto = fn.prototype;
let res = fn.apply(obj, arguments);
return typeof res === 'object' ? res : obj;
}

 function myNew1(fn, ...arg){
      var obj = Object.create(fn.prototype),
            res = fn.apply(obj, arg);
      return typeof obj === 'object' ? res : obj;
 }
never123450

never123450 commented on Sep 4, 2023

@never123450

在JavaScript中, new 操作符用于创建一个对象实例。当你使用 new 关键字调用一个函数时,它会执行以下操作:

  1. 创建一个新的空对象。
  2. 将这个新对象的原型指向构造函数的原型。
  3. 将构造函数的作用域赋给新对象(因此 this 指向新对象)。
  4. 执行构造函数内部的代码,可以在这个过程中给新对象添加属性和方法。
  5. 如果构造函数没有显式地返回一个对象,则返回这个新对象。

下面是一个手动实现 new 方法的JavaScript示例:

function myNew(constructor, ...args) {
  // 创建一个新的空对象,并将其原型指向构造函数的原型
  const obj = Object.create(constructor.prototype);
  
  // 将构造函数的作用域赋给新对象
  const result = constructor.apply(obj, args);
  
  // 如果构造函数有显式地返回一个对象,则返回该对象;否则返回新对象
  return (typeof result === 'object' && result !== null) ? result : obj;
}

// 示例构造函数
function Person(name, age) {
  this.name = name;
  this.age = age;
}

// 使用自定义的myNew方法创建对象实例
const person = myNew(Person, 'John', 25);
console.log(person.name); // 输出: John
console.log(person.age); // 输出: 25
这个自定义的 myNew 方法模拟了 new 操作符的行为,它接受构造函数和参数,并返回一个新的对象实例。

panpanxuebing

panpanxuebing commented on Dec 10, 2024

@panpanxuebing
/**
 * 手写 new 方法
 * 1. 生成一个新对象 obj
 * 2. 将 obj 的原型指向构造函数的原型
 * 3. 将构造函数的this指向 obj,然后执行
 * 4. 构造函数返回值如果是对象,则返回这个对象,否则返回  obj
 * */

function myNew () {
  const [Ctor, ...args] = arguments 
  const obj = {}
  // const obj = object(Ctor.prototype)
  obj.__proto__ = Ctor.prototype
  const res = Ctor.apply(obj, args)
  return typeof res === 'object' ? res : obj
}

function Ainimal (name) {
  this.name = name
}

Ainimal.prototype.say = function () {
  console.log('i am a' + this.name)
}

const cat = myNew(Ainimal, 'cat')
console.log(cat)
cat.say() // i am a cat
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    jsJavaScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @smile-2008@haizhilin2013@zebratt@never123450@bWhirring

        Issue actions

          [js] 第22天 你对new操作符的理解是什么?手动实现一个new方法 · Issue #76 · haizlin/fe-interview