-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
JavaScript深入之new的模拟实现 #13
Comments
var obj = Object.create(null) |
并没有什么区别吧,毕竟最后都是要更改原型的 以上是最初的看法,两者有很大的不同,欢迎下拉看两者之间的区别。 |
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,也来实践模拟一把😄 |
哈哈,添加的注释很赞 o( ̄▽ ̄)d |
想看看博主写的react系列,准备学习react了,最近react和vue一直在撕逼😄 |
我也好想写React呐,不过React估计是第三个或者第四个系列,现在第一个系列还没有发布完呢,第二个系列估计要写20篇左右,写到React,估计都下下个月了……看来是赶不上这波撕逼的浪潮了~😂😂😂 实际上,过了一年都没有开始写 React 系列 T^T |
objectFactory函数里最后一行建议改成“return typeof ret === 'object' ? ret||obj : obj;”,否则如果在Otaku函数里面return null,会有问题的。 |
@wcflmy 哈哈,被你发现了,我在模拟的时候,也发现这一点了,后来觉得反正主要目的是为了让大家了解 new 的原理,没有必要再写一句专门判断 null ,就没有写,不过使用你这种写法就不用多写那一句了,真的很赞!给你 32 个赞,哈哈~~~ o( ̄▽ ̄)d |
|
@Allen3039 哈哈,类型判断加正则,大家这是各显神通呐~ o( ̄▽ ̄)d |
@jawil var F=function(){}; |
@strongcode9527 试了你这种写法 后面直接用prototype添加的方法,无法被继承.... |
@a1029563229 能提供下这段代码吗? |
@mqyqingfeng @a1029563229 我也发现了这个问题 试了一下改成Object.create(Object.prototype)结果可以了...不是很明白什么道理 |
@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 生成的 两者的区别就在于 __proto__ 一个是实的,一个是虚的,由此我们可以猜测第一种方式是把 __proto__ 当成了一个属性值,而非去修改了原型! 原因其实在 《JavaScript深入之从原型到原型链》中有提过:
|
__proto__在ie里面不是没用么,代码在ie里面应该实现不了吧 |
@yh284914425 是的,本篇是希望通过模拟 new 的实现,让大家了解 new 的原理~ |
返回值应该判断三种类型: Function,Object 和Array |
这里构造函数返回null的时候,new返回的是obj,不是ret |
@qianL93 确实如此哈,@wcflmy 和 @Allen3039 已经在这个 issue 下提出了解决方案~ |
话说__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) 是一样也可以的吧? |
原型链的顶端是null, 但是null能干什么呢? 原型链能正常工作是内置Object起到的作用,即使Object的prototype是null(仅仅是设计如此).使用Object.create(null)相当于自己创建了一个prototype为null的'CustomObject',它不具备内置Object的一些特性,所以Object.create(null)创建的对象不支持原型特性, 自然也无法根据原型链查找属性/方法 |
求问用模拟的实现去实例化一个Date对象不行是什么原因呢?let a=mocknew(Date); a.getDate()报错 |
实际上,过了四年都没有开始写 React 系列 T^T |
第一眼看的时候有点懵逼,主要是没习惯arguments直接的用法,换成ES6的写法会明了很多,感谢大佬提供思路,怎么不继续更新了呢 // Constructor = [].shift.call(arguments) let ret = Constructor.apply(obj, args) return typeof ret === 'object' ? ret : obj |
都说模拟new 咋还函数内用到了new呢 |
第二版 返回的是null 也不合适 可以改成 return Object(ret ) === ret ? ret : obj |
function _new(fn) {
const prototype = fn.prototype;
const o = Object.create(prototype);
const result = prototype.constructor.apply(o, [].slice.call(arguments, 1));
return typeof result === "object" ? result : o;
}
console.log(
_new(
function (age, color) {
this.age = age;
this.color = color;
},
23,
"red"
)
); |
为什么要模拟new 的实现,内部还要用到new 啦, Object.create(null) 感觉确实是正解 |
都 2022 年了,还没有写 |
这是来自QQ邮箱的假期自动回复邮件。
您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
|
|
var ret = Constructor.apply(obj, [...arguments].slice(1)) 应该把构造函数去掉在绑定给obj吧 |
小记 function Otaku (name, age) {
this.name = name;
this.age = age;
this.habit = 'Games';
}
Otaku.prototype.strength = 60;
Otaku.prototype.sayYourName = function () {
console.log('I am ' + this.name);
}
function objectFactory() {
var obj = new Object(),//存疑,为什么模拟new里面使用new?
//var obj = Object.create(null),//报错:TypeError
//var obj = {},//正常
//var obj = Object.create({}),//正常
//var obj = Object.create(Object.prototype),//正常
Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
var ret = Constructor.apply(obj, arguments);
return typeof ret === 'object' ? ret||obj : obj;
};
var person = objectFactory(Otaku, 'Kevin', '18')
console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60
person.sayYourName(); // I am Kevin |
// 实现 new
function newFactory(fn, ...args) {
const obj = Object.create(fn.prototype); // 原型式继承
const ret = fn.apply(obj, args); // 继承属性
return typeof ret === "object" ? ret : obj;
} |
真不错 |
这是来自QQ邮箱的假期自动回复邮件。
您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
|
|
箭头函数的情况没有处理 |
这是来自QQ邮箱的假期自动回复邮件。
您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
|
function myNew(fn, ...args) { |
这是来自QQ邮箱的假期自动回复邮件。
您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
|
function _new (fn, ...args) {
const obj = Object.create(fn.prototype);
const result = fn.apply(obj, args);
return (result && typeof result === 'object') ? result: obj;
} |
这是来自QQ邮箱的假期自动回复邮件。
您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
|
new
一句话介绍 new:
也许有点难懂,我们在模拟 new 之前,先看看 new 实现了哪些功能。
举个例子:
从这个例子中,我们可以看到,实例 person 可以:
接下来,我们可以尝试着模拟一下了。
因为 new 是关键字,所以无法像 bind 函数一样直接覆盖,所以我们写一个函数,命名为 objectFactory,来模拟 new 的效果。用的时候是这样的:
初步实现
分析:
因为 new 的结果是一个新对象,所以在模拟实现的时候,我们也要建立一个新对象,假设这个对象叫 obj,因为 obj 会具有 Otaku 构造函数里的属性,想想经典继承的例子,我们可以使用 Otaku.apply(obj, arguments)来给 obj 添加新的属性。
在 JavaScript 深入系列第一篇中,我们便讲了原型与原型链,我们知道实例的 __proto__ 属性会指向构造函数的 prototype,也正是因为建立起这样的关系,实例可以访问原型上的属性。
现在,我们可以尝试着写第一版了:
在这一版中,我们:
更多关于:
原型与原型链,可以看《JavaScript深入之从原型到原型链》
apply,可以看《JavaScript深入之call和apply的模拟实现》
经典继承,可以看《JavaScript深入之继承》
复制以下的代码,到浏览器中,我们可以做一下测试:
[]~( ̄▽ ̄)~**
返回值效果实现
接下来我们再来看一种情况,假如构造函数有返回值,举个例子:
在这个例子中,构造函数返回了一个对象,在实例 person 中只能访问返回的对象中的属性。
而且还要注意一点,在这里我们是返回了一个对象,假如我们只是返回一个基本类型的值呢?
再举个例子:
结果完全颠倒过来,这次尽管有返回值,但是相当于没有返回值进行处理。
所以我们还需要判断返回的值是不是一个对象,如果是一个对象,我们就返回这个对象,如果没有,我们该返回什么就返回什么。
再来看第二版的代码,也是最后一版的代码:
下一篇文章
JavaScript深入之类数组对象与arguments
相关链接
《JavaScript深入之从原型到原型链》
《JavaScript深入之call和apply的模拟实现》
《JavaScript深入之继承》
深入系列
JavaScript深入系列目录地址:https://github.com/mqyqingfeng/Blog。
JavaScript深入系列预计写十五篇左右,旨在帮大家捋顺JavaScript底层知识,重点讲解如原型、作用域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难点概念。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎star,对作者也是一种鼓励。
The text was updated successfully, but these errors were encountered: