Giter VIP home page Giter VIP logo

Comments (160)

wcflmy avatar wcflmy commented on May 2, 2024 103

objectFactory函数里最后一行建议改成“return typeof ret === 'object' ? ret||obj : obj;”,否则如果在Otaku函数里面return null,会有问题的。

from blog.

strongcode9527 avatar strongcode9527 commented on May 2, 2024 90

var obj = Object.create(null)
这样创建会比较好

from blog.

jawil avatar jawil commented on May 2, 2024 71
function objectFactory() {

    var obj = new Object(),//从Object.prototype上克隆一个对象

    Constructor = [].shift.call(arguments);//取得外部传入的构造器

    var F=function(){};
    F.prototype= Constructor.prototype;
    obj=new F();//指向正确的原型

    var ret = Constructor.apply(obj, arguments);//借用外部传入的构造器给obj设置属性

    return typeof ret === 'object' ? ret : obj;//确保构造器总是返回一个对象

};

学习学习,之前一直是理论了解new,也来实践模拟一把😄

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024 64

我也好想写React呐,不过React估计是第三个或者第四个系列,现在第一个系列还没有发布完呢,第二个系列估计要写20篇左右,写到React,估计都下下个月了……看来是赶不上这波撕逼的浪潮了~😂😂😂


实际上,过了一年都没有开始写 React 系列 T^T

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024 39

@strongcode9527 @a1029563229 @lzayoih 我也发现了这个问题,测试 demo 为:

function Otaku (age) {}

Otaku.prototype.sayHello = function() {
	console.log('hello')
}

var person = objectFactory(Otaku, 'Kevin', '18');
console.log(person)
person.sayHello() //???

如果使用 Object.create(null),person.sayHello 就会报错,使用 new Object(),会正常打印 hello。

查看由两种方式生成的 person 对象,第一个是由 Object.create 生成的,第二个是 new Object 生成的

default

两者的区别就在于 __proto__ 一个是实的,一个是虚的,由此我们可以猜测第一种方式是把 __proto__ 当成了一个属性值,而非去修改了原型!

原因其实在 《JavaScript深入之从原型到原型链》中有提过:

__proto__ ,绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Person.prototype 中,实际上,它是来自于 Object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.__proto__ 时,可以理解成返回了 Object.getPrototypeOf(obj)。

default

from blog.

huangmxsysu avatar huangmxsysu commented on May 2, 2024 36

话说__proto__一个实一个虚的问题不是因为Object.create(null)是原型链顶端导致var obj = Object.create(null)之后 obj根本访问不到__proto__这个原型属性导致后面的obj.proto = Constructor.prototype使它的__proto__是实的,成为一个属性,从而没有修改原型。
我觉得是不是可以不需要

var obj = new Object()
obj.__proto__ = Constructor.prototype

直接用

var obj = Object.create(Constructor.prototype)

是一样也可以的吧?

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024 20

并没有什么区别吧,毕竟最后都是要更改原型的


以上是最初的看法,两者有很大的不同,欢迎下拉看两者之间的区别。

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024 17

@xdwxls 其实就是将 obj 的原型指向 Constructor.prototype,只不过@jawil 的写法中在 new 的模拟实现中又用到了 new 😂

from blog.

RayJune avatar RayJune commented on May 2, 2024 9

感谢作者 @mqyqingfeng ,学到了很多,也写一个自己优化的版本

function objectFactory() {
  var args = Array.prototype.slice.call(arguments);
  var Constructor = args.shift();
  var instance = Object.create(Constructor.prototype);
  var temp = Constructor.apply(instance, args);

  return (typeof temp === 'object' && temp !== null) ? temp : instance;
}

from blog.

enggirl avatar enggirl commented on May 2, 2024 7

博主你好,Object.create() vs new Object()区别,我的理解是new Object()得到的实例对象,有__proto__属性也有constructor属性,但是Object.create()创建的对象没有这两个属性,而且用instanceof 判断是否是Object,用Object.create() 创建的对象也是false。在MDN上面的例子,看了之后觉得,Object.create()是可以设置某个属性的底层是否可操作,但是这一点在new Object()没有。而且我在看到stackoverflow上说Object.create()其实并没有继承什么东西。new Object() 可以返回实际对象
https://stackoverflow.com/questions/4166616/understanding-the-difference-between-object-create-and-new-somefunction/4166723#4166723
不知道这么理解对不对,还望指点迷津

以下是代码:

image

from blog.

huangmxsysu avatar huangmxsysu commented on May 2, 2024 7

