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

第 14 题:情人节福利题,如何实现一个 new #12

Open
atheist1 opened this issue Feb 14, 2019 · 52 comments
Open

第 14 题:情人节福利题,如何实现一个 new #12

atheist1 opened this issue Feb 14, 2019 · 52 comments

Comments

@atheist1
Copy link

atheist1 commented Feb 14, 2019

鉴于十三题可以说的东西很多,就先看了十四题,作为一个单身狗,new的对象都是一个小狗啊

// 实现一个new
var Dog = function(name) {
  this.name = name
}
Dog.prototype.bark = function() {
  console.log('wangwang')
}
Dog.prototype.sayName = function() {
  console.log('my name is ' + this.name)
}
let sanmao = new Dog('三毛')
sanmao.sayName()
sanmao.bark()
// new 的作用
// 创建一个新对象obj
// 把obj的__proto__指向Dog.prototype 实现继承
// 执行构造函数,传递参数,改变this指向 Dog.call(obj, ...args)
// 最后把obj赋值给sanmao
var _new = function() {
  let constructor = Array.prototype.shift.call(arguments)
  let args = arguments
  const obj = new Object()
  obj.__proto__ = constructor.prototype
  constructor.call(obj, ...args)
  return obj
}
var simao = _new(Dog, 'simao')
simao.bark()
simao.sayName()
console.log(simao instanceof Dog) // true
@zwmmm
Copy link

zwmmm commented Feb 14, 2019

这样写是不是简单点啊

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

@atheist1
Copy link
Author

@zwmmm 你是对的,我写的有点问题

@hwxy
Copy link

hwxy commented Feb 15, 2019

function _new(fn, ...arg) {
var obj = Object.create(fn.prototype);
fn.call(obj, ...arg);
let result = fn();
return Object.prototype.toString.call(result) == '[object Object]' ? result : obj;
}

@nnecec
Copy link

nnecec commented Feb 18, 2019

function _new(){
  const obj = {}
  const Constructor = Array.prototype.shift.call(arguments)

  obj.__proto__ = Constructor.prototype
  const result = Constructor.apply(obj, arguments)

  return typeof result === 'object' ? result : obj
}

@chenjigeng
Copy link

/**
 *
 *
 * @param {Function} fn
 */
function _new(fn, ...args) {
	const obj = {};
	Object.setPrototypeOf(obj, fn.prototype);
	const result = fn.apply(obj, args);
	// 根据规范,返回 null 和 undefined 不处理,依然返回obj
	return result instanceof Object ? result : obj;
}

@ruochuan12
Copy link

之前写过一篇模拟实现new的文章~
面试官问:能否模拟实现JSnew操作符

我的这篇文章主要提出了对返回值是函数和对象的处理,还有对new.target的简单处理。

// 去除了注释
function newOperator(ctor){
    if(typeof ctor !== 'function'){
      throw 'newOperator function the first param must be a function';
    }
    newOperator.target = ctor;
    var newObj = Object.create(ctor.prototype);
    var argsArr = [].slice.call(arguments, 1);
    var ctorReturnResult = ctor.apply(newObj, argsArr);
    var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null;
    var isFunction = typeof ctorReturnResult === 'function';
    if(isObject || isFunction){
        return ctorReturnResult;
    }
    return newObj;
}

@GuoYuFu123
Copy link

我也贴一个
function Dog(name) {
this.name = name
this.say = function () {
console.log('name = ' + this.name)
}
}
function Cat(name) {
this.name = name
this.say = function () {
console.log('name = ' + this.name)
}
}
function _new(fn, ...arg) {
const obj = {};
obj.proto = fn.prototype;
fn.apply(obj, arg)
return Object.prototype.toString.call(obj) == '[object Object]'? obj : {}
}
var dog = _new(Dog,'xxx')
dog.say() //'name = xxx'
console.log(dog instanceof Dog) //true
var cat = _new(Cat, 'carname');
cat.say() //'name = carname'
console.log(cat instanceof Cat) //true

@flysme
Copy link

flysme commented Feb 19, 2019

写的真好

@lkoma
Copy link

lkoma commented Feb 21, 2019

这样写是不是简单点啊

function  _new(fn,... arg){
     const  obj  =  Object。创造(fn。原型);
    const  ret  =  fn。申请(obj,arg);
    返回 ret instanceof  对象 ?ret  obj;
}

