# Namespace

  • Variable names need to be unique
    变量名必须是唯一的
  • All variables by default are placed in the global window namespace when defined normally with the var keyword unless defined inside a function . Functional Scope, changes some with ES6+ let and const
    默认情况下,所有变量使用 var 关键字定义的变量,都放置在全局 window 命名空间中,除非在 function 中定义。函数作用域,在 ES6+ letconst 有一些改变
  • Variables defined inside a function are scoped or name spaced to that function.
    在函数内定义的变量的作用域或命名空间为该函数。
  • If we mix our code with others code, we may overlap variable names
    如果我们将我们的代码与其他代码混合在一起,我们可能会重叠变量名
  • We want to define our own namespace
  • We have a few ways we can do that.

# Self executing protecting function or Immediately-invoked Function Expressions IIFE

自我执行保护功能或立即调用的功能表达

(function(){
    //anything in here has its own special namespace
    // 这里的任何东西都有自己特殊的命名空间
    //functions and variables are not available to the outside
    // 函数和变量对外不可用
})();

# The Big Plain Map/Object Literal

var myNamespace = {};
myNamespace.aFunction = function(){
};
myNamespace.aVariable = 7;
  • Use everything from the Map/Object
    使用地图 / 对象中的所有内容
  • Useful for quick solution but doesn’t have private variables or methods at all
    用于快速解决方案但没有私有变量或方法论

# Exporting a Map to the global Namespace

向全局命名空间输出 Map

(function(){
    var myNamespace = {};
    //Private variables
    var name = "brian";
    //Public members/variables
    myNamespace.myName = "brian";
    //Public Method
    myNamespace.myFunction = function(){    
        alert(this.myName)
    };
    window.myNamespace = myNamespace;
})();

# Exporting a Map to the global Namespace with possible namespace in window already

向全局命名空间输出 Map,window 中可能已存在命名空间

(function(ns){
    //Private variables
    var name = "brian";
    //Public members/variables
    ns.myName = "brian";
    //Public Method
    ns.myFunction = function(){
        alert(this.myName)
    };
    window.myNamespace = ns;
})(window.myNamespace || {});

# Return a Map to the specified Namespace

将 Map 返回到指定的命名空间

var namespace = function(){
    var myNamespace = {};
    //Private variables
    var name = "brian";
    //Public members/variables
    myNamespace.myName = "brian";
    //Public Method
    myNamespace.myFunction = function(){
        alert(this.myName)
    };
    return myNamespace;
}();

# Namespace as a function parameter

命名空间作为函数参数

var namespace = {};
(function(ns){
    //set up private data here
    //public data
    ns.aFunc = function(){
        // ...
    };
    ns.aVar = 123;
})(namespace);

# Wrapping with an event function

用事件函数包装

  • Another option would be using the window event function like DOMContentLoaded to act as your namespace protector.
    另一种选择是使用 window 事件函数,如 DOMContentLoaded 作为命名空间的保护者。

  • Since the event handler is a function, it has function scope and keeps the variables and functions local to that function.
    由于事件处理程序是一个函数,它具有函数作用域,并保持该函数的局部变量和函数。

# Waiting for the DOM

等待 DOM 准备就绪

  • How do you prevent your JS from running before the page is ready to be manipulated?
    如何在页面准备好被操纵之前,阻止 JS 运行?
    • You could add and an event handler to the window ’s load event
      你可以为 windowload 事件添加一个事件处理函数
      • This will fire the event handler at the end of the document loading process.
        这将在文档加载过程结束时触发事件处理程序。
        All objects in the document are in DOM and all images, scripts, and other assets are also loaded.
        所有 DOM 中的对象文档,是指所有图像、脚本和其他资产也被加载。
      • Sometimes this will take longer than you really need.
        有时这会比您真正需要的时间更长。
        Most of the time you really just want the DOM to be ready to be manipulated.
        大多数时候你真的只是想要 DOM 准备好被操纵。
      • https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
  • Better option is often using the DOMContentLoaded event on the window or document object.
    更好的选择通常是在窗口或文档上使用 DOMContentLoaded 事件。
    • This event fires when the HTML document has been fully loaded and parsed. It does not wait for other assets like images and stylesheets.
      当 HTML 文档完全加载和解析时触发此事件。它不等待其他内容,如图像和样式表。
    • This event is often what you want vs listening for the full load event.
      这个事件通常是你想要的,而不是监听满载事件。
    • https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event
    • https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event
  • https://gist.github.com/jsonberry/0d71007ea188785e1a3d13d2e30d58a5
Load event
window.addEventListener('load', function (evt) {
    console.log('page is fully loaded');
});
DOMContentLoaded event
document.addEventListener('DOMContentLoaded', function (evt) {
    console.log('DOM fully loaded and parsed');
});

# DOM Element Creation and Deletion Demo

