Daily-Interview-Question icon indicating copy to clipboard operation
Daily-Interview-Question copied to clipboard

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

Open atheist1 opened this issue 6 years ago • 53 comments

鉴于十三题可以说的东西很多,就先看了十四题,作为一个单身狗,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

atheist1 avatar Feb 14 '19 02:02 atheist1

这样写是不是简单点啊

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

zwmmm avatar Feb 14 '19 02:02 zwmmm

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

atheist1 avatar Feb 14 '19 03:02 atheist1

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

hwxy avatar Feb 15 '19 01:02 hwxy

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
}

nnecec avatar Feb 18 '19 04:02 nnecec

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

chenjigeng avatar Feb 18 '19 09:02 chenjigeng

之前写过一篇模拟实现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;
}

ruochuan12 avatar Feb 18 '19 15:02 ruochuan12

我也贴一个 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

GuoYuFu123 avatar Feb 19 '19 02:02 GuoYuFu123

写的真好

flysme avatar Feb 19 '19 06:02 flysme

这样写是不是简单点啊

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

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

lkoma avatar Feb 21 '19 06:02 lkoma

这样写是不是简单点啊

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

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

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

atheist1 avatar Feb 23 '19 01:02 atheist1

这样写是不是简单点啊

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

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

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

zwmmm avatar Feb 25 '19 02:02 zwmmm

先理清楚 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 avatar Apr 02 '19 02:04 Hiker9527

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 }

cliYao avatar Apr 17 '19 05:04 cliYao

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

ZTH520 avatar Jul 09 '19 06:07 ZTH520

proto

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

nano-papa avatar Jul 09 '19 07:07 nano-papa

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

image

arixse avatar Jul 10 '19 08:07 arixse

先理清楚 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 avatar Jul 15 '19 02:07 harryliuy

这样写是不是简单点啊

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}

harryliuy avatar Jul 15 '19 03:07 harryliuy

鉴于十三题可以说的东西很多,就先看了十四题,作为一个单身狗,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来吧..

f4762690 avatar Jul 15 '19 03:07 f4762690

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

mongonice avatar Jul 16 '19 03:07 mongonice

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

wang-hongliang avatar Jul 16 '19 05:07 wang-hongliang

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)

Mini-Web avatar Jul 18 '19 03:07 Mini-Web

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
}

ravencrown avatar Jul 18 '19 07:07 ravencrown

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

Nina0408 avatar Jul 19 '19 03:07 Nina0408

應另外確認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
}

soc221b avatar Jul 19 '19 06:07 soc221b

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

caixianglin avatar Jul 21 '19 02:07 caixianglin

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

wython avatar Jul 22 '19 03:07 wython

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

NuoHui avatar Jul 22 '19 10:07 NuoHui

constructor.call(obj, ...args)

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

Jouryjc avatar Jul 24 '19 01:07 Jouryjc

先理清楚 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吧,或者把...去掉

Y-qwq avatar Aug 05 '19 08:08 Y-qwq