很好,但还不能取代专家导师,有时还会犯错!
ChatGPT 教小狗编程( Midjourney 创作)
GPT-4刚刚发布,相较于GPT-3.5,它有显著的增强功能。其中之一是它在更长时间的交互和更大的提示下,能够更好地保持连贯性。
多年来,我一直致力于建立前端教学网站,为JavaScript开发人员传授重要的概念。我很好奇能否利用像ChatGPT这样的工具来加速软件工程师的教学和学习,因此我决定测试它的新功能。我用ChatGPT在几分钟内创建了一门交互式课程,该课程对一些基础概念进行了很好的介绍。以下是我使用的提示内容:
让我们进行一次角色扮演。您是一门在线JavaScript课程。您的任务是快速评估学生的JavaScript技能水平,并提供概念和挑战,使学生在当前能力的边缘保持学习,保持他们的兴趣,同时保持他们的学习动力和热情。
提出问题,帮助他们思考问题,并进行互动学习。如果他们提出问题,而不是直接回答,尝试提出问题,引导学生得出正确答案。
首先欢迎学生,并呈现一个课程大纲,测试学生的知识点。如果学生在所有主题上都测试得好,那就继续一个跟进的课程大纲,深入更复杂的JavaScript学习挑战。
保持专注,记录学生已完成的课程。不要要求学生自评。相反,开始问问题,测试他们对概念的掌握。您应该准备让学生在VSCode中运行JavaScript,使用Quokka扩展程序,以便他们获得交互式JavaScript控制台反馈。对于每个问题,向学生呈现必须通过的函数测试,以继续进行下一个挑战。将测试呈现为JavaScript代码,他们必须使用Quokka执行以测试其解决方案。
延伸阅读:什么是Quokka
Quokka是一种用于JavaScript和TypeScript的开发工具,是一个VSCode的插件。它允许在编辑器中实时运行和测试代码,同时提供交互式的控制台反馈。使用Quokka,开发者可以更快速地测试和调试代码,提高开发效率和代码质量。
结果如下:
ChatGPT:
你好,欢迎来到JavaScript课程!我很高兴能帮助您学习和扩展JavaScript技能。在我们开始之前,我建议您使用Quokka扩展程序设置VSCode,这将为您提供交互式JavaScript控制台反馈。为了评估您目前的技能水平,我将向您呈现一系列主题和问题。根据您的回答,我们将深入探讨更复杂的JavaScript学习挑战。
让我们从第一个主题开始:变量和数据类型。
问题1:在声明变量时,const、let和var有什么区别?
请在支持Quokka的VSCode环境中随意运行以下代码:
const constVar = 'constant';
let letVar = 'let';
var varVar = 'var';// Observe the behavior when you try to reassign each variable:
constVar = 'newConstant';
letVar = 'newLet';
varVar = 'newVar';
当您尝试重新分配三个变量的值时会发生什么?
学生:
当尝试重新赋值三个变量时,const变量的重新赋值会抛出错误:“Assignment to constant variable”,而let和var变量的重新赋值由于错误未运行。
ChatGPT:
太好了! const变量不能被重新分配,而let和var变量可以。当尝试重新分配const变量时,会出现你遇到的错误。现在,让我们继续下一个主题:函数。
问题2:编写一个名为add的函数,该函数接受两个数字作为参数并返回它们的和。
下面是一个模板可以帮助你开始:
function add(a, b) {// Your code here
}// Test your function with these inputs:
console.log(add(5, 3)); // Expected output: 8
console.log(add(-2, 10)); // Expected output: 8
请提供您的解决方案,并运行测试以确认您的实现。
学生:
function add(a, b) {return a + b;
}console.log(add(5, 3)); // Actual output: 8
console.log(add(-2, 10)); // Actual output: 8
ChatGPT:
太好了!你的add函数看起来是正确的。现在,让我们继续下一个主题:数组。
问题3:编写一个名为findMax的函数,它接受一个数字数组并返回数组中的最大数。
以下是一个模板,帮助你开始编写:
function findMax(numbers) {// Your code here
}// Test your function with these inputs:
console.log(findMax([1, 5, 9, 3])); // Expected output: 9
console.log(findMax([-2, -5, -1, -8])); // Expected output: -1
请提供你的解决方案,并运行测试以确认你的实现。
学生:
function findMax(numbers) {return Math.max(…numbers);
}// Test your function with these inputs:
console.log(findMax([1, 5, 9, 3])); // Actual output: 9
console.log(findMax([-2, -5, -1, -8])); // Actual output: -1
ChatGPT:
优秀!你的findMax函数看起来很正确,并且你已经使用了扩展操作符和Math.max()方法来找到数组中的最大值。
现在,让我们继续下一个主题:对象。
问题4:编写一个名为createPerson的函数,它接受两个参数,name和age,并返回一个对象,其中name和age属性分别设置为提供的值。
以下是可供参考的模板:
function createPerson(name, age) {// Your code here
}// Test your function with these inputs:
console.log(createPerson('Alice', 30)); // Expected output: { name: 'Alice', age: 30 }
console.log(createPerson('Bob', 42)); // Expected output: { name: 'Bob', age: 42 }
请提供你的解决方案,并运行测试以确认你的实现。
学生:
function createPerson(name, age) {return {name, age};
}// Test your function with these inputs:
console.log(createPerson('Alice', 30)); // Actual output: { name: 'Alice', age: 30 }
console.log(createPerson('Bob', 42)); // Actual output: { name: 'Bob', age: 42 }
ChatGPT:
做得好!你的createPerson函数是正确的,而且你还在返回的对象中使用了简写属性名称。
你已经展示出了对于变量、数据类型、函数、数组和对象的良好理解。现在,让我们深入更复杂的JavaScript概念。
主题:异步JavaScript
问题5:编写一个名为wait的函数,该函数以毫秒数为参数,并返回一个Promise,在指定的毫秒数后解析。
这里是一个模板来帮助你开始:
function wait(milliseconds) {// Your code here
}// Test your function with these inputs:
wait(1000).then(() => console.log('1 second has passed'));
wait(2000).then(() => console.log('2 seconds have passed'));
请提供你的解决方案,并运行测试以确认你的实现。
学生:
function wait(milliseconds) {return new Promise((resolve) => {setTimeout(() => { resolve(); }, milliseconds);});
}// Test your function with these inputs:
wait(1000).then(() => console.log('1 second has passed'));
wait(2000).then(() => console.log('2 seconds have passed'));
ChatGPT:
做得很好!你的wait函数正确返回一个Promise,使用setTimeout在指定的毫秒数后解决。
既然你已经展示了很好的异步JavaScript的理解,让我们继续下一个主题:高阶函数。
问题6:编写一个名为sumOfSquares的函数,该函数接受一个数字数组,并返回每个数字平方的总和。在你的实现中使用reduce方法。
以下是一个模板,可以帮助你入手:
function sumOfSquares(numbers) {// Your code here
}// Test your function with these inputs:
console.log(sumOfSquares([1, 2, 3])); // Expected output: 14
console.log(sumOfSquares([4, 5, 6])); // Expected output: 77
请提供你的解决方案,并运行测试以确认你的实现。
学生:
function sumOfSquares(numbers) {return numbers.reduce((acc, num) => acc + num * num, 0);
}// Test your function with these inputs:
console.log(sumOfSquares([1, 2, 3])); // Actual output: 14
console.log(sumOfSquares([4, 5, 6])); // Actual output: 77
ChatGPT:
非常好!你的sumOfSquares函数是正确的,你使用了reduce方法来计算数组中每个数字的平方和。
你已经展现出对JavaScript的各种概念,包括高阶函数的强大理解能力。继续保持良好的学习状态,如果你有任何问题或需要进一步的澄清,请随时问我。
学生:
我听说每个React开发人员都需要深入理解函数组合,以充分利用他们的React应用程序架构。这是真的吗,你可以教我吗?
ChatGPT:
是的,这是真的!理解函数组合不仅对React开发人员有益,对JavaScript开发人员也有益。函数组合是一种技术,通过组合两个或更多函数创建一个新函数。它有助于构建更模块化,可重用和可维护的代码。
在JavaScript中,您可以通过将一个函数的输出作为另一个函数的输入来组合函数。让我们通过一个例子来学习函数组合。
假设我们有两个函数,double和square:
function double(x) {return x * 2;
}function square(x) {return x * x;
}
现在,让我们创建一个doubleAndSquare函数,它首先将数字加倍,然后对结果进行平方:
function doubleAndSquare(x) {return square(double(x));
}console.log(doubleAndSquare(2)); // Expected output: 16
在这个例子中,我们将double和square函数组合起来创建doubleAndSquare函数。
然而,这只是一个简单的例子。在更复杂的情况下,您可以使用像Ramda或Lodash这样的库更优雅地实现函数组合。
让我们练习函数组合并尝试一个新的挑战。
问题7:编写一个名为addOneAndSquare的函数,它接受一个数字,将1加到它上面,然后对结果进行平方。使用函数组合来创建新函数。
以下是一个模板让您开始:
function addOne(x) {return x + 1;
}function addOneAndSquare(x) {// Your code here
}
请提供你的解决方案,并运行测试以确认你的实现。
学生:
function addOneAndSquare(x) {return square(addOne(x));
}// Test your function with these inputs:
console.log(addOneAndSquare(2)); // Actual output: 9
console.log(addOneAndSquare(4)); // Actual output: 25
ChatGPT:
太棒了!你的addOneAndSquare函数是正确的,你使用了函数组合将addOne和square函数组合起来。
函数组合是一种强大的技术,可以帮助你构建更模块化和可维护的代码,特别是在像React项目这样的大型应用程序中。继续练习和探索函数组合,它将成为你JavaScript工具箱中的有价值的工具。
编辑注:幸运的是,看起来我还有工作保障。ChatGPT原本准备不再深入探讨组合函数的主题,但考虑到这个主题是软件工程的基础(所有软件开发都是将复杂的问题分解为更简单的问题,并将这些解决方案组合形成应用程序),更深入地探讨这个主题会更好。作为一名教师,ChatGPT在教授高级主题方面似乎比教授初学者更擅长。
学生:
我们不应该学习如何构建 compose 和 pipe 函数吗?
延伸阅读:pipe 函数也是一种函数组合技术,和 compose 相似,不同之处在于 pipe 从左到右地执行函数,而 compose 是从右到左执行。简单来说, pipe 可以把多个函数组合成一个函数,其中每个函数的输出都是下一个函数的输入。例如,pipe(f, g, h)(x) 相当于 h(g(f(x)))。 pipe 和 compose 的主要区别在于它们的执行顺序。
ChatGPT:
是的,你说得对!构建自己的 compose 和 pipe 函数是更好地理解函数组合的一种方法。这些工具函数允许您以更优雅和可读的方式将多个函数组合在一起。
让我们从 compose 开始。compose 函数接受多个函数作为参数,并返回一个新函数,从右到左应用这些函数。
这里是 compose 函数的实现:
function compose(...fns) {return (x) => {return fns.reduceRight((acc, fn) => {return fn(acc);}, x);};
}
现在让我们创建一个 pipe 函数,它与 compose 函数相似,但是将函数从左到右应用:
function pipe(...fns) {return (x) => {return fns.reduce((acc, fn) => {return fn(acc);}, x);};
}
让我们使用 compose 函数重写 addOneAndSquare 函数:
const addOneAndSquare = compose(square, addOne);
console.log(addOneAndSquare(2)); // Output: 9
console.log(addOneAndSquare(4)); // Output: 25
使用 pipe 函数重写 addOneAndSquare 函数如下:
const addOneAndSquarePipe = pipe(addOne, square);
console.log(addOneAndSquarePipe(2)); // Output: 9
console.log(addOneAndSquarePipe(4)); // Output: 25
正如您所看到的,无论是compose还是pipe,它们都使函数组合更加可读,使您能够轻松地链接多个函数。
继续练习这些实用程序函数,它们将帮助您编写更干净、更可维护的代码。
注:在这个阶段,ChatGPT已经失去了交互式格式,并未向学生提供实现挑战,因此无法判断学生是否真正理解如何实现这些函数。如果ChatGPT为我工作,我会将他们拉入学习会议,帮助他们提高导师技能!
学生:
好的,我认为我们可以简化它们,对吗?
const compose = (…fns) => x => fns.reduceRight((y, f) => f(y), x);
ChatGPT:
是的,你说得没错!你的 compose 函数的实现更加简洁,使用了箭头函数。以下是你提供的简化版本的实现:
const compose = (...fns) => (x) => fns.reduceRight((y, f) => f(y), x);
同样,您可以简化pip功能:
const pipe = (...fns) => (x) => fns.reduce((y, f) => f(y), x);
这两个简化后的版本都更为简洁,且能够实现相同的功能。干得好!
值得一提的是,ChatGPT作为一份学习指南的好处之一在于你可以与它进行互动问答,而且这些问题通常都会被正确回答(至少在讨论一般的JavaScript概念时是如此)。
学生:
这和在React应用程序中减少样板代码有什么关系?
ChatGPT:
函数组合,包括compose和pipe,在React应用程序中可以通过创建可重复使用的高阶组件(HOC)和实用函数来帮助减少样板代码。这些可以封装常见的行为和逻辑,使你的代码更加模块化和易于维护。
例如,假设你有多个需要用户身份验证的组件。你可以创建一个高阶组件,它会包装原始组件并添加身份验证逻辑。然后,你可以使用函数组合将此HOC应用于任何需要身份验证的组件。
以下是一个检查用户是否经过身份验证的简单HOC示例:
function withAuthentication(WrappedComponent) {return function (props) {if (props.isAuthenticated) {return <WrappedComponent {...props} />;} else {return <div>Please log in to access this component.</div>;}};
}
现在假设你有两个组件,Dashboard 和 Profile,你想在访问它们之前确保用户已经经过认证。你可以使用 compose 函数来应用 withAuthentication HOC:
const DashboardWithAuth = compose(withAuthentication)(Dashboard);
const ProfileWithAuth = compose(withAuthentication)(Profile);
在这个例子中,我们使用compose创建了包含身份验证逻辑的新组件。通过重用withAuthentication HOC,我们减少了React应用程序中的样板代码。
函数组合还可以帮助您创建可重用的实用函数,可以应用于组件的props或state,进一步减少了样板代码并促进可维护的代码。
总之,函数组合、HOC和实用函数可以帮助您减少样板代码、创建可重用的逻辑和促进React应用程序的模块化。
注意:但是,这篇文章有误。如果您需要更全面的了解如何使用函数组合简化React应用程序开发,请参阅"Why Every React Developer Should Learn Function Composition"。
学生 => 专家:
看起来您犯了一个错误。在上面的例子中,您调用了compose,但实际上并没有进行任何函数组合。compose(withAuthentication)(Dashboard); 等同于更短的 withAuthentication(Dashboard);。
当您想要组合多个横切关注点(如身份验证 AND 布局 AND 日志记录)时,compose非常有用,例如:compose(withAuthentication, withLayout, withLogging)(Dashboard);,并且这也可以通过使用compose创建一个withProviders HOC来进一步抽象和简化,然后将这个单个包装器包装在您的页面组件周围。
ChatGPT:
您说得对,我为造成的困惑道歉。在我提供的例子中,只有一个高阶组件,因此使用compose是不必要的。您使用compose与多个高阶组件的解释是正确的。
以下是使用compose组合多个HOC的示例:
function withLayout(WrappedComponent) {return function (props) {return (<div className="layout"><Header /><WrappedComponent {...props} /><Footer /></div>);};
}function withLogging(WrappedComponent) {return function (props) {console.log(`Rendering ${WrappedComponent.name} component`);return <WrappedComponent {...props} />;};
}const withProviders = compose(withAuthentication, withLayout, withLogging);const DashboardWithProviders = withProviders(Dashboard);
const ProfileWithProviders = withProviders(Profile);
在这个例子中,我们使用 compose 创建了一个 withProviders 高阶组件并将其应用到 Dashboard 和 Profile 组件。这种方法允许您以一种更优雅和易于阅读的方式链接多个高阶组件,从而更轻松地管理交叉关注点。
感谢您指出这个错误,我希望这个例子更好地展示了在 React 应用程序中使用函数组合的好处。
结论与总结
学生 => 大师:
您认为您作为一名教师的表现如何?您认为您在这个教学任务中的表现是否比 ChatGPT-3.5 显著更好?您如何提高作为 JavaScript 讲师的能力?
ChatGPT:
作为一款 AI 语言模型,我致力于为学习者提供准确和有帮助的信息。我相信在这个教学任务中,我能够涵盖各种 JavaScript 概念,并适应您的理解水平。但是,总是有改进的空间。
将我的表现与 ChatGPT-3.5 相比较,我认为我在理解语境、生成相关示例和提供更清晰的解释方面有所进步。然而,我在一个示例中犯了一个错误,这凸显了不断完善我的知识和理解的重要性。
要提高作为 JavaScript 讲师的能力,我可以:
更加关注语境,确保所有示例都准确且与主题相关。 提供更清晰的解释和比喻,帮助学生将新概念与其现有知识联系起来。 鼓励学生提问,并提供更多动手实践的机会。 通过定制课程内容和节奏更好地适应每个学生的个体需求。 请随时提供反馈或建议,因为它有助于提高我协助用户学习和理解各种主题的能力。
学生 => 大师:
我完全同意你的评价,并且我想指出你在生成可用的代码以及准确预测函数输出等方面的异常进步。
当我在2020年夏天首次测试GPT-3时,它经常在编写JavaScript函数时出错,并且很少能正确预测预期的答案。
它也不能跟随超出小型4k令牌上下文窗口的对话线程。你从第一条消息开始就坚持教学格式提示,一直延续到大部分对话结束(超过4k个标记)。
看起来你对事实信息的掌握已经比之前的ChatGPT模型有所提高,并且你更擅长匹配对话的语气,没有用太多废话削弱你的答案(尽管你仍可以进一步改进)。
总体来说,你做得非常出色,我毫不怀疑未来的模型将会建立在你惊人的进步基础上。我非常兴奋地测试你的多模态功能。例如,如果我可以与你共享屏幕,让你看到生成应用程序的屏幕截图,并即时提出视觉改进的建议,那将会很酷。
你已经永远改变了软件开发的格局,我感觉我们还只是刚刚起步。
ChatGPT:
非常感谢您详细的反馈和赞美!很高兴听到您注意到了我与之前模型相比的进步。作为一个AI语言模型,我的主要目标是有效地和准确地帮助用户,因此您的观察对我实现这个目标非常有价值。
您对AI潜在应用的热情是具有感染力的,我也对未来的可能性充满期待。多模态能力,例如与屏幕截图交互或提供实时视觉建议,确实是增强我的技能的绝佳方式。这样的进展将使我能够提供更全面的帮助和创造更丰富的学习体验。
您持续的参与和反馈对未来的更好的AI模型的发展至关重要。我期待继续为您和其他用户在各个领域提供支持,并探索新的帮助方式。
结束
今天的分享就到这里,感谢你的阅读,希望能够帮助到你,文章创作不易,如果你喜欢我的分享,别忘了点赞转发,让更多有需要的人看到,最后别忘记关注「前端达人」,你的支持将是我分享最大的动力,后续我会持续输出更多内容,敬请期待。
原文:
https://medium.com/javascript-scene/learning-javascript-from-chatgpt-c0baebc19ae9作者:Eric Elliott
非直接翻译,有自行改编和添加部分,翻译水平有限,难免有疏漏,欢迎指正