Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
haizhilin2013 opened this issue May 7, 2019 · 31 comments
Labels
js JavaScript

Comments

@haizhilin2013
Copy link
Collaborator

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

@haizhilin2013 haizhilin2013 added the js JavaScript label May 7, 2019
@AnsonZnl
Copy link
Contributor

AnsonZnl commented May 8, 2019

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
Copy link

BeADre commented May 8, 2019

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

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

@tzjoke
Copy link

tzjoke commented May 29, 2019

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

@myprelude
Copy link

myprelude commented Jun 13, 2019

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

@bWhirring
Copy link

bWhirring commented Jul 9, 2019

  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
Copy link

Vi-jay commented Jul 29, 2019

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
Copy link

/**
 * 模拟实现 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
Copy link

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

@0x3c
Copy link

0x3c commented Feb 21, 2020

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;
}

@13168335674
Copy link

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

@blueRoach
Copy link

对一个实例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
Copy link

推荐看 mdn new运算符

@276378532
Copy link

        // 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;
        }

@MrZ2019
Copy link

MrZ2019 commented Sep 22, 2020

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

@bozaigao
Copy link

bozaigao commented Oct 6, 2020

new操作符做了四件事:初始化一个对象、将对象的原型指向构造函数的prototype、将构造函数的this指向这个对象、返回这个对象。

function objectFactory() {
    let object = new Object(), Constractor = [].shift.call(arguments);
    object.__proto__ = Constractor.prototype;
    Constractor.apply(object, arguments)
    return object;
}

@m7yue
Copy link

m7yue commented Oct 10, 2020

const myNew = (Ctor, ...args) => {
  let instance = {}
  Object.setPrototypeOf(instance, Ctor.prototype)
  const res = Ctor.apply(instance, args)

  // 如果构造方法已经return了一个对象,那么就返回该对象, 否则返回myNew创建的新对象 obj
  if (typeof res === "function" || (typeof res === "object" && res !== null)) {
    return res
  }
  return instance
}
function F(name) {
  this.name = name
}
const f = myNew(F, '7 yue')
console.log(f)
console.log(f instanceof F)

@maxthonl
Copy link

maxthonl commented Oct 27, 2020

Reflect.construct(target, argumentsList[, newTarget]) // 新的思路

@zebratt
Copy link

zebratt commented Jan 19, 2021

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
Copy link

overwatch555 commented Mar 1, 2021

    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
Copy link

对一个实例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
Copy link

实例化一个对象。

@zxcdsaqwe123
Copy link

实例化对象

@amikly
Copy link

amikly commented Nov 9, 2021

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
Copy link

flashyy commented Feb 17, 2022

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

@github-cxtan
Copy link

创建一个新对象
将构造函数中的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
Copy link

ilss commented Mar 8, 2022

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

@yxllovewq
Copy link

yxllovewq commented Mar 9, 2022

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
Copy link

// 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
Copy link

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

@wyy-g
Copy link

wyy-g commented Sep 12, 2022

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
Copy link

never123450 commented Sep 4, 2023

在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 操作符的行为,它接受构造函数和参数,并返回一个新的对象实例。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js JavaScript
Projects
None yet
Development

No branches or pull requests