这样ret不是一直都是undefined吗?res instanceof Object就一直是false啊

@atheist1
Copy link
Author

这样写是不是简单点啊

function  _new(fn,... arg){
     const  obj  =  Object。创造(fn。原型);
    const  ret  =  fn。申请(obj,arg);
    返回 ret instanceof  对象 ?ret  obj;
}

这样ret不是一直都是undefined吗?res instanceof Object就一直是false啊

当然不是,这里判断构造函数执行的返回类型,如果构造函数执行结果返回的是个对象不就是true了

@zwmmm
Copy link

zwmmm commented Feb 25, 2019

这样写是不是简单点啊

function  _new(fn,... arg){
     const  obj  =  Object。创造(fn。原型);
    const  ret  =  fn。申请(obj,arg);
    返回 ret instanceof  对象 ?ret  obj;
}

这样ret不是一直都是undefined吗?res instanceof Object就一直是false啊

构造函数是默认返回对象的(但是这个是没有返回值的)。但是你也可以自己return一个对象。

@Hiker9527
Copy link

先理清楚 new 关键字调用函数都的具体过程,那么写出来就很清楚了

  1. 首先创建一个空的对象,空对象的__proto__属性指向构造函数的原型对象
  2. 把上面创建的空对象赋值构造函数内部的this,用构造函数内部的方法修改空对象
  3. 如果构造函数返回一个非基本类型的值,则返回这个值,否则上面创建的对象
function _new(fn, ...arg) {
    var obj = Object.create(fn.prototype);
    const result = fn.apply(obj, ...arg);
    return Object.prototype.toString.call(result) == '[object Object]' ? result : obj;
}

@cliYao
Copy link

cliYao commented Apr 17, 2019

function _new(fn , ...args){
const obj={}
const Constructor = fn
obj.proto = Constructor.prototype
const result = Constructor.call(obj , ...args)
return typeof result === "object" ? result : obj
}

@yygmind yygmind changed the title 14题 情人节快乐! 第 14 题:情人节福利题,如何实现一个 new Apr 26, 2019
@ZTH520
Copy link

ZTH520 commented Jul 9, 2019

function _new(fn, ...args){
let obj = {}
Object.setPrototypeOf(obj,fn.prototype)
let result = fn.apply(obj,args)
return result instanceof Object ? result : obj
}

@nano-papa
Copy link

proto

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

@arixse
Copy link

arixse commented Jul 10, 2019

function __new__(_Contructor,...args) {
	let obj = new Object();
	obj.__proto__ = _Contructor.prototype;
	_Contructor.apply(obj,args);
	return obj;
}

image

@harryliuy
Copy link

先理清楚 new 关键字调用函数都的具体过程,那么写出来就很清楚了

  1. 首先创建一个空的对象,空对象的__proto__属性指向构造函数的原型对象
  2. 把上面创建的空对象赋值构造函数内部的this,用构造函数内部的方法修改空对象
  3. 如果构造函数返回一个非基本类型的值,则返回这个值,否则上面创建的对象
function _new(fn, ...arg) {
    var obj = Object.create(fn.prototype);
    const result = fn.apply(obj, ...arg);
    return Object.prototype.toString.call(result) == '[object Object]' ? result : obj;
}

两处错误

@harryliuy
Copy link

这样写是不是简单点啊

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

关于为什么最后要判断 return ret instanceof Object ? ret : obj
instanceof Object 来判断是否是对象,包含Array,Object,Function、RegExp、Date
构造函数是可以自己指定返回一个对象的

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

  function A(d) {
    this.d = d;
    return {
      a: 6
    };
  }
  console.log(new A(123));  //{a: 6}
  console.log(_new(A, 123)); //A {d: 123}

@f4762690
Copy link

鉴于十三题可以说的东西很多,就先看了十四题,作为一个单身狗,new的对象都是一个小狗啊

