你需要了解的 4 个 JavaScript 知识点
.call()、.bind()、.apply()
多次承诺执行
代理人
作品
结论
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
作为一名 JavaScript 开发人员,我发现了很多有趣的东西,我想和大家分享 4 件我认为如果你想成为一名更优秀的 JavaScript 开发人员应该知道的事情。
.call()、.bind()、.apply()
如果你曾经使用过 React,我确信你见过 ` bind()method` 方法,也许你曾经用过它,但并不真正了解它的含义。或许你在某些 JavaScript 库中也见过类似的方法,但你不明白call(), bind(), apply()它们是如何工作的。
首先你需要理解的是它的this含义。this它指的是内存中当前上下文的对象引用,而它所指向的引用会根据上下文执行阶段的不同而改变。
这些方法允许我们更改引用的位置this。
.bind()
const user = {
name: "Peter",
lastName: "Parker",
fullName: function () {
return `${this.name} ${this.lastName}`;
},
};
const print = function (greet) {
console.log(`${greet} ${this.fullName()}`);
};
print("hi");
执行这段代码时会报错:this.fullname() is not a function因为print函数内部this引用了全局对象。如果想在打印函数内部访问用户上下文,可以使用bind类似这样的方法:
const myBindedPrint = print.bind(user);
myBindedPrint("hi");
那么,我们做了什么呢?我们复制了打印函数并将其保存到myBindedPrint变量中。这个bind()方法允许我们创建一个带有特殊功能的副本,我们可以将要this引用的上下文作为参数传递。
。称呼()
.call()执行一个函数,例如,如果我们使用 ` ()and`,它允许我们将指向该函数的引用作为第一个参数传递。this.
const user = {
name: "Peter",
lastName: "Parker",
fullName: function () {
return `${this.name} ${this.lastName}`;
},
};
print.call(user, "hello");
执行该操作时,我们得到的结果与使用时相同.bind(),区别在于使用时.call()我们不会创建副本,而是直接执行它。
申请()
call()嗯,两者之间只有一个区别,apply()那就是调用方式。.apply()方法接收的参数是一个数组,像这样。
print.apply(user, ['hello'])
在什么情况下可以使用它?
函数借用
当我们想在不同的对象之间共享函数时,比如将一个函数“借用”给另一个对象,就需要用到这种方法。让我们来看一个例子。
const user = {
name: "Peter",
lastName: "Parker",
getFullName: function () {
return `${this.name} ${this.lastName}`;
},
};
const dog = {
name: "Thoby",
lastName: "Parker",
};
const result = user.getFullName.apply(dog);
console.log(result);
bind ()并且call ()与每个上下文中“指代”的apply ()位置有关this,这就是为什么它很有用,因为有了这些工具,我们可以决定这意味着什么,这在解决与执行上下文相关的问题时非常强大。
多次承诺执行
我见过一些初级程序员常犯的一个错误。
假设我们有一个方法,它会调用我们的 API 将产品保存到数据库中,这是一个异步操作。现在,假设我们有一个产品数组,我们想要保存它们,然后等待保存操作完成才能继续执行其他操作。我们需要执行多个 Promise。我见过类似的情况。
const saveProduct = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve({ data: {}, success: true }), 3000);
});
const saveProducts = async (products) => {
try {
const response = await products.map(
async (product) => await saveProduct(product)
);
console.log("success");
return response;
} catch (err) {
console.log(err);
}
};
const products = [{ name: "Pollo" }, { name: "Cerveza" }, { name: "Agua" }];
saveProducts(products).then((response) => console.log("response", response));
看起来似乎合情合理,但这一行代码 =>console.log("success")会立即执行,请检查!
你需要做的,大概是这样的。
const saveProducts = async (products) => {
try {
const response = await Promise.all(
products.map((product) => saveProduct(product))
);
console.log("succes");
return response;
} catch (err) {
console.log(err);
}
};
如果你运行一下,就会发现它正如我们预期的那样工作。我们的 `=>`console.log("success")行只有在所有 Promise 都解析完毕后才会执行。此外,我们的saveProducts方法会返回所有 Promise 的响应。
代理人
ES2015 代理提供了一个 API,用于捕获或拦截对对象执行的任何操作,并修改该对象的行为。JavaScript 代理有很多用途,例如:
- 拦截
- 对象虚拟化。
- 资源管理。
- 在调试应用程序时进行性能分析并生成日志。
- 安全和访问控制。
要实现代理,你需要了解一些术语。
- 目标:您要代理的原始对象。
- 处理程序:一个定义哪些操作将被拦截以及如何重新定义被拦截操作的对象。
我们来看一个例子。
const person = {
name: "Peter",
};
const handler = {
get: function (target, key) {
return key in target
? target[key]
: `Property ${key} doesn't exist in this object`;
},
};
const proxy = new Proxy(person, handler);
console.log(proxy.name); // Peter
console.log(proxy.lastName); // Property lastName doesn't exist in this object
使用代理可以做很多事情。我将向您展示一个实用案例。
缓存
const getArticles = (person) => {
fetch("api-url").then((articles) => {
// do something with articles
});
};
这意味着每次需要查阅某个人的文章时,都需要发起新的请求。而另一种方法是,在首次请求时缓存文章,后续请求可以直接从缓存中获取。
const cache = {
Peter: ["Article 1", "Article 2"],
};
const handler = {
get: function (target, person) {
if (target[person]) {
return target[person];
} else {
// fetch here
fetch("api-url").then((articles) => {
target[person] = articles;
return articles;
});
}
},
};
const proxy = new Proxy(cache, handler);
这样,只有当该人员不在缓存对象中时,才会执行 fetch 操作。
使用代理可以做很多事情,例如验证、提供对象的只读视图、私有属性等等。
作品
组合是一个简单却强大的概念。它是一种使用多个函数的简单方法。每个函数接收一个输入,并将其输出传递给下一个函数。
或许你曾经使用过这种构图方式,却并不了解其背后的概念含义。我将为你举一个简单的例子。
假设我们要清理用户输入的内容,我们有一个函数可以删除空格,还有一个函数可以删除特殊字符。
const withoutSpaces = (value) => value.replace(/ /g, "");
const removeSpecialChars = (value) => value.replace(/[^a-zA-Z ]/g, "");
我们可以通过以下方式将这些函数合并成一个函数:
const compose = (f1, f2) => (value) => f2(f1(value));
const emptyInput = compose(withoutSpaces, removeSpecialChars);
console.log(emptyInput(" d'ani el")); // daniel
我们的 compose 函数会返回一个新函数,该函数接收一个参数并返回最终的字符串。如果你仔细观察f2 (f1 (value)),你会发现我们实际上是将第一个函数的结果传递给了第二个函数,就这么简单。
如果我们想要组合多个函数,我们可以使用 reduceRight 方法。
const withoutSpaces = (value) => value.replace(/ /g, "");
const removeSpecialChars = (value) => value.replace(/[^a-zA-Z ]/g, "");
const toLowerCase = (value) => value.toLowerCase();
const compose = (...fns) => (initialVal) =>
fns.reduceRight((val, fn) => fn(val), initialVal);
const emptyInput = compose(withoutSpaces, removeSpecialChars, toLowerCase);
console.log(emptyInput(" d'AVID ")); // david
结论
希望这些概念能让你学到/理解一些新东西,如果你有什么补充,请在评论区留言。
接下来几天,我将撰写一些关于 JavaScript 中其他有趣概念的文章。
文章来源:https://dev.to/dcastro/4-javascript-things-you-need-to-know-37el