@enggirl 准确来讲是因为Object.create(null)返回一个没有任务继承关系的空值,你才觉得没有__proto__或者construtor或者instanceof返回false,当你使用Object.create(Object.prototype)的时候又是另一回事了那些属性

from blog.

xuchaobei avatar xuchaobei commented on May 2, 2024 7

第二版代码最后一行,
return typeof ret === 'object' ? ret : obj;
应该改为:
return ret instanceof Object ? ret : obj;
因为typeof 的值可能等于“function”,如果是函数,依然应该使用这个函数作为最终返回值。

from blog.

zhw2590582 avatar zhw2590582 commented on May 2, 2024 7

ES6 简化版

function objectFactory(Constructor, ...rest) {
  const instance = Object.create(Constructor.prototype);
  const result = Constructor.apply(instance, rest);
  return (typeof result === 'object' && result) || instance;
}

from blog.

xukuanzhuo avatar xukuanzhuo commented on May 2, 2024 6

” 两者的区别就在于 __proto__ 一个是实的,一个是虚的,由此我们可以猜测第一种方式是把 __proto__当成了一个属性值,而非去修改了原型! “

感觉根本原因有误。

原因是 Object.create(null) 创建的是一个没有原型链链接的空对象, new Object() 类似于 Object.create(Object.prototype) 创建的是有原型链链接的空对象,

var a = Object.create(null)
var b = new Object()
  • Object.getPrototypeOf(a) // null
    a
  • Object.getPrototypeOf(b)
    b

Object.getPrototypeOf(b) === Object.prototype // true

a 是没有原型链链接的空对象,自然访问不到__proto__ 属性,没有在原型链上,所以也可以用来做字典,不会有原型链上属性影响。

reference: You Don't Know JS Object.create

from blog.

jgchenu avatar jgchenu commented on May 2, 2024 5

从深入第一篇看到这里即将完结,必须给大大点个赞!狂赞一下!写得太好看了,我在坐地铁还有睡觉前,手机微信网页都是置顶大大的博客来看的❤️❤️❤️

from blog.

tinytot1 avatar tinytot1 commented on May 2, 2024 5

根据mdn new 运算符定义

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

const _new = (_Contructor, ...args) => {
  // 1.创建一个空的简单JavaScript对象(即{});
  const obj = {}
  // 2.链接该对象(即设置该对象的构造函数)到另一个对象 ;
  Object.setPrototypeOf(obj, _Contructor.prototype)
  // 3.将步骤1新创建的对象作为this的上下文 ;
  const ret = _Contructor.apply(obj, args)
  //4.如果该函数没有返回对象,则返回this。
  return ret instanceof Object ? ret : this
}

from blog.

lzuliuyun avatar lzuliuyun commented on May 2, 2024 4

@Latube

顺着你的需求和思路,你是需要修改constructor吧,最后我发现在执行new的时候,其内部是调用最原始的构造函数执行,即便后面修改了构造函数,也没有办法绑定到new出来的实例对象的。

参考:https://stackoverflow.com/questions/9267157/why-is-it-impossible-to-change-constructor-function-from-prototype。

自己试着实现了,仅供参考

var util = (function () {      
      function objectFactory() {
        var funCollection1 = arguments[0];
        var funCollection2 = arguments[1];

        return function () {        
          for (name1 in funCollection1) {
              this[name1] = funCollection1[name1];
          }
          for (name2 in funCollection2) {
              this.constructor.prototype[name2] = funCollection2[name2];
          }
        }          
      }

      return {
        objectFactory: objectFactory
      }
 })()

//定义构造函数
var Methods =  util.objectFactory({
  checkName: function() {
      console.log("checkName func");
  }
}, {
  checkEmail: function() {
      console.log("checkEmail func");
  }
});

//实例化
var m = new Methods()

// console.log(Methods.checkName())
console.log(m.checkEmail()); //checkEmail func
console.log(m.checkName()); //checkName func

from blog.

FishPlusOrange avatar FishPlusOrange commented on May 2, 2024 4

没有明白为什么 Constructor 会声明成全局变量

正文例子里面 Constructor 并不是声明成全局变量,只是省略了 var

它的上一句 var obj = new Object(), 是以 , 结尾,而不是 ;

from blog.

GisonL avatar GisonL commented on May 2, 2024 4
return typeof ret === 'object' ? ret : obj;

这里不严谨:

  1. 如果构造函数return的是函数的话,接收到的也会是那个函数。
    test2

  2. 如果return null,也应该返回obj

    所以我认为应该写成:

return (typeof ret === 'object' || typeof ret === 'function')? ret||obj : obj;

from blog.

Allen3039 avatar Allen3039 commented on May 2, 2024 3

