Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/443.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 我的函数不在另一个函数范围之外工作,即使我已导入它_Javascript_Webpack_Scope_Babeljs_Ecmascript 5 - Fatal编程技术网

Javascript 我的函数不在另一个函数范围之外工作,即使我已导入它

Javascript 我的函数不在另一个函数范围之外工作,即使我已导入它,javascript,webpack,scope,babeljs,ecmascript-5,Javascript,Webpack,Scope,Babeljs,Ecmascript 5,我试图弄清楚下面的代码是怎么回事,我已经使用import{gettoos}从“./todos”将我的函数导入到另一个名为views.js的文件中。我试图在views.js的顶层调用gettoos,但是我得到一个错误,它不是一个函数,它是未定义的。但是,一旦我尝试在同一模块中的函数中使用gettoos,它就会突然起作用!?为什么它突然不再是未定义的,我如何修复代码以便在我想要的地方定义它 My todos.js文件,其中包括定义getTodos函数: import uuidv4 from 'uui

我试图弄清楚下面的代码是怎么回事,我已经使用import{gettoos}从“./todos”将我的函数导入到另一个名为views.js的文件中。我试图在views.js的顶层调用gettoos,但是我得到一个错误,它不是一个函数,它是未定义的。但是,一旦我尝试在同一模块中的函数中使用gettoos,它就会突然起作用!?为什么它突然不再是未定义的,我如何修复代码以便在我想要的地方定义它

My todos.js文件,其中包括定义getTodos函数:

import uuidv4 from 'uuid/v4'
import { renderTodos } from './views'

let todos = []

const loadTodos = () => {
    const todosJSON = localStorage.getItem('todos')
    try {
        return todosJSON ? JSON.parse(todosJSON) : []
    } catch (e) {
        return []
    }
}


todos = loadTodos()

const getTodos = () => todos


const saveTodos = () => {
    localStorage.setItem('todos', JSON.stringify(todos))
}


const createTodo = (text) => {

    if (text.length > 0) {
        todos.push({
            id: uuidv4(),
            text,
            completed: false
        })
        saveTodos()
        renderTodos()
    }

}

const removeTodo = (id) => {
    const todoIndex = todos.findIndex((todo) => todo.id === id)

    if (todoIndex > -1) {
        todos.splice(todoIndex, 1)
        saveTodos()
    }
}

const toggleTodo = (id) => {
    const todo = todos.find((todo) => todo.id === id)

    if (todo) {
        todo.completed = !todo.completed
        saveTodos()
    }
}



export { loadTodos, getTodos, createTodo, removeTodo, toggleTodo }
My views.js文件,我正在尝试将getTodos加载到该文件中,然后使用它:

import { getTodos, saveTodos, toggleTodo, removeTodo  } from './todos'
import { getFilters } from './filters'

const todos = getTodos()
const renderTodos = () => {

    const filters = getFilters()
    const todosEl = document.querySelector('#todos')

    const filteredTodos = todos.filter((todo) => {
        const searchTextMatch = todo.text.toLowerCase().includes(filters.searchText.toLowerCase())
        const hideCompletedMatch = !filters.hideCompleted || !todo.completed

        return searchTextMatch && hideCompletedMatch
    })

    const incompleteTodos = filteredTodos.filter((todo) => !todo.completed)

    todosEl.innerHTML = ''
    todosEl.appendChild(generateSummaryDOM(incompleteTodos))

    if (todos.length > 0) {
        filteredTodos.forEach((todo) => {
            todosEl.appendChild(generateTodoDOM(todo))
        })
    } else {
        const emptyMessage = document.createElement('p')
        emptyMessage.textContent = 'No to-dos to show, go ahead and add some!'
        emptyMessage.classList.add('empty-message')
        todosEl.appendChild(emptyMessage)
    }
}


const generateTodoDOM = (todo) => {

    const todoEl = document.createElement('label')
    const containerEl = document.createElement('div')
    const checkbox = document.createElement('input')
    const removeButton = document.createElement('button')
    const span = document.createElement('span')


    // Setup Container
    todoEl.classList.add('list-item')
    containerEl.classList.add('list-item__container')
    todoEl.appendChild(containerEl)

    // Setup Remove Button
    removeButton.textContent = 'remove'
    removeButton.classList.add('button', 'button--text')
    removeButton.addEventListener('click', () => {
        removeTodo(todo.id)
        renderTodos()
    })
    span.textContent = todo.text


    // Setup Checkbox
    checkbox.setAttribute('type', 'checkbox')
    checkbox.checked = todo.completed
    checkbox.addEventListener('change', (e) => {
        toggleTodo(todo.id)
        renderTodos()
    })
    containerEl.appendChild(checkbox)


    containerEl.appendChild(span)
    todoEl.appendChild(removeButton)

    return todoEl
}