// 实现一个new
var Dog = function(name) {
  this.name = name
}
Dog.prototype.bark = function() {
  console.log('wangwang')
}
Dog.prototype.sayName = function() {
  console.log('my name is ' + this.name)
}
let sanmao = new Dog('三毛')
sanmao.sayName()
sanmao.bark()
// new 的作用
// 创建一个新对象obj
// 把obj的__proto__指向Dog.prototype 实现继承
// 执行构造函数,传递参数,改变this指向 Dog.call(obj, ...args)
// 最后把obj赋值给sanmao
var _new = function() {
  let constructor = Array.prototype.shift.call(arguments)
  let args = arguments
  const obj = new Object()
  obj.__proto__ = constructor.prototype
  constructor.call(obj, ...args)
  return obj
}
var simao = _new(Dog, 'simao')
simao.bark()
simao.sayName()
console.log(simao instanceof Dog) // true

内部创建对象的时候也不能使用new来吧..

@mongonice
Copy link

mongonice commented Jul 16, 2019

new运算符都做了哪些操作呢?
1、创建了一个新对象(是Object类型的数据)
2、将this指向新对象
3、将创建的对象的原型指向构造函数的原型
4、返回一个对象(如果构造函数本身有返回值且是对象类型,就返回本身的返回值,如果没有才返回新对象)

下面就写一个实现new功能的函数:

function mynew () {
     // 1、创建一个新对象
     const obj = Object.create({});    // 也可以写成 const obj = {}
     // 2、将this指向该对象
     let Fn = [].shift.call(arguments);    // 把构造函数分离出来
     let returnObj = Fn.apply(obj, arguments);     // 通过apply将this指向由Fn变为obj
     
     // 3、将新对象的原型指向构造函数的原型
     obj.__proto__ = Fn.prototype
     
    // 4、返回对象(如果构造函数有返回对象,那么就返回构造函数的对象,如果没有就返回新对象)
    return Object.prototype.toString.call(returnObj) == '[object Object]' ? returnObj : obj;
}

@wang-hongliang
Copy link

// 首先创建一个空的对象,空对象的__proto__属性指向构造函数的原型对象
// 把上面创建的空对象赋值构造函数内部的this,用构造函数内部的方法修改空对象
// 如果构造函数返回一个非基本类型的值,则返回这个值,否则上面创建的对象

@Mini-Web
Copy link

function miniNew(...args) {
    const [constructor, ...otherArgs] = args;
    
    if(typeof constructor !== 'function') {
        throw new TypeError('constructor is not a function');
    };

    // 1~2 步骤简单写法 const obj = Object.create(constructor.prototype);   

    // 1.创建一个空的简单JavaScript对象(即{});
    const obj = {};   

    // 2.链接该对象(即设置该对象的构造函数)到另一个对象 ;
    Object.setPrototypeOf(obj, constructor.prototype)

    // 3.将步骤1新创建的对象作为this的上下文
    const result = constructor.apply(obj, otherArgs);

    // 4.如果该函数没有返回对象,则返回this。
    return isPrimitive(result) ? obj : result
}

function isPrimitive(value) {
    return value == null || ['string', 'number', 'boolean', 'symbol'].includes(typeof(value))
}

function A(x, y) {
    this.x = x;
    this.y = y;
}

var a = miniNew(A, 1,2)

@ravencrown
Copy link

function New (func) {
    var res = {}
    if (func.prototype !== null) {
        res.__protp__ = func.prototype
    }
    var ret = func.apply(res, Array.prototype.slice.call(arguments, 1))
    if ((typeof ret === 'object' || typeof ret === 'function') && ret !== null) {
        return ret
    }
    return res
}

@Nina0408
Copy link

function create(){
var obj = new Object();
var src = Array.prototype.shift.call(arguments);
if (src == null) {
return obj;
}
obj._proto = src.prototype;
obj.call(src, ...arguments);
return obj;
}

@iendeavor
Copy link

應另外確認null,new關鍵字針對null是處理成回傳this

function _new(fn, ...args) {
  const object = Object.create(fn.prototype)
  const result = fn.call(object, ...args)
  return typeof result === 'object' && result !== null ? result : object
}

@caixianglin
Copy link

function _new(fn, ...arg) {
var obj = Object.create(fn.prototype);
fn.call(obj, ...arg);
let result = fn();
return Object.prototype.toString.call(result) == '[object Object]' ? result : obj;
}

call和apply在绑定this时会立即执行,bind才是单纯绑定this,所以你得

fn.call(obj, ...arg); // 已经是执行了
let result = fn();
上面换成bind,或直接let result = fn.call

@wython
Copy link

wython commented Jul 22, 2019