return Object.prototype.toString.call(ret).match(/^\[object (\w+)\]$/)[1]==='Object' ? ret : obj; 也可以吧

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024 3

@yh284914425 是的,本篇是希望通过模拟 new 的实现,让大家了解 new 的原理~

from blog.

Lin-Saint avatar Lin-Saint commented on May 2, 2024 3

两年了,我还在等你的react哈哈哈哈哈

from blog.

vnues avatar vnues commented on May 2, 2024 3

哈哈哈哈哈 想到一个问题 我们是去实现new 还用 var obj = new Object()
这不是有毒吗

实际let obj={} <===>var obj = new Object() 这样理解起来不是更好吗哈哈哈哈哈哈

from blog.

FridayDai avatar FridayDai commented on May 2, 2024 3

写一个便于理解的版本

function myNew(fn, ...args) {
  const obj = Object.create(fn.prototype);
  const result = fn.call(obj, ...args);
  return typeof result === 'object' ? result || obj : obj;
}

from blog.

Williris avatar Williris commented on May 2, 2024 2

返回值应该判断三种类型: Function,Object 和Array

from blog.

lizhongzhen11 avatar lizhongzhen11 commented on May 2, 2024 2

赞同楼上。
试试这个:

var obj1 = new Object();
var obj2 = Object.create(Object.prototype);
obj1.constructor === Object; // true
obj1.__proto__ === Object.prototype; // true
obj2.constructor === Object; // true
obj2.__proto__ === Object.prototype; // true

@enggirl

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024 2

@jgchenu 真的感谢回答哦~ o( ̄▽ ̄)d,不过我发现 @xuchaobei 好像说的没有问题……

当构造函数内部返回一个函数的时候,应该使用这个函数作为返回值,写个 demo 验证一下:

function Otaku2 (name, age) {
    this.strength = 60;
    this.age = age;

    return function cb() {
    	return {
    		value: 1
    	}
    }
}

console.log(new Otaku2('kevin', '18'));  // function cb()

确实是返回了这个函数,所以当返回函数和对象的时候,都应该将其作为最终返回值,使用 typeof 确实没有做到函数的判断……

@xuchaobei 感谢指正~ ( ̄▽ ̄)~*

from blog.

roninliu avatar roninliu commented on May 2, 2024 2

var obj = Object.create(null);
obj.proto = Constructor.prototype;

看了上面议论通过 Object.create(null) 创建一个空对象,但我发现实际上这种方式实例没法访问到
Constructor.prototype 上面的属性。

Object.create(null)继承的null的原型,所以没有prototype

from blog.

quanru avatar quanru commented on May 2, 2024 2

@jawil

var obj = new Object(),//从Object.prototype上克隆一个对象

这行是不是多余了

from blog.

qianL93 avatar qianL93 commented on May 2, 2024 1

这里构造函数返回null的时候,new返回的是obj,不是ret

from blog.

Latube avatar Latube commented on May 2, 2024 1

@lizhongzhen11
赞同,因为 Object.create(null) 返回的是一个没有任何属性的空对象, new Object() 返回的是有 __proto__ 属性的对象,其__proto__ 指向Object.prototype 对象

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024 1

@huangmxsysu @lizhongzhen11 @Latube 非常感谢各位指正!

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024 1

@Latube 上述的代码有的小问题,完整的是不是

   Function.prototype.addMethod = function() {
        var funCollection1 = arguments[0];
        var funCollection2 = arguments[1];

        for (name1 in funCollection1) {
            this[name1] = funCollection1[name1];
        }
        for (name2 in funCollection2) {
            this.prototype[name2] = funCollection2[name2];
        }
    }

    //定义构造函数
    var Methods = function() {};
    //对构造函数以及构造函数的原型对象添加方法
    Methods.addMethod({
        checkName: function() {
            console.log("checkName func");
        }
    }, {
        checkEmail: function() {
            console.log("checkEmail func");
        }
    });

    //实例化
    var m = new Methods()

    console.log(Methods.checkName())

    console.log(m.checkEmail()); //checkEmail func
    console.log(m.checkName()); //error

如果 console.log(Methods.checkName()) 可以打印到 checkName func,这是因为 checkName 方法被挂载到了 Methods 构造函数上,而非 Methods.prototype 上,而实例对象只能访问 Methods.prototype 上的方法,如果 console.log(m.constructor.checkName()) 也是可以打印到的,而为什么只能访问原型对象中的方法,这是因为 JavaScript 原型就是这样设计的……就是只能沿着原型链去查找属性……

from blog.

hankanon avatar hankanon commented on May 2, 2024 1

虽然是写new关键字的实现原理 但是懂得了Object.create() 和 new Object() 的区别,很开心

