• js的new操作符深度解析


    引言

    • 我们都知道new操作符在js中一般是用来创建一个构造函数的实例,它在创建实例具体做了什么,MDN文档是这么说的: 我一开始看到,完全没有任何的头绪和理解,到底什么意思,后面通过上网查阅了大量的资料,对new操作符有了初步的认识。

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

    普通函数和构造函数的区别

    • 在js中 普通函数和构造函数并无本质的区别,都是函数,构造函数约定首字母大写(主要目的区分普通函数和构造函数)。并且通过new操作符调用并创建构造函数的实例。

    new操作符做了什么

    
     var _this = null
     function Fun(){
         this.name = '车神-黄杰'
         this.gender = '男'
         this.age = 23
    	
         _this = this		
         console.log('this--->', this)
     }
    
     var foo = new Fun()		
     console.log('foo--->', foo)
     console.log('foo === _this--->', foo === _this)
     console.log('name--->', foo.name)
    
    

    输出结果

    创建空对象(第一步)

    
     var fun = new Object()
    

    链接该对象(第二步)

    • 其实就是设置了第一步创建的空对象fun__proto__属性 和 构造函数Funprototype属性指向同一块内存地址。
    
     var fun = new Object()// 1
     fun .__proto__ = Fun.prototype// 2
    

    新创建的对象作为this的上下文(第三步)

    • 这里和第二步类似,即第一步创建的空对象funthis指向同一块内存地址(这是我个人理解)
    
     var fun = new Object()// 1
     fun .__proto__ = Fun.prototype// 2
     this = fun// 3
    

    返回值(第四步)

    • 我们知道函数的调用即为函数名,后面紧跟一个括号,创建构造函数的实例是 new Fun(),自然会调用构造函数,那构造函数里面的代码必然会执行。当构造函数没有返回具体对象(注意这里是对象),默认是返回this。执行var foo = new Fun()这一句代码即为foo接收了返回值this,结果就是foo也指向了this所指向的内存地址。说白了空对象funthis、实例foo指向了同一块内存地址。当你往this添加了name、gender、age属性,自然实例foo也能访问到。

    隐式参数

    • 为什么函数调用的时候没有传递this和arguments,却可以使用它们呢,原因就是在调用函数的时候会默认传递两个隐式参数this和arguments,其中的this即为第三步的thisarguments是一个伪数组对象,包含着传入函数中的所有参数。

    构造函数有具体的返回对象

    • 当构造函数有返回新的对象(注意这里是对象),执行var foo = new Fun()这一句代码,foo接收的值为构造函数返回的具体的对象。
    
     var _this = null
     function Fun(){
         this.name = '车神-黄杰'
         this.gender = '男'
         this.age = 23
    	
         _this = this		
         console.log('this--->', this)
        
        //返回新的对象
         return {name: '我是新的name'}
     }
    
     var foo = new Fun()		
     console.log('foo--->', foo)
     console.log('foo === _this--->', foo === _this)
     console.log('name--->', foo.name)
    
    

    输出结果

    模拟new操作符

    • 这里用到了函数对象的两个主要的方法apply、call,总的来说就是可以调用函数并且绑定具体this
     function cloneNew(){
    				
         //先获取传递进来的构造函数对象 
         //默认为第一个参数 由于arguments不是数组
         //不能直接使用数组的shift方法(自己了解 shift 的方法使用)
         //可以通过函数的shift方法返回第一个参数
        //并去除arguments的第一个参数
         var constructor = [].shift.call(arguments)				
    				
         //第一步:创建一个空对象
         var obj = new Object()
    				
         //第二步:链接该对象
         obj.__proto__ = constructor.prototype
    				
         //第三步:新创建的对象作为this的上下文 
         //这里借助函数对象的 apply 方法,对应还有一个 call 方法
         var newObj = constructor.apply(obj,arguments)
    				
         //第四步:判断构造函数有没有返回具体的对象
         return newObj instanceof Object ? newObj : obj				
     }
    			
     //返回this			
     function Fun(name){
         this.name = name
     }
    
     //返回具体对象			
     function Foo(name){
         this.name = name
         //返回具体得到对象
         return {name: '新的黄杰'}
     }
    			
     var fun = cloneNew(Fun, '黄杰')
     var foo = cloneNew(Foo, '黄杰')
    			
     console.log('this的name--->'+ fun.name)// 输出 黄杰
     console.log('构造函数返回具体对象的name--->'+ foo.name)//输出 新的黄杰
    
    

    输出结果

    注意

    • 这里完全讨论的是new操作符,没有具体讨论this的指向问题,本人也在不断努力学习中,如有错误,恳请多多指教。
  • 相关阅读:
    设计模式 ( 十七) 状态模式State(对象行为型)
    设计模式 ( 十六 ) 观察者模式Observer(对象行为型)
    设计模式 ( 十五 ) 中介者模式Mediator(对象行为型)
    设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)
    设计模式 ( 十三 ) 命令模式Command(对象行为型)
    设计模式(十一)代理模式Proxy(结构型)
    设计模式(十)享元模式Flyweight(结构型)
    开源项目
    C#中的Marshal
    给枚举加上Description,必要时,可以直接获取枚举类型代表的中文
  • 原文地址:https://www.cnblogs.com/HJ412/p/11235831.html
Copyright © 2020-2023  润新知