Basic DOM creation Demo
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Basic DOM creation Demo</title>
</head>
<body>
    <button id="btn">Insert Text</button>
    <div id="contentArea"></div>
    <script>
        window.addEventListener('load', function() {
            console.log('window load');
            document.getElementById('btn').addEventListener('click', function(){
                console.log('btn clicked');
                let headline = document.createElement('h1');
                headline.id = 'main-headline';
                headline.setAttribute('class', 'redtext');
                let hcontent = document.createTextNode('Hello Basic DOM Creation Demo');
                headline.appendChild(hcontent);
                document.getElementById('contentArea').appendChild(headline);
                let container = document.createElement('div');
                let para = document.createElement('p');
                para.appendChild(document.createTextNode('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'));
                container.appendChild(para);
                document.getElementById('contentArea').appendChild(container);
            });
        });
    </script>
</body>
</html>
DOM creation and deletion demo
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DOM creation and deletion demo</title>
</head>
<body>
    <div id="root"></div>
    <script>
        document.addEventListener('DOMContentLoaded', function(){
            console.log('DOMContentLoaded fired');
            
            let controls = document.createElement('div');
            controls.id = 'controlsWrapper';
            controls.style.backgroundColor = '#aaa';
            controls.style.padding = '20px';
            let textIn = document.createElement('input');
            textIn.setAttribute('type', 'text');
            textIn.id = 'textIn';
            let textLabel = document.createElement('label');
            textLabel.setAttribute('for', 'textIn');
            textLabel.appendChild(document.createTextNode('Enter Text: '));
            controls.appendChild(textLabel);
            controls.appendChild(textIn);
            let colorSelect = document.createElement('select');
            colorSelect.id = 'colorSelect';
            let optRed = document.createElement('option');
            optRed.setAttribute('value', '#ff0000');
            optRed.appendChild(document.createTextNode('Red'));
            colorSelect.appendChild(optRed);
            let optGreen = document.createElement('option');
            optGreen.setAttribute('value', '#00ff00');
            optGreen.appendChild(document.createTextNode('Green'));
            colorSelect.appendChild(optGreen);
            let optBlue = document.createElement('option');
            optBlue.setAttribute('value', '#0000ff');
            optBlue.appendChild(document.createTextNode('Blue'));
            colorSelect.appendChild(optBlue);
            controls.appendChild(colorSelect);
            let saveBtn = document.createElement('button');
            saveBtn.id = 'saveBtn';
            let saveBtnText = document.createTextNode('Save');
            saveBtn.appendChild(saveBtnText);
            saveBtn.addEventListener('click', saveHandler);
            controls.appendChild(saveBtn);
            document.getElementById('root').appendChild(controls);
            let list = document.createElement('ul');
            list.id = 'list';
            list.style.listStyleType = 'none';
            list.style.padding = '0';
            document.getElementById('root').appendChild(list);
            function saveHandler(){
                console.log('save clicked');
                let text = document.getElementById('textIn').value.trim();
                let color = document.getElementById('colorSelect').value;
                console.log('Text: ' + text + ', Color: ' + color);
                if (text === '') {
                    alert('Text can not be empty!');
                } else {
                    let item = document.createElement('li');
                    let img = document.createElement('img');
                    img.src = 'close.png';
                    img.setAttribute('alt', 'Delete Item Button');
                    img.style.width = '20px';
                    img.style.margin = '0 10px 0 0';
                    img.style.cursor = 'pointer';
                    img.addEventListener('click', function(e){
                        console.log('img clicked');
                        console.log(e);
                        //e.target.parentNode.parentNode.removeChild(e.target.parentNode);
                        this.parentNode.parentNode.removeChild(this.parentNode);
                    });
                    item.appendChild(img);
                    item.appendChild(document.createTextNode(text));
                    item.style.color = color;
                    document.getElementById('list').appendChild(item);
                    document.getElementById('textIn').value = '';
                    document.getElementById('colorSelect').selectedIndex = 0;
                }
            }
        }); //end DOMContentLoaded
    </script>
</body>
</html>
Dom Ready Demo
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dom Ready Demo</title>
    <script>
        window.addEventListener('load', function(){
            console.log('window load');
            let x = document.getElementById('closeimg').getAttribute('alt');
            console.log(x);
        });
        window.addEventListener('DOMContentLoaded', function(){
            console.log('DOMContentLoaded - window');
            let x = document.getElementById('closeimg').getAttribute('alt');
            console.log(x);
        });
        document.addEventListener('DOMContentLoaded', function(){
            console.log('DOMContentLoaded - document');
            let x = document.getElementById('closeimg').getAttribute('alt');
            console.log(x);
        });
    </script>
</head>
<body>
    <img id="closeimg" alt="close icon" src="close.png">
</body>
</html>

# Quiz 5

  1. The DOM method appendChild will insert an element as a child before any other child elements.

  2. The DOMContentLoaded event fires only on the document object.

  3. Which event handler will fire first?

    • document.addEventListener('DOMContentLoaded', function(){
          //event handler code
      });
    • window.addEventListener('load', function(){
          //event handler code
      });
  4. Wrapping your code in a DOMContentLoaded event handler is a way to protect the global namespace from your variables and functions.

  5. The DOM method createElement needs to be called on the document object.