from blog.

inkn avatar inkn commented on May 2, 2024 1

没有明白为什么 Constructor 会声明成全局变量

from blog.

MrRENGE avatar MrRENGE commented on May 2, 2024 1

博主使用 var obj = new Object() ,是为了返回的对象的__proto__ 属性能指向Object目的也许是为了保持一致的表现。评论区有老哥说的使用var obj = Object.create(null),表现是不一样的,obj上不存在任何属性此obj.__proto__ 则为undefined。其实说 var obj = {};var obj = new Object(); var obj = Object.create(); 效果都是一样的,既然为了模拟new,封装的时候不使用new跟合理些。强迫症患者0_0

from blog.

ATQQ avatar ATQQ commented on May 2, 2024 1

依葫芦画瓢,我也丢一个小改版

function myNew() {
    // 创建一个空对象
    let obj = {}
    // 获取构造函数
    let Con = [].shift.call(arguments)
    // 设置空对象的原型
    obj.__proto__ = Con.prototype
    // 绑定this
    let res = Con.apply(obj, arguments)
    // 返回新对象
    return res instanceof Object ? res : obj
}

from blog.

Vstar18 avatar Vstar18 commented on May 2, 2024 1

@mqyqingfeng
关于Object.create(null)的猜想我同意,使用Object.keys验证一下。person1是Object.create({})生成的,person2是Object.create(null)生成的。结果如下:
image

猜想:
Object.create(null)是创建一个原型链指向null的对象,当原型链为null时,不可再次更改原型链。因此再次obj.proto 赋值时,实际是添加了一个属性,而不是链接原型了。