const generateSummaryDOM = (incompleteTodos) => {
    const summary = document.createElement('h2')
    summary.classList.add('list-title')
    const plural =  incompleteTodos.length === 1 ? '' : 's'
    summary.textContent = `You have ${incompleteTodos.length} todo${plural} left`
    return summary
}

// Make sure to set up the exports

export { generateSummaryDOM, renderTodos, generateTodoDOM }
index.js文件:

import { createTodo } from './todos'
import { renderTodos } from './views'
import { setFilters } from './filters'

// Render initial todos

renderTodos()

// Set up search text handler

document.querySelector('#search-todos').addEventListener('input', (e) => {
    setFilters({
        searchText: e.target.value
    })
    renderTodos()
})

// Set up checkbox handler

document.querySelector('#hide-completed').addEventListener('change', (e) => {
    setFilters({
        hideCompleted: e.target.checked
    })
    renderTodos()
})

// Set up form submission handler

document.querySelector('#add-todo').addEventListener('submit', (e) => {
    e.preventDefault()
    const text = e.target.elements.addTodoText.value.trim()
    createTodo(text)
    e.target.elements.addTodoText.value = ''
})
chrome调试器控制台中的错误包括:

views.js:4 Uncaught TypeError: (0 , _todos.getTodos) is not a function
    at Object../src/views.js (views.js:4)
    at __webpack_require__ (bootstrap:19)
    at Object../src/todos.js (todos.js:2)
    at __webpack_require__ (bootstrap:19)
    at Object../src/index.js (index.js:1)
    at __webpack_require__ (bootstrap:19)
    at Object.0 (bundle.js:20254)
    at __webpack_require__ (bootstrap:19)
    at bootstrap:68
    at bootstrap:68
我只是想理解为什么会发生这种奇怪的行为,因为一旦我在renderTodos中使用getTodos,它实际上就可以工作了,而且我没有收到任何错误,比如:

const renderTodos = () => {
    const todos = getTodos()
    // Other stuffs
}

我正在使用Babel和Webpack。

主要的问题是您有一个循环依赖关系。对于能够说明问题的更简单示例,请考虑:

// foo.js
import bar from './bar';
const x = bar();
export default () => x;

// bar.js
import foo from './foo';
const y = foo();
export default () => y;
在上面的代码中,就像在您的代码中一样,您有使用导入的模块,其中所述导入还依赖于从当前模块导入内容。如果A从B导入,并且B也从A导入,那么您需要确保在A和B的两个顶级代码都完成之前,它们都不使用彼此的任何内容-否则,您不能依赖于当时定义的另一个导入

最好重构代码,以某种方式删除循环依赖关系

我喜欢使用的一种模式是确保模块中的顶级代码不会启动任何东西——相反,当所有东西最终都可以从入口点(这里看起来是index.js)启动时,这很好。一个快速修复方法是每个模块导出一个运行初始化代码的函数,而不是将该代码放在顶层。例如:

// views.js

import { getTodos, saveTodos, toggleTodo, removeTodo  } from './todos'
import { getFilters } from './filters'

let todos;
const init = () => {
  todos = getTodos();
};
// ... everything else
export { generateSummaryDOM, renderTodos, generateTodoDOM, init }
然后让index.js导入,并在导入所有内容之后在一开始调用init

幸运的是,由于todos.js只调用cross模块,在其createTodo函数中导入了rendertodo,并且createTodo已导出但未在todos.js中调用,因此不需要对其进行更改

另一个可能更好的选择是删除todos.js对renderdos的依赖性。在todos.js中,您当前仅在其createTodo函数中使用renderTodos。考虑改变thigs,以便创建和保存ToDo,但不使用ReDeRotoDOS来渲染它,而是查找CuroToToDo在哪里使用,它看起来仅在索引x.js中,并且具有索引。 及


您没有导出getTodos,因此无法在其他文件中导入它。我已经导出了getTodos,但我没有在上面的代码中显示它。很抱歉,我忘了在末尾添加它。谢谢,您可以显示您在todos.js中使用RenderTos的位置吗?弄清楚这一点将揭示事情是如何发展的refactored@CertainPerformance我已经添加了所有使用renderTodosYes的文件,它确实有效!需要提到的是,我还需要从todos.js的./views`中删除导入{rendertoos}。即使该函数根本没有被使用,但如果代码到位,就会把事情搞砸。
// todos.js

// do not import renderTodos here

// ...
const createTodo = (text) => {
    if (text.length > 0) {
        todos.push({
            id: uuidv4(),
            text,
            completed: false
        })
        saveTodos()
    }
}
// index.js

// ...
document.querySelector('#add-todo').addEventListener('submit', (e) => {
    e.preventDefault()
    const text = e.target.elements.addTodoText.value.trim()
    createTodo(text)
    renderTodos();
    e.target.elements.addTodoText.value = ''
})