博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
new fn() 做了什么
阅读量:7040 次
发布时间:2019-06-28

本文共 2203 字,大约阅读时间需要 7 分钟。

1. 函数的多重用途

函数可以搭配new使用,函数内部的this会指向一个新对象,最终函数会返回这个新对象

function fn(){  this.count = 1}const obj = new fn()  // {count: 1}fn()   // undefined  全局对象上会添加一个属性count,值为 1复制代码

js函数有两个不同的内部方法:[[Call]][[construct]]

  • 使用new调用函数时,会执行[[construct]]方法:
    1. 在内存中创建一个继承自 fn.prototype 的新对象
    2. 把函数体的this指向新对象,并执行函数体。
    3. 默认返回新对象。如果构造函数指定的返回值为复杂类型,会覆盖掉默认返回值。
  • 直接调用函数,会执行[[Call]]方法,直接执行函数体。

使用代码模拟new的操作:

function New(fn, ...arg) {  // 创建新对象,原型为构造函数的原型  let res = Object.create(fn.prototype)  // 修改this指向为新对象,并执行函数体  let ret = fn.apply(res, arg)  // 如果返回值不是有效对象,则返回新对象  return (typeof ret === 'object' && typeof ret === 'function' && ret !== null) ? ret : res}function Fn(a) {  this.a = a}Fn.prototype = {  sayHello() {      console.log('hello')  }}console.log(new Fn(2))   console.log(new(Fn, 2))复制代码

在控制台查看输出时,唯一不同的是红框的地方:
new操作符创造的对象会有一个Fn。并不太清楚这是什么,后来猜测这是
实例对象的构造函数名,于是尝试给
Fn的原型加上了
constructor属性:

Fn.prototype = {  constructor: Fn,  sayHello() {    console.log(1)  }}复制代码

然后输出完全一致了。

那么问题来了:为什么 new操作符创建的实例在原型没有constructor属性时,也能够知道实例的构造函数,而且并没有设置constructor属性,在控制台第一次的输出中可以看到。望有缘人能帮忙解答!!!

2. es5中判断函数被调用的方式

根据上述原理,es5经常依据this是否为构造函数的实例,来判断函数被调用的方式

function Person(){  if(this instanceof Person){      alert('使用new,函数被当做构造函数调用')  }else{      alert('当做普通函数调用')  }}复制代码

以前经常 使用面向对象开发jquery插件,发现有些插件初始化时,可以使用new也可以不使用new ,比如let swiper = new Swiper(options)let swiper = Swiper(options)均可,观察后发现,插件结构是这样的:

// 忘记 Swiper是否可以不使用new初始化,这里就拿它举例说明了function Swiper(option){ if(this instanceof Swiper){     // 初始化操作 }else{     return new Swiper(option) }}复制代码

把函数的两种调用方式,都过滤为构造函数式调用,所以是否使用new都可以。

题外话: 当时自己也偷学了这种方式,来写插件,觉得很高级,但总是忘记具体写法。学习的高潮之处,就在于新知识与自己的旧知识体系碰撞并融合的过程,最后融为了一声 "奥~~,TM原来如此"

但这种方式也有缺陷因为可以用call或者apply修改函数内的this 指向到函数的实例上,比如let person = new Person(); Person.call(person),那么就不能区分是否通过new调用

3. es6判断函数调用方式

为了判断函数是否通过new调用,es6引入了new.target这个元属性。

元属性:是指非对象的属性,可以提供非对象目标的补充信息

  1. 使用new调用函数时,会执行[[construct]]方法,new.target被赋值为函数本身
  2. 直接调用函数,会执行[[Call]]方法,new.targetundefined
function Person(){    if(new.target === Person){        // 使用 new调用        console.log(new.target)    }else{        console.log(new.target)    }}new Person()   // PersonPerson()   // undefined复制代码

new.target在函数体外是一个语法错误

转载于:https://juejin.im/post/5c98f627e51d453b2e0846bd

你可能感兴趣的文章
数据中心可靠级别划分
查看>>
你真的理解什么是“财富自由”吗?
查看>>
释放LINUX内存(请使用火狐浏览器浏览本页面)
查看>>
Andrew Ng 深度学习笔记-01-week3-课程
查看>>
Android获取通过XML设置的空间的高宽
查看>>
生活的苦逼
查看>>
在iptables防火墙下开启vsftpd的端口
查看>>
Mysql、MariaDB 新型主从集群配置GTID
查看>>
Linux HA Cluster的实例演示(2)
查看>>
Delphi之word报表
查看>>
unity的默认文件目录及脚本之间的执行顺序
查看>>
angular 定时函数
查看>>
移动端app测试关注点
查看>>
Android 仿QQ消息界面
查看>>
a demo for how to use QThread
查看>>
扩展欧几里德算法
查看>>
【原创】多字节版本下MFC控件处理字符集的BUG
查看>>
ntp服务器
查看>>
子线程中刷新了UI
查看>>
UIPopoverController事件分发
查看>>