原因可能是原型链的顶端就是null(Object.prototype.proto === null//true),所以原型链是null的不可更改


@strongcode9527 @a1029563229 @lzayoih 我也发现了这个问题,测试 demo 为:

function Otaku (age) {}

Otaku.prototype.sayHello = function() {
	console.log('hello')
}

var person = objectFactory(Otaku, 'Kevin', '18');
console.log(person)
person.sayHello() //???

如果使用 Object.create(null),person.sayHello 就会报错,使用 new Object(),会正常打印 hello。

查看由两种方式生成的 person 对象,第一个是由 Object.create 生成的,第二个是 new Object 生成的

default

两者的区别就在于 proto 一个是实的,一个是虚的,由此我们可以猜测第一种方式是把 proto 当成了一个属性值,而非去修改了原型!

原因其实在 《JavaScript深入之从原型到原型链》中有提过:

proto ,绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Person.prototype 中,实际上,它是来自于 Object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.proto 时,可以理解成返回了 Object.getPrototypeOf(obj)。

default

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

哈哈,添加的注释很赞 o( ̄▽ ̄)d

from blog.

jawil avatar jawil commented on May 2, 2024

想看看博主写的react系列,准备学习react了,最近react和vue一直在撕逼😄

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@wcflmy 哈哈,被你发现了,我在模拟的时候,也发现这一点了,后来觉得反正主要目的是为了让大家了解 new 的原理,没有必要再写一句专门判断 null ,就没有写,不过使用你这种写法就不用多写那一句了,真的很赞!给你 32 个赞,哈哈~~~ o( ̄▽ ̄)d

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@Allen3039 哈哈,类型判断加正则,大家这是各显神通呐~ o( ̄▽ ̄)d

from blog.

xdwxls avatar xdwxls commented on May 2, 2024

@jawil var F=function(){};
F.prototype= Constructor.prototype;
obj=new F();//指向正确的原型 这写法是什么意思 没太看明白

from blog.

a1029563229 avatar a1029563229 commented on May 2, 2024

@strongcode9527 试了你这种写法 后面直接用prototype添加的方法,无法被继承....

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@a1029563229 能提供下这段代码吗?

from blog.

Izayoih avatar Izayoih commented on May 2, 2024

@mqyqingfeng @a1029563229 我也发现了这个问题 试了一下改成Object.create(Object.prototype)结果可以了...不是很明白什么道理

from blog.

yh284914425 avatar yh284914425 commented on May 2, 2024

__proto__在ie里面不是没用么,代码在ie里面应该实现不了吧

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@qianL93 确实如此哈,@wcflmy@Allen3039 已经在这个 issue 下提出了解决方案~

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@huangmxsysu 可以呀,毕竟 Object.create 的实现方式与之类似,之所以用 __proto__ 的方式是考虑之前的文章并未讲过 Object.create 的方法,使用这个方法还需要多一层解释成本

from blog.

huangmxsysu avatar huangmxsysu commented on May 2, 2024

嗯嗯,昨天读了你这些文章,收获蛮大的!棒!后面有再写什么么?

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@huangmxsysu 写完专题系列,接下来会写 ES6 系列 和 React 系列,欢迎关注哈~

from blog.

JeffAAA avatar JeffAAA commented on May 2, 2024

在处理返回值的时候,我发现使用new出来的实例的__proto__和我们模拟出来的实例的__proto__是不一样的,导致获取不到原型链上对应的值。有点没懂,可否解答一下@mqyqingfeng,代码如下

var objectFactory = function () {
  var obj = new Object();
  var constructor = Array.prototype.shift.call(arguments);
  obj.__proto__ = constructor.prototype;
  var returnValue = constructor.apply(obj, arguments);
  return typeof retrunValue == 'object' ? retrunValue : obj
}

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

Person.prototype.height = '160';
Person.prototype.sayHi = function () {
  return this.name + ' say hi!';
}
var newPerson = new Person('jeff', '11');
var factoryPerson = objectFactory(Person, 'jeff', '12');
console.log(newPerson.name, factoryPerson.name) // jeff jeff
console.log(newPerson.age, factoryPerson.age) // 11 12
console.log(newPerson.height, factoryPerson.height) // undefined "160"
console.log(newPerson.sayHi, factoryPerson.sayHi) //  undefined ƒ () {return this.name + ' say hi!';}

那这样,是不是我们没有成功模拟到new一个实例的功能呢

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@JeffAAA 你这里写错了哈:

var returnValue = constructor.apply(obj, arguments);
return typeof retrunValue == 'object' ? retrunValue : obj

都改成returnValue 结果就统一了~

from blog.

JeffAAA avatar JeffAAA commented on May 2, 2024

😅 好吧 手残了 ~~

from blog.

 avatar commented on May 2, 2024
function objectFactory() {

    var obj = new Object(),//从Object.prototype上克隆一个对象

    Constructor = [].shift.call(arguments);//取得外部传入的构造器

    var F=function(){};
    F.prototype= Constructor.prototype;
    obj=new F();//指向正确的原型

    var ret = Constructor.apply(obj, arguments);//借用外部传入的构造器给obj设置属性

    return typeof ret === 'object' ? ret : obj;//确保构造器总是返回一个对象

};

@jawil 你第一行代码new出Object实例,然后把该实例赋值给obj变量,但是在第五行又重新给obj变量赋值。所以我感觉第一行赋值为Object实例没啥意义。另外,第一行代码你也可以这样写,var obj = new Object;

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@RayJune 感谢补充哈~

from blog.

easterCat avatar easterCat commented on May 2, 2024
obj.__proto__ = Constructor.prototype;

这个是不是把function Object(){}的prototype给覆盖了?

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@a792751238 是的,不过 Constructor.prototype 的 __proto__ 又是这个 Object.prototype……

default

from blog.

zhouyingkai1 avatar zhouyingkai1 commented on May 2, 2024

又复习一遍 受益良多 🙏,谢谢

看到博主提到react, 想问下博主有计划写react系列吗,或者什么时候会写

from blog.

ClarenceC avatar ClarenceC commented on May 2, 2024
function objectFactory() {
  // 使用objectFactory的时候,把arguments,转化为数组
  var args = Array.prototype.slice.call(arguments);
  //提取第1个构建对象
  var Constructor = args.shift();
  // 创建constructor实例 instance 
  var instance = Object.create(Constructor.prototype);
  // 使用apply函数运行args, 把 instance 绑定到 this
  var temp = Constructor.apply(instance, args); 
  //返回对象判断 是object 还是 null 还是实例
  return (typeof temp === 'object' && temp !== null) ? temp : instance; 
}

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@ClarenceC 感谢分享哈~

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@enggirl 我错了,楼下的是正解!

from blog.

Latube avatar Latube commented on May 2, 2024

博主,您好,麻烦您看一下如下代码,我又犯糊涂了。

//为所有函数新增addMethod方法,该方法的目的是为了给构造函数和构造函数的原型对象批量增加方法
Function.prototype.addMethod=function({},{}){
    var funCollection1 = arguments[0];
    var funCollection2 = arguments[1];

    for(name1 in funCollection1){
         this[name1] = funCollection1[name1];
    }
    for(name2 in funCollection2){
         this.prototype[name2] = funCollection2[name2];
    }
}

//定义构造函数
var Methods = function(){};
//对构造函数以及构造函数的原型对象添加方法
Methods.addMethod({
    checkName: function(){
        console.log("checkName func");
    },{
    checkEmail: function(){
        console.log("checkEmail func");
});

//实例化
var m = new Methods()
console.log(m.checkEmail());   //checkEmail func
console.log(m.checkName());  //error

最后一句输出的错误是 m.checkName is not a function ,在对Methods进行功能增强后,为什么实例化后的对象无法复制构造函数里的方法而只能够访问原型对象里的方法呢?(因为是在手机上浏览,代码全是手码上去的)

from blog.

Latube avatar Latube commented on May 2, 2024

@mqyqingfeng 博主,您好,完整的代码确实是您写的这个意思,一下子豁然开朗,感谢😭😭😭

from blog.

jgchenu avatar jgchenu commented on May 2, 2024

@xuchaobei

function objectFactory() {

    var obj = new Object(),

    Constructor = [].shift.call(arguments);

    obj.__proto__ = Constructor.prototype;

    var ret = Constructor.apply(obj, arguments);

    return typeof ret === 'object' ? ret : obj;

};

作者写的没有错,如果构造函数里面有返回对象,那么调用构造函数之后返回的对象赋值给 ret,如果没有返回对象,那么默认使用构造的obj,obj的属性通过执行Constructor得来,至于instanceof Object 是为了判断函数返回的值是不是对象,如果返回的值是undefined或者其他基本类型的值,就使用obj作为构造出来的 对象,不知道这么说你是否懂了

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@lzuliuyun 赞 o( ̄▽ ̄)d

from blog.

hsroad avatar hsroad commented on May 2, 2024

你好,new 模拟实现的话 是不是还应该有一个是判断返回的是不是对象

from blog.

GayeChen avatar GayeChen commented on May 2, 2024

var obj = new Object(),
这里岂不是用了new,改成字面量创建,也行吧
var obj = {}

from blog.

Rabbitzzc avatar Rabbitzzc commented on May 2, 2024

@mqyqingfeng 对于let obj = new Object()已经使用了new去创造一个实例,那可否直接使用let obj = {}呢

from blog.

Rabbitzzc avatar Rabbitzzc commented on May 2, 2024

是的,通过

let a = new Object()
let b = Object.create(null)
let c = {}
打印的a,b,c可以看到,b不存在__proto__这个属性,而其他两个则存在。

from blog.

haoxl3 avatar haoxl3 commented on May 2, 2024

所以最后一句应该改为:return ret instanceof Object ? ret : obj; 是吗?小白我都看晕了

from blog.

TStoneLee avatar TStoneLee commented on May 2, 2024

@haoxl3 应该使用instanceof判断
不使用的话,如果是返回值是function类型的话,自定义的new会返回一个被赋值的构造函数(?是这样叫吗) Otaku { name: 'snow', age: 23, habit: 'Games' }
function objectFactory() {
var obj = new Object();
var Constractor = [].shift.call(arguments);
obj.proto = Constractor.prototype; // obj = Object.create(Constractor.prototype)
var ret = Constractor.apply(obj, arguments);
return typeof ret === 'object' ? ret || obj : obj;
// return ret instanceof Object ? ret || obj : obj;
}
function Otaku(name, age) {
this.name = name;
this.age = age;
this.habit = 'Games'
return function() {
value = 1;
}
}
Otaku.prototype.strength = 60;
Otaku.prototype.sayYourname = function() {
console.log('I am ' + this.name);
}
var person = objectFactory(Otaku, 'snow', 23)
person.sayYourname()
console.log(person)

如果使用instanceof判断的话,会出现和原生的new 一样的结果。 即, 会报错,TypeError: person.sayYourname is not a function。(仅在上面的实例中)

from blog.

SageWu avatar SageWu commented on May 2, 2024
function objectFactory() {
    var constructor = [].shift.call(arguments);
    var obj = Object.create(constructor.prototype);
    var result = constructor.apply(obj, arguments);
    return result instanceof Object? result: obj;
};

from blog.

MiaLeung01 avatar MiaLeung01 commented on May 2, 2024

赞,以前只知道 call apply bind new 这些方法,看完深入了解了他们是怎么实现的了!

from blog.

imtag avatar imtag commented on May 2, 2024

var obj = Object.create(null);
obj.proto = Constructor.prototype;

看了上面议论通过 Object.create(null) 创建一个空对象,但我发现实际上这种方式实例没法访问到
Constructor.prototype 上面的属性。

from blog.

imtag avatar imtag commented on May 2, 2024

是没有prototype,难道通过给obj添加--proto--属性也没用吗。

from blog.

ilvliu avatar ilvliu commented on May 2, 2024

很赞了

from blog.

SanQiG avatar SanQiG commented on May 2, 2024

大大你好,我想share一下我在看您文章之前所知道的new的底层实现

function New(fn) {
	var res = {};
	res.prototype = fn.prototype;

	var ret = fn.apply(res, Array.prototype.slice.call(arguments, 1));

	if ((typeof ret == 'function' || typeof ret == 'object') && ret !== null) {
		return ret;
	}

	return res;
}

from blog.

ositowang avatar ositowang commented on May 2, 2024

有点不明白为什么这里后来直接在构造函数原型链上加的函数,就取不到了,显示fuction is not defined

const objectContructorUltimate = (...args) => {
  let constructor = [].shift.call(args);
  let obj = Object.create(constructor.prototype);
  let result = constructor.apply(obj, args);
  // ensure we return an object or null
  return typeof result === 'object' ? result : obj;
};

//your lovely test cases
function cat(name, sex) {
  this.age = 16;
  this.weight = 20;
  return {
    name: name,
    sex: sex,
  };
}

cat.prototype.meow = function() {
  console.log('I am' + this.name);
};

const kathy = objectContructorUltimate(cat, 'kathy', 'female');
console.log(kathy.name);
console.log(kathy.sex);
kathy.meow() // meow is not defined

from blog.

zhw2590582 avatar zhw2590582 commented on May 2, 2024

@ositowang
因为你的cat构造函数返回了一个对象,实例化之后也只会返回这个对象。

from blog.

cliYao avatar cliYao commented on May 2, 2024

楼上正解,如果没有返回对象的话,就可以访问到原型对象上新增的方法

from blog.

yaozhongnan avatar yaozhongnan commented on May 2, 2024

我也好想写React呐,不过React估计是第三个或者第四个系列,现在第一个系列还没有发布完呢,第二个系列估计要写20篇左右,写到React,估计都下下个月了……看来是赶不上这波撕逼的浪潮了~😂😂😂

实际上,过了一年都没有开始写 React 系列 T^T

两年了...

from blog.

Arrogant128 avatar Arrogant128 commented on May 2, 2024

image
这种方式可以不

from blog.

btea avatar btea commented on May 2, 2024

@Arrogant128 你的fn执行结果如果返回的是一个非null的对象,mvmv的值应该指向该返回对象。

from blog.

Arrogant128 avatar Arrogant128 commented on May 2, 2024

@btea 我myNew方法写错了,使用Object.create(null)创造出来的对象没有__proto__属性,应该直接空对象就好了

from blog.

wangyesheng avatar wangyesheng commented on May 2, 2024

两年了,我还在等你的react哈哈哈哈哈

from blog.

naecoo avatar naecoo commented on May 2, 2024

function objectFactory (o, ...args) {
const c = Object.create(o.prototype)
c.proto.constructor = o
o.apply(c, args)
return c
}

from blog.

raclen avatar raclen commented on May 2, 2024

请问这么写有什么问题吗,我看起来也能用

    function Student(name, age, sex) {
      People.call(this, name, age);
      this.sex = sex;
    }
    Student.prototype.speak = function() {
      return "i im speak";
    };
   function customizeNew(Sup) {
      let Sub = {}; //新建一个对象
      Sub.__proto__ = Sup.prototype; //对象的原型指向其构造函数
      Sub.constructor = Sup;
      return function() {
        Sup.apply(Sub, arguments);
        return Sub;
      };
    }
    let s2 = customizeNew(Student)("悟空", 24);
    let s3 = customizeNew(Student)("悟空1", 25);

from blog.

luckymore avatar luckymore commented on May 2, 2024

@jawil @mqyqingfeng @Imlisten

function objectFactory() {

    var obj = new Object(),//从Object.prototype上克隆一个对象

    Constructor = [].shift.call(arguments);//取得外部传入的构造器

    var F=function(){};
    F.prototype= Constructor.prototype;
    obj=new F();//指向正确的原型

    var ret = Constructor.apply(obj, arguments);//借用外部传入的构造器给obj设置属性

    return typeof ret === 'object' ? ret : obj;//确保构造器总是返回一个对象

};

学习学习,之前一直是理论了解new,也来实践模拟一把😄

这一句没啥用吧

var obj = new Object(),//从Object.prototype上克隆一个对象

from blog.

usherwong avatar usherwong commented on May 2, 2024

var obj = Object.create(null)
这样创建会比较好

 let obj = Object.create(Constructor.prototype)

这样和楼主的

obj.__proto__ = Constructor.prototype;

效果是一样的

from blog.

YuArtian avatar YuArtian commented on May 2, 2024

最后的判断可以改成 ret instanceof Object ? ret : obj

from blog.

xsfxtsxxr avatar xsfxtsxxr commented on May 2, 2024

我也好想写React呐,不过React估计是第三个或者第四个系列,现在第一个系列还没有发布完呢,第二个系列估计要写20篇左右,写到React,估计都下下个月了……看来是赶不上这波撕逼的浪潮了~😂😂😂

实际上,过了一年都没有开始写 React 系列 T^T

大佬,现在2019年了,React你还没开始写呢,没事,我还能再等两年

from blog.

MierCurry avatar MierCurry commented on May 2, 2024

有个问题,就是这个是模拟new的实现,然后new Object()这个不是已经用了new了吗

from blog.

sfsoul avatar sfsoul commented on May 2, 2024

有个问题,就是这个是模拟new的实现,然后new Object()这个不是已经用了new了吗

你看下其他人的回复,修改下定义就好了。let obj = {}

from blog.

 avatar commented on May 2, 2024

发一下我写的版本,

Function.prototype._newOne = function () {
	let cotr = this;
	let newObj = Object.create({});
	Object.setPrototypeOf(newObj, cotr.prototype);
	let args = [].slice.call(arguments);
	let res = cotr.apply(newObj, args);
	function isObjectOrFunction (res) {
		return (typeof res === 'object' || typeof res === 'function');
	}
	return isObjectOrFunction(res) ? res || newObj : newObj;
}

function P (name) {
    this.name = name;
}

P.prototype.age = 22;

var p = P._newOne('linyx');

p.name // 'linyx'
p.age // 22
p.__proto__ === P.prototype // true

大家看看这么写有什么问题吗

from blog.

lisiur avatar lisiur commented on May 2, 2024

根据mdn new 运算符定义

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

const _new = (_Contructor, ...args) => {
  // 1.创建一个空的简单JavaScript对象(即{});
  const obj = {}
  // 2.链接该对象(即设置该对象的构造函数)到另一个对象 ;
  Object.setPrototypeOf(obj, _Contructor.prototype)
  // 3.将步骤1新创建的对象作为this的上下文 ;
  const ret = _Contructor.apply(obj, args)
  //4.如果该函数没有返回对象,则返回this。
  return ret instanceof Object ? ret : this
}

@tinytot1 最后应该返回 obj 吧

from blog.

hardmanhong avatar hardmanhong commented on May 2, 2024

var obj = Object.create(null)
这样创建会比较好

感觉这样好一点

var obj = Object.create(Constructor.prototype)

from blog.

liubon avatar liubon commented on May 2, 2024

Constructor 这不是声明了一个全局变量么?在外部可以访问到啊,是不是要加个声明

from blog.

angelayun avatar angelayun commented on May 2, 2024

根据mdn new 运算符定义

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

const _new = (_Contructor, ...args) => {
  // 1.创建一个空的简单JavaScript对象(即{});
  const obj = {}
  // 2.链接该对象(即设置该对象的构造函数)到另一个对象 ;
  Object.setPrototypeOf(obj, _Contructor.prototype)
  // 3.将步骤1新创建的对象作为this的上下文 ;
  const ret = _Contructor.apply(obj, args)
  //4.如果该函数没有返回对象,则返回this。
  return ret instanceof Object ? ret : this
}

ret instanceof Object 这里不行,如果

const _new = (_Contructor, ...args) => {
  // 1.创建一个空的简单JavaScript对象(即{});
  const obj = {}
  // 2.链接该对象(即设置该对象的构造函数)到另一个对象 ;
  Object.setPrototypeOf(obj, _Contructor.prototype)
  // 3.将步骤1新创建的对象作为this的上下文 ;
  const ret = _Contructor.apply(obj, args)
  //4.如果该函数没有返回对象,则返回this。
  return ret instanceof Object ? ret : this
}

代码对于 __proto__的设置是不正确的,你用下面的测试代码试下就知道了
// 下面是测试代码
function Person (name, age) {
this.name = name;
this.age = age;

return {
    name: name,
    habit: 'read book'
}

}

Person.prototype.strength = 60;

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

var person = _new(Person, 'angela', '20')

console.log(person.name)
console.log(person.habit)
console.log(person.strength)

person.sayName();

from blog.

wungjyan avatar wungjyan commented on May 2, 2024

@mqyqingfeng 返回值那里有问题,我改了下:

function myNew (){
    const obj = {}
    Constructor = [].shift.call(arguments);
    obj.__proto__ = Constructor.prototype
    const ret = Constructor.apply(obj, arguments)
    // 实测,当构造函数返回对象或者函数时,直接返回;如果为null或者基本类型,则返回实例对象
    if(
        (typeof ret === 'object' || typeof ret === 'function')
        && ret !== null
    ){
        return ret
    }
    return obj
}

from blog.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.