建议去mdn看下__proto__,这个属性性能极差,而且已经废弃(不安全)。应该在构造函数的原型上做手脚,而不是利用实例的__proto__做手脚。实例和构造函数还是要区分的。

@NuoHui
Copy link

NuoHui commented Jul 22, 2019

function _new(fx, ...args) {
  // 创建一个新对象
  // 对象的__proto__指向构建函数的prototype
  const target = Object.create(fx.prototype);
  // 执行代码时候, 绑定this指向新的对象
  const execResult = fx.apply(target, args);
  // 如果构造函数有返回值, 返回构造函数的值, 否则返回新对象
  return Object.prototype.toString.call(execResult) === '[object Object]' ? execResult : target;
};

@Jouryjc
Copy link

Jouryjc commented Jul 24, 2019

constructor.call(obj, ...args)

这里需要返回值,判断是不是对象,是的话返回该对象,不是的话返回obj

@Y-qwq
Copy link

Y-qwq commented Aug 5, 2019

先理清楚 new 关键字调用函数都的具体过程,那么写出来就很清楚了

  1. 首先创建一个空的对象,空对象的__proto__属性指向构造函数的原型对象
  2. 把上面创建的空对象赋值构造函数内部的this,用构造函数内部的方法修改空对象
  3. 如果构造函数返回一个非基本类型的值,则返回这个值,否则上面创建的对象
function _new(fn, ...arg) {
    var obj = Object.create(fn.prototype);
    const result = fn.apply(obj, ...arg);
    return Object.prototype.toString.call(result) == '[object Object]' ? result : obj;
}

const result = fn.apply(obj, ...arg);的apply应该改为call吧,或者把...去掉

@houmao
Copy link

houmao commented Aug 14, 2019

class Foo {
  constructor() {
    this.foo = 42;
  }
}

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

new Foo(); //{foo: 42}
_new(Foo); //TypeError: Class constructor Foo cannot be invoked without 'new'

这个_new并不等价new

@weixiaoxu123
Copy link

weixiaoxu123 commented Aug 16, 2019

var obj = new A()
new 操作:
var obj = {} obj.__proto__ = A.prototype A.call(obj,arguments)

@liuxingit
Copy link

判断ret的作用是?

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

@zhoushaw
Copy link

判断ret的作用是?

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

WX20190819-182759@2x

详细可参考mdn关于new运算符第四条定义

@ACE-LV ACE-LV mentioned this issue Sep 21, 2019
@aeolusheath
Copy link

new 关键点

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。new 关键字会进行如下的操作:

  • 创建一个空的简单JavaScript对象(即{});

  • 链接该对象(即设置该对象的构造函数)到另一个对象 ;

  • 将步骤1新创建的对象作为this的上下文 ;

  • 如果该函数没有返回对象,则返回this。 【很关键】


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

Dog.prototype.sayHi = function() {
  console.log('hello its me')
}

Dog.prototype.sayName = function() {
  console.log('my name is ' + this.name)
}

方法一

// 实现一个new
// 1,创建一个新的对象obj
// 2,将obj的__proto__指向Dog.prototype实现继承
// 3,执行构造函数,传递参数,改变this指向

// 方法一
function _new() {
  let args = arguments
  let constructor = Array.prototype.shift.call(args)
  const obj = new Object()
  Object.setPrototypeOf(obj, constructor.prototype)// 和下面一句是同样的效果
  // obj.__proto__ = constructor.prototype
  constructor.call(obj, ...args)
  return obj
}

方法二

function _new2(fn, ...arg) {
   // 这一句话只是构造了一个对象,这个对象的__proto__=== fn.prototype
   var obj = Object.create(fn.prototype)
   // 并没有给这个对象赋值,将fn的this对象设置为obj
   // call 是列表, apply是数组
   const ret = fn.call(obj, ...arg) 
   // 为啥这里需要判断一下ret,根据new的定义,如果构造函数没有返回一个对象,那么返回this对象,this当前就是obj
   return ret instanceof Object ? ret : obj 
}

@xiaoxixi6633
Copy link

xiaoxixi6633 commented Sep 28, 2019

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

还可以这么写

  obj.__proto__ = fn.prototype
  const result = fn.call(obj, ...args)
  return result instanceof Object ? result: obj
}

@yangwanging
Copy link

