Javascript的一些坑点(二)

本文探讨了如何在JavaScript中正确处理this的问题,特别是箭头函数的this行为,并提供了修复错误的方法,包括使用call()和闭包。重点讲解了箭头函数与普通函数在this指向上的区别,以及何时选择哪种写法以保持代码清晰和可读性。
摘要由CSDN通过智能技术生成

1、this指向问题

当我们需要抽离一个类/对象的函数出来使用时,需要手动调整函数内部的this指向
如:

class Foo {
	constructor(num) {
		this.num = num;
	}
	getNum() {
		return this.num;
	}
}
let obj = new Foo();
print(obj.getNum);

function print(fn) {
	Promise.resolve()
	.then(function() {
		fn();
		resovle();
	})
	.then(function() {
		...
	})
}

如果按这么写的话,将会得到一个报错:UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'num' of undefined, 究其原因,是将 getNum 从对象/类原型函数中抽离出来,此时处在的作用域为 全局, this下无num这是其一,this为undefined是因为node默认采用的严格模式。

因此,改正过来的话 只需要 fn.call(obj) 即可

或者使用闭包进行改造

class Foo {
	... 
	getNum() {
		let context = this;
		return function() {
			return context.num;
		}
	}
}

2、过度使用箭头函数

使用箭头函数的好处就是节省篇幅,代码看起来很简短,在处理简单的逻辑时效率会很高,如 创建一个矩阵,给一个数组设置排序规则等等

// 创建m*n的矩阵
let arr = new Array(m).fill(0).map(v=>new Array(n).fill(0));

// 将nums按升序规则原地稳定排序
nums.sort((a,b) => a-b);

但是逻辑一旦复杂起来时,用箭头函数写出的代码可阅读性极差,让人难以费解,甚至还需要数括号来判断嵌套关系,如:

/*
const N = 5;
let obj = new Scheduler(N);
const timeout = ms => new Promise(res => setTimeout(res, ms));
const LOG = console.log;
*/
const addTask = obj.add((time, order) => timeout(time)).then(() => LOG(order));

以上为被注释的代码令人费解,大致逻辑是 then被add返回的Promise调用,但看的不仔细的话甚至会认为 then 是被 timeout(time) 返回的Promise调用的。

因此,避免这个坑的办法是 箭头函数超过1层嵌套时,就用函数声明把:

function addTask(time, order) {
	obj.add(function task(time, order) {
		timeout(time);
	}).then(function() {
		LOG(order);	
	});
}

但是箭头函数与声明式函数function应该是不能随意来回切换写法,因为箭头函数相较声明式函数function来说,有以下几点区别,为了简便描述,将箭头函数记作 arrow,将声明式函数记为 fn

(1)fn中this指向为调用它的环境,arrow的this指向固定为创建它的环境,call/apply/bind都无法改变

(2)arrow不可用作构造函数,因此无 new.target

(3)arrow无arguments属性,只可用 …params 得到参数列表 params

(4)无原型,无super

因此,应该在合适的环境中使用箭头函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值