이 글은 JavaScript에서 가장 자주 발생하는 10가지 오류를 모아 놓은 것입니다. 이러한 오류의 원인과 오류를 방지하는 방법을 알려드리겠습니다. 도움이 필요한 친구들이 참고할 수 있습니다
개발자 커뮤니티에 보답하기 위해 우리는 수천 개의 프로젝트 데이터베이스를 조사한 결과 JavaScript에서 가장 자주 발생하는 오류 10개를 발견했습니다. 이러한 오류의 원인과 이러한 오류가 발생하지 않도록 방지하는 방법을 알려드리겠습니다. 이러한 "함정"에 빠지지 않을 수 있다면 당신은 더 나은 개발자가 될 것입니다.
데이터가 왕입니다. 가장 자주 발생하는 JavaScript 오류 상위 10개를 수집하고 분석했습니다. Rollbar는 각 프로젝트의 모든 오류를 수집하고 각 오류가 발생한 횟수를 요약합니다. 이를 위해 "지문"(롤바에서 사용하는 알고리즘, https://rollbar.com/docs/grouping-algorithm/ 참조)을 기반으로 오류를 그룹화합니다. 기본적으로 두 번째 오류가 첫 번째 오류와 중복된 경우 두 오류를 모두 동일한 그룹으로 그룹화합니다. 이렇게 하면 로그 파일에 표시되는 엄청난 양의 덤프보다는 사용자에게 좋은 개요를 제공할 것입니다.
우리는 귀하와 귀하의 사용자에게 가장 큰 영향을 미칠 수 있는 버그에 중점을 둡니다. 이를 위해 다양한 회사의 프로젝트 세트를 연구하여 오류의 순위를 매겼습니다. 각 오류가 발생한 총 횟수만 살펴보면 대용량 프로젝트에서 생성된 오류가 다른 오류를 압도하여 대부분의 독자에게는 관련이 없는 오류 데이터 세트가 될 수 있습니다.
다음은 상위 10개 JavaScript 오류입니다.
쉽게 읽을 수 있도록 각 오류 설명을 단축했습니다. 다음으로, 각 오류를 자세히 살펴보고 오류의 원인과 오류 발생을 방지하는 방법을 알아보세요.
1. Uncaught TypeError: Cannot read property
JavaScript 개발자라면 이 오류를 감히 인정할 수 없을 만큼 많이 보았을 것입니다(웃음...). 이 오류는 정의되지 않은 개체의 속성을 읽거나 해당 메서드를 호출할 때 Chrome에서 발생합니다. Chrome 개발자 콘솔에서 쉽게 테스트(시도해보기)할 수 있습니다.
이런 일이 발생하는 데에는 여러 가지 이유가 있지만 일반적인 이유는 UI 구성 요소를 렌더링할 때 상태 초기화가 부적절하기 때문입니다.
실제 애플리케이션에서 어떤 일이 일어나는지 예를 살펴보겠습니다. 우리는 React를 선택했지만 Angular, Vue 또는 기타 프레임워크에도 동일하게 적용됩니다.
class Quiz extends Component { componentWillMount() { axios.get('/thedata').then(res => { this.setState({items: res.data}); }); } render() { return ( <ul> {this.state.items.map(item => <li key={item.id}>{item.name}</li> )} </ul> ); } }
여기서 달성해야 할 두 가지 중요한 사항이 있습니다.
구성 요소의 상태(예: this.state)는 정의되지 않음에서 시작됩니다.
데이터를 비동기식으로 가져오는 경우 생성자 componentWillMount 또는 componentDidMount에서 가져오든 구성 요소는 데이터가 로드되기 전에 적어도 한 번 렌더링되며 퀴즈가 처음 렌더링되면 this.state.items가 정의되지 않습니다. 이는 결국 ItemList가 항목을 정의되지 않은 것으로 정의하고 콘솔에 오류가 표시됨을 의미합니다. "Uncaught TypeError: Cannot read property 'map' of ununde".
이 문제는 쉽게 해결할 수 있습니다. 가장 간단한 방법은 합리적인 기본값을 사용하여 생성자의 상태를 초기화하는 것입니다.
class Quiz extends Component { // Added this: constructor(props) { super(props); // Assign state itself, and a default value for items this.state = { items: [] }; } componentWillMount() { axios.get('/thedata').then(res => { this.setState({items: res.data}); }); } render() { return ( <ul> {this.state.items.map(item => <li key={item.id}>{item.name}</li> )} </ul> ); } }
애플리케이션의 특정 코드는 다를 수 있지만 애플리케이션에서 이 문제를 해결하거나 방지할 수 있는 충분한 단서를 제공했기를 바랍니다. 아직 읽어보지 않으셨다면 아래에서 관련 오류에 대한 더 많은 예를 다룰 것이므로 계속 읽어보세요.
2. 유형 오류: '정의되지 않음'은 객체가 아닙니다
Safari에서 정의되지 않은 객체에 대한 속성을 읽거나 메서드를 호출할 때 발생하는 오류입니다. Safari 개발자 콘솔에서 이를 쉽게 테스트할 수 있습니다. 이는 본질적으로 1에서 언급한 Chrome 오류와 동일하지만 Safari는 다른 오류 메시지를 사용합니다.
3. TypeError: null은 개체가 아닙니다
Safari에서 null 개체의 속성을 읽거나 메서드를 호출할 때 발생하는 오류입니다. Safari 개발자 콘솔에서 이를 쉽게 테스트할 수 있습니다.
흥미롭게도 JavaScript에서는 null과 정의되지 않음이 동일하지 않기 때문에 두 가지 다른 오류 메시지가 표시됩니다. 정의되지 않음은 일반적으로 할당되지 않은 변수이고, null은 값이 비어 있음을 의미합니다. 동일하지 않은지 확인하려면 엄격한 항등 연산자 ===를 사용해 보세요.
실제 예에서 이 오류가 발생할 수 있는 한 가지 시나리오는 요소를 로드하기 전에 JavaScript에서 요소를 로드하려고 시도하는 경우입니다. 강요. DOM API가 빈 객체 참조에 대해 null을 반환하기 때문입니다.
任何执行和处理 DOM 元素的 JS 代码都应该在创建 DOM 元素之后执行。 JS 代码按照 HTML 中的规定从上到下进行解释。 所以,如果 DOM 元素之前有一个标签,脚本标签内的 JS 代码将在浏览器解析 HTML 页面时执行。 如果在加载脚本之前尚未创建 DOM 元素,则会出现此错误。
在这个例子中,我们可以通过添加一个事件监听器来解决这个问题,这个监听器会在页面准备好的时候通知我们。 一旦 addEventListener被触发,init() 方法就可以使用 DOM 元素。
<script> function init() { var myButton = document.getElementById("myButton"); var myTextfield = document.getElementById("myTextfield"); myButton.onclick = function() { var userName = myTextfield.value; } } document.addEventListener('readystatechange', function() { if (document.readyState === "complete") { init(); } }); </script> <form> <input type="text" id="myTextfield" placeholder="Type your name" /> <input type="button" id="myButton" value="Go" /> </form>
4. (unknown): Script error
当未捕获的 JavaScript 错误(通过window.onerror处理程序引发的错误,而不是捕获在try-catch中)被浏览器的跨域策略限制时,会产生这类的脚本错误。 例如,如果您将您的 JavaScript 代码托管在 CDN 上,则任何未被捕获的错误将被报告为“脚本错误” 而不是包含有用的堆栈信息。这是一种浏览器安全措施,旨在防止跨域传递数据,否则将不允许进行通信。
要获得真正的错误消息,请执行以下操作:
1. 发送 ‘Access-Control-Allow-Origin' 头部
将 Access-Control-Allow-Origin 标头设置为 * 表示可以从任何域正确访问资源。 如有必要,您可以将域替换为您的域:例如,Access-Control-Allow-Origin:www.example.com。 但是,处理多个域会变得棘手,如果你使用 CDN,可能由此产生更多的缓存问题会让你感觉到这种努力并不值得。 在这里看到更多。
这里有一些关于如何在各种环境中设置这个头文件的例子:
Apache
在 JavaScript 文件所在的文件夹中,使用以下内容创建一个 .htaccess 文件:
Header add Access-Control-Allow-Origin "*"
Nginx
将 add_header 指令添加到提供 JavaScript 文件的位置块中:
location ~ ^/assets/ { add_header Access-Control-Allow-Origin *; }
HAProxy
将以下内容添加到您为 JavaScript 文件提供资源服务的后端:
rspadd Access-Control-Allow-Origin:\ *
2. 在