惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Privacy International News Feed
云风的 BLOG
云风的 BLOG
Google DeepMind News
Google DeepMind News
Recorded Future
Recorded Future
I
InfoQ
aimingoo的专栏
aimingoo的专栏
Microsoft Security Blog
Microsoft Security Blog
MongoDB | Blog
MongoDB | Blog
Vercel News
Vercel News
D
DataBreaches.Net
Microsoft Azure Blog
Microsoft Azure Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
A
About on SuperTechFans
博客园 - 聂微东
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 司徒正美
博客园 - 三生石上(FineUI控件)
M
MIT News - Artificial intelligence
H
Help Net Security
B
Blog
J
Java Code Geeks
Y
Y Combinator Blog
Martin Fowler
Martin Fowler
IT之家
IT之家
WordPress大学
WordPress大学
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 叶小钗
博客园_首页
The Cloudflare Blog
爱范儿
爱范儿
Hugging Face - Blog
Hugging Face - Blog
博客园 - Franky
小众软件
小众软件
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Check Point Blog
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
Recent Announcements
Recent Announcements
Last Week in AI
Last Week in AI
U
Unit 42
雷峰网
雷峰网
P
Proofpoint News Feed
有赞技术团队
有赞技术团队
V
Visual Studio Blog
人人都是产品经理
人人都是产品经理
The Register - Security
The Register - Security
罗磊的独立博客

博客园 - 前端架构师

Claude Code 源码架构分析 我不是狐狸,我是那Harness Engineering 小龙虾的自我养成之路 vue3+ts添加公共富文本组件 vue watch详解 微信授权没搞过? css3图片防止变形 公众号使用微信sdk的正确姿势 web离线应用前提之离线检测 es6手写一个call this综合篇 this绑定番外篇之箭头函数绑定 vue中引入公用过滤器? this详解下 012天this详解上 011天之跨域资源共享CORS 010天JSON.stringify()详解 009天之跨浏览器的事件处理程序 使用XHR上传文件要不要了解一下?
同学给我来个手写的new吧
前端架构师 · 2020-03-22 · via 博客园 - 前端架构师

1.手写一个new

首先看看new怎么用

function Person(name){
    this.name = name
}
Person.prototype.eat = function() {
    console.log("Eating")
}
var qd = new Person('qd')
console.log(qd)
qd.eat();
  使用new创建的实例:
    能够访问构造函数里的属性(name);
    能够访问原型中的属性(eat)
在调用new时候发生了四件事:
    1新生成一个对象
    2将构造函数的作用域赋值给新对象(即绑定新对象的 this)
    3执行构造函数中的代码(即为这个新对象添加属性)
    4返回新对象

A版本

function create() {
    //1.获取构造函数,并删除arguments中的第一项
    var Con = [].shift.call(arguments);
    
    //2.创建一个空对象并连接到构造函数的原型,使它能够访问原型中的属性
    var obj = Object.create(Con.prototype);
    
    3.使用apply改变构造函数中this的指向实现继承,使obj能够访问到构造函数中的属性
    var ret = Con.apply(obj,arguments);
    
    4.优先返回构造函数返回的对象
    return ret instanceof Object ? ret : obj;
}

解释一下4中的判断:主要考虑的是没有返回值,

//1.有返回值且为对象:
function Person (name, sex) {
    this.name = name
    return {
        sex:sex
    }
}
1.构造函数中有返回值且为对象,那么创建的实例就只能访问到返回对象中的属性,
所以要判断一下ret的类型,如果是对象的话,则返回这个对象。

//2构造函数没有返回值:
function Person(name){
    this.name = name;
}
2.构造函数没有返回值,那么创建的实例就能访问这个构造函数中的所有属性了,此时ret就会为undefined,所以返回obj。

3,返回值为基本类型
function Person(name){
    this.name = name
    return 'str'
}
3.构造函数中没有返回值但是返回值是undefined以外的其他基本类型(比如字符串),这种情况当成第二种情况(没有返回值)来处理。

好了我们来验证一下吧:

function Person (name) {
    this.name = name
}
Person.prototype.eat = function() {
    console.log("Eating")
}

function create() {
    var Con = [].shift.call(arguments);
    var obj = Object.create(Con.prototype);
    var ret = Con.apply(obj, arguments);
    return ret instanceof Object ? ret : obj;
}

//调用
var qdleader = create(Person, 'qdleader');
console.log(qdleader); //Person{name:'LinDaiDai'}
qdleader.eat()  //'Eatting'





注意:object.create方法,参数为new出来的实例的原型,也就是_proto_的指向

还有其他版本的: b版本

function create() {
    // 创建一个空的对象
    let obj = {}
    // 获得构造函数
    // 因为 arguments 类数组,所以我们可以用数组的 shift 来实现 arguments 的 ‘push’ 和 ‘pop’
    // 将 arguments 进数组,并将第一个元素移除并赋值给 Con (Constructor).
    let Con = [].shift.call(arguments)
    // 链接到原型
    obj.__proto__ = Con.prototype
    // 绑定this,并执行构造函数,就相当于 obj .constructor(arguments)
    let result = Con.apply(obj, arguments)
    // 确保 new 出来的是个对象
    return typeof result === 'object' ? result : obj
}




1:arguments是一个类数组,以像是数组的样子取到传入的所有参数,有一个callee属性(值为被调用的方法)利用数组的shift方法拿到了第一项 也就是Animal函数,同时原来的arguments被更改,失去了第一个参数。再后面被apply拿来做参数

2:Constructor.apply(obj, arguments)
意思是在obj里执行构造函数,并且挨着arguments里剩下的参数

3:[ ]可以等价Array.prototype.shift ,也就是在arguments上执行数组的shift方法的意思

4:最后可以加一个判断,是否为对象再返回

比b版本更好一点的写法:

function _new() {
    let target = {}; //创建的新对象
    //第一个参数是构造函数
    let [constructor, ...args] = [...arguments];
    //执行[[原型]]连接;target 是 constructor 的实例
    target.__proto__ = constructor.prototype;
    //执行构造函数,将属性或方法添加到创建的空对象上
    let result = constructor.apply(target, args);
    if (result && (typeof (result) == "object" || typeof (result) == "function")) {
        //如果构造函数执行的结构返回的是一个对象,那么返回这个对象
        return result;
    }
    //如果构造函数返回的不是一个对象,返回创建的新对象
    return target;
}

个人感觉A版本好一些

欢迎加群!