-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
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: