为何无法将input.val()设为全局变量?如何实现代码DRY?
问题解答:邮编API调用的DRY优化与全局变量问题
问题描述
我需要用输入框里的邮编发起多个地图API调用,把邮编作为参数传入API URL,同时还要把邮编存到localStorage里供其他地方展示。
当我把var userPostalCode = $('#input').val()设为全局变量时,所有功能都失效了。我甚至在点击处理函数里加了event.preventDefault()尝试修复,但只有把这个变量设为函数局部变量时才能正常运行。但这样的代码完全不符合DRY原则,因为每个API调用里都要重复写相同的代码行。
请问:
a) 如何优化代码使其符合DRY原则?
b) 为何无法将该变量设为全局变量?
用户提供的抽象代码:
// Fires call to all API functions and renders page myBtn.click(function(event) { event.preventDefault(); // Runs mapping functions firstAPICall(); secondAPICall() saveToLocalStorage() }); function firstAPICall() { var userPostalCode = $('#input').val(); var FIRST_URL = `https://anotherwebsite.com/query=${userPostalCode}&limit=6&api_key=${API_KEY}`; $.ajax({ url: FIRST_URL, method: "GET" }).then(function(response) { // Code block }); }; function secondAPICall() { var userPostalCode = $('#input').val(); var SECOND_URL = `https://somewebsite.com/location=${userPostalCode}&api_key=${API_KEY}`; $.ajax({ url: SECOND_URL, method: "GET" }).then(function(response) { // Code block }); }; function saveToLocalStorage() { var userPostalCode = $('#input').val(); savedSearches.push(userPostalCode); localStorage.setItem("zipCode", JSON.stringify(savedSearches)); };
a) 代码优化方案(符合DRY原则)
核心思路是在点击事件触发时一次性获取邮编,再把这个值传递给各个需要它的函数,避免重复获取输入框值的操作。优化后的代码如下:
// 点击按钮触发所有操作 myBtn.click(function(event) { event.preventDefault(); // 只在这里获取一次当前输入的邮编 const userPostalCode = $('#input').val(); // 将邮编作为参数传递给各个函数 firstAPICall(userPostalCode); secondAPICall(userPostalCode); saveToLocalStorage(userPostalCode); }); function firstAPICall(postalCode) { const FIRST_URL = `https://anotherwebsite.com/query=${postalCode}&limit=6&api_key=${API_KEY}`; $.ajax({ url: FIRST_URL, method: "GET" }).then(function(response) { // 处理响应的代码块 }); }; function secondAPICall(postalCode) { const SECOND_URL = `https://somewebsite.com/location=${postalCode}&api_key=${API_KEY}`; $.ajax({ url: SECOND_URL, method: "GET" }).then(function(response) { // 处理响应的代码块 }); }; function saveToLocalStorage(postalCode) { savedSearches.push(postalCode); localStorage.setItem("zipCode", JSON.stringify(savedSearches)); };
如果想进一步简化,还可以封装通用的API调用逻辑,减少重复的AJAX代码:
// 通用AJAX调用函数,复用请求逻辑 function fetchFromAPI(url) { return $.ajax({ url: url, method: "GET" }); } // 点击事件处理 myBtn.click(function(event) { event.preventDefault(); const userPostalCode = $('#input').val(); // 调用封装后的API函数 fetchFromAPI(`https://anotherwebsite.com/query=${userPostalCode}&limit=6&api_key=${API_KEY}`) .then(response => { // 第一个API的响应处理逻辑 }); fetchFromAPI(`https://somewebsite.com/location=${userPostalCode}&api_key=${API_KEY}`) .then(response => { // 第二个API的响应处理逻辑 }); saveToLocalStorage(userPostalCode); }); function saveToLocalStorage(postalCode) { savedSearches.push(postalCode); localStorage.setItem("zipCode", JSON.stringify(savedSearches)); };
b) 全局变量失效的原因
你把userPostalCode设为全局变量时,变量的赋值时机错误:
- 如果全局变量是在页面加载时就执行
var userPostalCode = $('#input').val(),此时输入框还没有用户输入的内容,变量值就是空字符串。 - 后续用户输入邮编、点击按钮时,全局变量不会自动更新,仍然保留页面加载时的空值,导致API调用传入无效参数,功能自然失效。
而把变量放在函数内部时,每次点击按钮调用函数,都会重新获取输入框的当前值,所以能正常工作。
如果一定要使用全局变量,需要在点击事件触发时重新更新全局变量的值,示例如下:
// 声明全局变量 let userPostalCode; myBtn.click(function(event) { event.preventDefault(); // 点击时更新全局变量为当前输入的邮编 userPostalCode = $('#input').val(); firstAPICall(); secondAPICall(); saveToLocalStorage(); }); // 后续函数直接使用全局变量 function firstAPICall() { const FIRST_URL = `https://anotherwebsite.com/query=${userPostalCode}&limit=6&api_key=${API_KEY}`; // ... AJAX代码 }
不过这种方式不如参数传递清晰,容易引发变量污染或意外的取值错误,更推荐前面的参数传递方案。
内容的提问来源于stack exchange,提问作者BuiltByDan
相关产品推荐
相关产品推荐