先理清楚 new 关键字调用函数都的具体过程,那么写出来就很清楚了

  1. 首先创建一个空的对象,空对象的__proto__属性指向构造函数的原型对象
  2. 把上面创建的空对象赋值构造函数内部的this,用构造函数内部的方法修改空对象
  3. 如果构造函数返回一个非基本类型的值,则返回这个值,否则上面创建的对象
function _new(fn, ...arg) {
    var obj = Object.create(fn.prototype);
    const result = fn.apply(obj, ...arg);
    return Object.prototype.toString.call(result) == '[object Object]' ? result : obj;
}

fn.apply(obj, ...arg);应该用call或者arg

@calmchang
Copy link

请问大家,有用自己写的这个 _new 方法试过 _new(Number,123)或_new(String,"abc") 吗?

@calmchang
Copy link

calmchang commented Nov 3, 2019

改进一下

function create(fn,...args){
  if(fn===null)return null;
  let obj =  Object.create(fn.prototype);
  let ret= fn.apply(obj,args);
  if( ['string','number','boolean'].includes( typeof ret ) ){
    ret=new fn(args);
    return ret;
  }
  return typeof ret==='object'?ret:obj;
}

create(Number,123)
create(String,'abc')
以上情况也支持了

@52javascript
Copy link

52javascript commented Nov 6, 2019

function Person(name,age){
    this.name=name;
    this.age=age;
    this.sayName=function(){
        console.log(this.name);
    };
    return{
        name:this.name,
        age:this.age,
        sayName:this.sayName
    }
}

Person.prototype.sayHi=function(){
    console.log("I am "+this.name);
};

function foo() {
    let constructor = [].shift.apply(arguments)
    let obj = Object.create(constructor.prototype)
    let res = constructor.call(obj, ...arguments)
    if (typeof res === 'object') {
        res.__proto__ = obj.__proto__
        return res
    }
    if (typeof res === 'number' ||  typeof res === 'string') {
        return res
    }
    return obj
}

let a = foo(Person, 1, 2)
console.log(a.name)
console.log(a.age)
console.log(a.sayHi())


let b = foo(Number, 1)
console.log(b)

@gaoxinxiao
Copy link

/**
* 实现思想
* 1.首先创建一个对象
* 2.取到arguments的第一个参数也就是传进来的即将被实例化的函数赋值给Con
* 3.将Con.prototyp绑定到当前创建的obj的__proto__ 因为要访问构造函数里原型的属性
* 4.通过apply改变构造函数内部的指向
* 5.最后判断一下构造函数的返还参数 是否是对象
* */

    function $new() {
        var obj = new Object()
        Con = [].shift.call(arguments)
        obj.__proto__ = Con.prototype
        var res = Con.apply(obj, arguments)
        return res instanceof Object ? res : obj
    }

@wjx25zj
Copy link

wjx25zj commented Jan 15, 2020

// method2
function myNew() {
    var [param1, args] = [...arguments];
    var target = {};
    target.__proto__ = Person.prototype
    var res = param1.call(target, args)
    if (res) {
        return res;
    } else {
        return target
    }
}

// method2
function myNew2() {
    var [param1, args] = [...arguments];
    var target = Object.create(Person.prototype)
    var res = param1.call(target, args)
    if (res) {
        return res;
    } else {
        return target
    }
}

//--------------------------------------------------------------------

function Person(name) {
    this.name = name;
}
Person.prototype.sayName = function () {
    console.log(this.name);
}
var per = myNew(Person, '张安');
// var per = myNew2(Person, '张安');
per.sayName();
console.log(per);


@yayxs
Copy link

yayxs commented Apr 22, 2020

JavaScript中的new操作符

面试题

根据new操作符相关的知识点一般会 延伸出以下的面试题 ,面试官你是否有很多问号

  • 问题一:new 之后都做了些什么??
  • 问题二:能否手写new操作符原理??

mdn关于new运算符关键字的描述

  1. 创建一个空的简单JavaScript对象(即{});
  2. 链接该对象(即设置该对象的构造函数)到另一个对象 ;
  3. 将步骤1新创建的对象作为this的上下文 ;
  4. 如果该函数没有返回对象,则返回this

以上4条是MDN 上关于new 操作符(或者说关键字)的面试,简单的来体验下利用构造函数来new 一个对象

