箭头函数有原型链吗?
我的结论是箭头函数的原型链是不完整的,但并不是没有!
问题的思考来源于instanceof
在我写代码的一个场景里需要判断某个变量类型是不是函数,于是我想到了使用instanceof,mdn中对instanceof定义是去比对实例对象的原型链的构造函数是否相同。
function fn(){}
fn instanceof Fucntion // true
此时我就有了一个想法如果fn是箭头函数呢?在我的脑海里总是记得箭头函数是没有原型链的,所以我就以为下面这段代码的结果会是false
let fn = () => {}
fn instanceof Fucntion // 结果还是true
结果还是true
于是我震惊了,我就去百度?说不定会有别的角度的理解! 百度的结果是:
我觉得不严谨,我就去了伟大的mdn,看看mdn对箭头函数的定义!
也就是说箭头函数中只是没有prototype属性,没有构造函数的这一特有定义的属性。但是
let fn = () => {}
fn.__proto__ = Function.prototype // true
fn.__proto__.__proto__ === Object.prototype
也就是说,箭头函数不能类比普通的函数,含有prototype属性等!(不绑定arguments.不能使用使用 yield 关键字等).类似于Funtion构造函数的实例对象。
结论一:箭头函数有原型链,但是没有prototype属性,箭头函数作为构造函数去创建实例对象!
let fn = () => {}
let obj = new fn() // VM1103:2 Uncaught TypeError: fn is not a constructor
于是乎我有了新的想法,让箭头函数可以成为构造函数!
:对比区别,是什么让箭头函数无法成为构造函数!
因为箭头函数不是constructor。这个地方我目前想不出办法来解决,没有找到new关键字在运行过程的详细代码,不知道如何一个变量是如何判断是否是一个constructor?希望有大佬能教我一下。
function fn() {}
let obj = new fn() // fn是如何判断是constructor?
总结下来两个点可以解决问题
- 让构造函数拥有prototype来维系原型链
- 手写一个新的new函数,跳过判断原型的过程
那么prototype有什么呢?
- contructor: 指向实例对象的构造函数
- '__ proto __': 当前执行构造函数上一级的构造函数的prototype
- 其他自定义的属性
个人理解:原型链的起点是实例对象的__proto__,往上走每一级的的对象即是实例对象也是构造函数。沿着 __ proto __.__proto__一直向上查找到对应的方法或属性。直到null!
let theArrowFn.prototype = () => {}
theArrowFn.prototype = {
constructor: arrow1, // 指向实例对象的构造函数
__proto__: Function.prototype // 当前执行构造函数上一级的构造函数的prototype
mm: 11,
sayHello: ()=> {
console.log(1111,this.a,this.b);
}
}
new的过程呢?
- 创建一个新对象
- 指定新对象的__proto__ 为构造函数的原型prototype
- 绑定构造函数this指向为新对象,运行函数
- 构造函数返回值为对象 ? 输出返回的对象 :新对象
function handleNew(fun,...args) {
// 边界错误返回 null
if(!(fun instanceof Function)) {
return null
}
let a = {} // 创建一个新对象
a.__proto__ = fun.prototype // 指定新对象的__proto__
let c = fun.apply(a,args) // 运行构造函数
return c instanceof Object ? c : a // 输出结果
}
验证结果
let theArrowFn = (a,b) => {
this.a = a
this.b = b
}
theArrowFn.prototype = {
constructor: theArrowFn, // 指向实例对象的构造函数
__proto__: Function.prototype, // 当前执行构造函数上一级的构造函数的prototype
mm: 11,
sayHello: ()=> {
console.log(1111,this.a,this.b);
}
}
// 手写new函数
function handleNew(fun,...args) {
// 边界错误返回 null
if(!(fun instanceof Function)) {
return null
}
let a = {} // 创建一个新对象
a.__proto__ = fun.prototype // 指定新对象的__proto__
let c = fun.apply(a,args) // 运行构造函数
return c instanceof Object ? c : a // 输出结果
}
let resuleObj = handleNew(theArrowFn,1,2)
consoloe.log(resuleObj.a) // undefined
consoloe.log(resuleObj.b) // undefined
consoloe.log(resuleObj.mm) // 11
consoloe.log(resuleObj.sayHello()) // 1111 1 2
当我信心满满的验证结果的时候发现验证结果不对!this的绑定不对,apply没有生效!此时明白我犯了一个致命的错误!
—-> 箭头函数的this指向无法改变
js是基于词法作用域的,也就是静态作用域,词法作用域是指函数this指向由函数定义的时候的位置决定的。箭头函数不会创建自己的this,只会取/继承指向定义时的函数作用域/全局作用域!
并且在mdn中说明了由于 箭头函数没有自己的 this 指针,通过 call() 或 apply() 方法调用一个函数时,只能传递参数(不能绑定 this---译者注),他们的第一个参数会被忽略!**
所以由于无法改变箭头函数this指向,那么正在new的过程的中,运行构造函数时无法为新对象赋予新的属性或方法
总结
- 对待别人输出的观点要自己实践思辨后再吸收!
- 虽然是一次错误的尝试,但是梳理之后还是有所收获!