欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Javascript的一些坑点(二)

程序员文章站 2022-07-15 15:48:43
...

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

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

相关标签: web