var self;

function Person(name) {
  console.log(this);
  self = this;
  this.name = name;
}
let p = new Person("张三");
console.log(p);
console.log(self === p); // true 构造函数中的this 绑定在了p这个对象上
console.log(p.__proto__ === Person.prototype); // 对象p的原型属性指向构造函数的原型,这样也就保证了实例能够访问在构造函数原型中定义的属性和方法。

然后在构造函数添加原型方法

function Persion(name){
    this.name = name
}
console.log(Persion.prototype)
Persion.prototype.sayHello = function(){
    console.log(this) // 指向构造出的对象
    console.log(this.name) // 小明
}

let xiaoMing = new Persion('小明')
xiaoMing.sayHello()

经过上文的简单案例我们可以得知,

  • new 一个构造函数得到一个对象,它的原型属性(也就是__ proto __)与该构造函数的原型是全等

  • new 通过构造函数 Persion 创建出来的实例可以访问到构造函数中的属性,就行这样

    console.log(xiaoMing.name) // 小明
  • 言简意赅:new出来的实例对象通过原型链和构造函数联系起来

构造函数说白了也是一个函数,那是函数就可以有返回值

function Person(name) {
  this.name = name;
  //   return 1; // 返回内部新创建的对象
  //   return "1"; // 返回内部新创建的对象
  // return null; // 返回内部新创建的对象
  //   return undefined; // 返回内部新创建的对象
  //   return {}; // {} // 直接返回
  return function () {}; // 直接返回
  return [1]; // [1] // 直接返回
}
let p = new Person("李四");
console.log(p);

有了给构造函数返回一个值得想法,那就通过不同的数据类型 进行测试得出结论

  • 不同的数据类型返回的效果是不一样的,像数字1 字符串”1“ ,返回的依然是内部创建的对象
  • 那如果返回一个对象({})或者说数组(【】) 都会直接返回回去

小结

也就是说,构造函数一般不需要return

  • 返回一般的数据类型吧,不起作用
  • 返回对象吧, new 的意义又何在呢

手写一个自己的myNew

如果自己实现一个new 的话,首先要满足它的几点效果

  1. 一个构造函数会返回一个对象,那函数里就应该有对象

    let obj ={}
  2. 并将其__proto__属性指向构造函数的prototype属性

    obj.__proto__ = constructor.prototype;
  3. 调用构造函数,绑定this

    constructor.apply(obj, args)
  4. 返回原始值需要忽略,返回对象需要正常处理

    res instanceof Object ? res : obj

测试成果

function myNew() {
  let [constructor, ...args] = [...arguments];
  let obj = {};
  obj.__proto__ = constructor.prototype;

  let res = constructor.apply(obj, args);
  return res instanceof Object ? res : obj;
}

function Person(name) {
  this.name = name;
//   return {};
}

Person.prototype.sayHi = function () {
  console.log(`原型方法中的函数--${this.name}`);
};
let p1 = myNew(Person, "测试");
// console.log(p1)
p1.sayHi();
console.log(p1.name);

@lunhui1994
Copy link

  1. 创建一个空对象obj。 (1,3可以使用const obj = Object.creat(fn.prototype))
  2. 原型继承。
  3. 构造函数继承。
  4. 返回对象(若构造函数中return了引用类型比如数组,对象等。new会返回该引用对象,否则将返回初始化之后的对象obj。)

@JTangming
Copy link

JTangming commented May 31, 2020

实例代码:

function Person(name){ 
  this.name = name;
} 
Person.prototype.getName = function() {
    return this.name;
}

var p1 = new Person('Dan');

console.log(p1); // Person {name: "Dan"}
console.log(p1.__proto__ === Person.prototype); // true

new 操作符实现了如下的功能:

  • 创建一个新对象
  • 新对象继承了构造函数的原型
  • 构造函数的 this 指向新对象,并执行构造函数
  • 最后隐式的返回 this,即新对象

前面提到了隐式的返回,如果是显式返回呢?

构造函数如果返回基本类型,则还是会返回原来的 this (新对象)。如果返回的是引用类型,则返回该返回值。(可以自己在上面例子加上代码验证一下)

new 操作符的模拟实现

function createNew(func, ...args) {
    let obj = {};
    // 将空对象指向构造函数的原型链
    Object.setPrototypeOf(obj, func.prototype);
    // obj 绑定到构造函数上,便可以访问构造函数中的属性
    let result = func.apply(obj, args);
    // 如果返回的 result 是一个对象则返回该对象,new 方法失效,否则返回 obj
    return result instanceof Object ? result : obj;
}

Object.setPrototypeOf()是ECMAScript 6最新草案中的方法,相对于 Object.prototype.proto ,它被认为是修改对象原型更合适的方法

写个测试用例:

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

let test = createNew(Test, 'Dan', 20);
console.log(test.name); // Dan
console.log(test.age); // 20

Reference

@Ke1vin4real
Copy link

function _new(fn, ...arg) {
    const obj = Object.create(fn.prototype);
    const ret = fn.apply(obj, arg);
    return ret instanceof Object ? ret : obj;
}
_new(Number, 1).toFixed(2) // Uncaught TypeError: Number.prototype.toFixed requires that 'this' be a Number

这个_new出来的对象调用原型上的方法会报错?

@tjwyz
Copy link

tjwyz commented Jul 16, 2020

默写高赞...

function _new (fn , ...arg) {
    let obj = Object.create(fn.prototype);
    let ret = fn.apply(obj, arg);
    // 构造函数本就可以返回一个类对象...  
    // 手动返回基础类型时 or 正常不return时 才返回this
    // 
    // 但是fn不是构造函数... 就是正常执行下.. 为了和正常的构造函数保持一致所以修正一下
    return ret instanceof Object ? ret : obj;
}

@zengkaiz
Copy link

zengkaiz commented Aug 4, 2020

new 都做了什么?
1、创建一个新的实例对象
2、将this指向新的实例对象
3、新对象的__proto__属性指向构造函数的原型对象
4、返回值
第一种实现:

function _new(Func, ...args){
  let obj = {}
  obj.__proto__ = Func.prototype
  let result = Func.call(obj, ...args)
 return (result!== null && /^(object)|(function)$/.test(typeof result)) ? result : obj
}

第二种实现:

function _new(Func, ...args){
 let obj = Object.create(Func.prototype)
 let result = Func.call(obj, ...args)
return (result!== null && /^(object)|(function)$/.test(typeof result)) ? result : obj
}

@promotion-xu
Copy link

promotion-xu commented Aug 20, 2020

// 实现一个new
// 1. 创建一个空对象,并指向构造函数的原型
// 2. 将空对象指向构造函数的this, 用构造函数内部方法修改空对象
// 3. 如果构造函数返回一个非基本类型的值,则返回这个值,否则返回空对象

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

function _new(fn, ...args) {
  const obj = Object.create(fn.prototype);
  const result = fn.apply(obj, args);
  return result instanceof Object ? result : obj;
}

console.log(_new(Person, "xuzhen", "18"));

@zuibunan
Copy link

先理清楚 new 关键字调用函数都的具体过程,那么写出来就很清楚了

  1. 首先创建一个空的对象,空对象的__proto__属性指向构造函数的原型对象
  2. 把上面创建的空对象赋值构造函数内部的this,用构造函数内部的方法修改空对象
  3. 如果构造函数返回一个非基本类型的值,则返回这个值,否则上面创建的对象
function _new(fn, ...arg) {
    var obj = Object.create(fn.prototype);
    const result = fn.apply(obj, ...arg);
    return Object.prototype.toString.call(result) == '[object Object]' ? result : obj;
}

@Hiker9527
构造函数返回 String, Number, Boolean等对象也是可以的,而这些对象toString后并不是[object Object]

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

@Jiujiuou
Copy link

Jiujiuou commented Mar 3, 2021

function _new(){
  const obj = {}
  const Constructor = Array.prototype.shift.call(arguments)

  obj.__proto__ = Constructor.prototype
  const result = Constructor.apply(obj, arguments)

  return typeof result === 'object' ? result : obj
}
// result 可能返回的是null,当result是null当时候就应该返回obj了,改一下你的代码
function _new(){
  const obj = {}
  const Constructor = Array.prototype.shift.call(arguments)

  obj.__proto__ = Constructor.prototype
  const result = Constructor.apply(obj, arguments)

  return typeof result === 'object' ? result || obj: obj
}

@crush12132
Copy link

这个题的题目描述是啥...

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

No branches or pull requests