javascript – ‘var webApp = {..}’和’var webApp = function(){..}’之间的区别是什么?

我最近一直在尝试使用模块化JS,我仍然想知道我是否正在以“正确的方式”编写它.

例如,如果我有一个页面,其中有输入和提交按钮,应该在提交后显示数据(例如表格和图形),所以我在IFFE下编写代码,所以没有任何东西可以访问它,但是使用这样的对象变量:

var webApp = { ... } 

在其中我从DOM缓存元素,添加绑定事件和其他有用的功能.

这是我用于表单的真实代码,在加载数据时应该显示图形,表格和进度条,并且所有代码都在一个对象qwData中进行管理:

(function() {

    const qwData = {

        // Initialize functions
        init: function() {
            this.cacheDom();
            this.bindEvents();
        },
        // Cache vars 
        cacheDom: function() {
            this.dataDisplayed      = false;
            this.countUsers         = <?php echo $_SESSION['all_users_count_real']; ?>;
            this.customerMachines   = <?php echo $_SESSION['customer_statistics']['total_machines']; ?>;
            this.$form              = $('#frm');
            this.$alistToolbar      = this.$form.find('.alist-toolbar');
            this.start_date         = this.$form[0][9].value;
            this.end_date           = this.$form[0][10].value;
            this.dateCount          = this.countDays(this.start_date, this.end_date);
            this.show               = document.querySelector('#btn-show');
            this.downloadBtn        = document.querySelector('#download_summary_button');
            this.$dataContainer     = $('#qw-data-container');
            this.$qwTable           = $('#qwtable');
            this.$qwTbody           = this.$qwTable.find('tbody');
            this.$qwTd              = this.$qwTbody.find('td');
            this.qwChart            = echarts.init(document.getElementById('main-chart'));
            this.progressBar        = document.querySelector('.progress-bar');
            Object.defineProperty(this, "progress", {
                get: () => {
                   return this.progressPrecent || 0;
                },
                set: (value) => {

                    if( value != this.progressPrecent ) {
                      this.progressPrecent = value;
                      // this.setQwChartProgress(value);
                      this.setProgressBarValue(value);
                      this.setProgressButton(value);
                    }
                }, 
                  configurable: true
            });
            this.qwChartProgress    = this.progress;
        },
        // Bind click events (or any events..)
        bindEvents: function() {

            var that = this;

            // On click "Show" BTN
            this.show.onclick = this.sendData.bind(this);

            // On Change inputs
            this.$form.change(function(){
                that.updateDatesInputs(this);
            });

            // downloadQw
            this.downloadBtn.onclick = this.downloadQw.bind(this);
        },
        downloadQw: function(e){
            e.preventDefault();

            var customer = "<?php echo $_SESSION['company_name']; ?>";
            var filename = customer + "qws_"+ this.start_date + "-" + this.end_date + ".zip";

            $.ajax({
                url: "/aaa/api/download_csv.php",
                method: "GET",
                dataType : "json",
                data: { 
                    customer: customer,
                    filename: filename
                },
                success:function(result){
                if(result.status){
                    window.location.href="/aaa/api/download_csv.php?customer="+customer+"&filename="+filename+"&download=1";
                }
            },
                error:function(){
                }
            })
        },
        setQwChartProgress: function(value){
            if (value != 0) {
                // Show Chart Loading 
                this.qwChart.showLoading({
                    color: (value == 99) ? '#00b0f0' : '#fff',
                    text: value + '%' 
                });
            }
        },
        setProgressButton: function(value){

            if ( value >= 100 || value == 0 ){
                this.show.value     = 'Show';
            }
            else {
                this.show.value     = value +'%';
                // this.show.disabled   = true;
                this.disableShow();
            }
        },
        resetShowButton: function(){
            this.show.value = 'Show';
            this.disableShow();
        },
        disableShow: function(){
            // this.show.style.color = "grey";
            // this.show.disabled   = true;
            this.show.classList.add("isDisabled");
        }, 
        enableShow: function(){
            // this.show.style.color = "#66aa66";
            // this.show.disabled   = false;
            this.show.classList.remove("isDisabled");
        },
        updateDatesInputs: function(){
            this.start_date     = this.$form[0][9].value;
            this.end_date       = this.$form[0][11].value;
            this.dateCount      = this.countDays(this.start_date,this.end_date);
            // this.show.disabled   = false;
            this.enableShow();
            this.removeError();
        },
        removeError: function(){
            if (this.errors) {
                this.errors.remove();
                delete this.errors;
            }
        },
        countDays: function(date1, date2){

            // First we split the values to arrays date1[0] is the year, [1] the month and [2] the day
            var date1 = date1.split('-');
            var date2 = date2.split('-');

            // Now we convert the array to a Date object, which has several helpful methods
            date1 = new Date(date1[0], date1[1], date1[2]);
            date2 = new Date(date2[0], date2[1], date2[2]);

            // We use the getTime() method and get the unixtime (in milliseconds, but we want seconds, therefore we divide it through 1000)
            var date1_unixtime = parseInt(date1.getTime() / 1000);
            var date2_unixtime = parseInt(date2.getTime() / 1000);

            // This is the calculated difference in seconds
            var timeDifference = date2_unixtime - date1_unixtime;

            // in Hours
            var timeDifferenceInHours = timeDifference / 60 / 60;

            // and finaly, in days :)
            var timeDifferenceInDays = timeDifferenceInHours  / 24;

            if (timeDifferenceInDays > 0){
                return timeDifferenceInDays;
            } else {
                // alert('Error: The date are invalid.');
            }
        },
        // Get data, prevent submit defaults and submit. 
        sendData: function(e) {
            e.preventDefault();

            if (this.show.classList.contains('isDisabled')) {

                this.showErrorDiv("Please select a new date range before submitting.");
            } else {

                let that                = this;
                let estimatedTotalTime  = ( (this.countUsers*this.customerMachines)/777 ) * 0.098; 
                let estimatedTime       = estimatedTotalTime/99;
                let estimatedTimeMs     = estimatedTime*1000;
                let timer               = setInterval( function(){that.incrementProgress(timer);}, estimatedTime); 

                console.log('Total Time: ' + estimatedTotalTime + 's');
                console.log('Estimated Time for 1%: ' + estimatedTime + 's');

                $.ajax({
                    type: 'POST',
                    url: "/manageit/ajax.php?module=qw_module",
                    dataType: 'json',
                    data: {
                            start_ts: that.start_date,
                            stop_ts: that.end_date, 
                            submitted: true, 
                            company_name: "<?php echo $_SESSION['company_name']; ?>"
                    },
                    beforeSend: function() {

                        // Show Chart Loading 
                        that.qwChart.showLoading({ 
                            color: '#00b0f0', 
                            // text: that.qwChartProgress
                            text: ''
                        });

                        // If data div isn't displayed
                        if (!that.dataDisplayed) {
                            // Show divs loading
                            that.showMainDiv();
                        } else {
                            that.$qwTbody.slideUp('fast');
                            that.$qwTbody.html('');
                        }
                    },
                    complete: function(){},
                    success: function(result){

                        // Reset show btn
                        that.resetShowButton();

                        // Clear timer
                        clearInterval(timer);

                        // Set progressbar to 100%
                        that.setProgressBarTo100();

                        // Show Download Button
                        that.downloadBtn.style.display = 'inline-block';

                        // Insert Chart Data
                        that.insertChartData(result);

                        // Insert Table Data
                        that.insertTableData(result);
                    }
                });

                that.dataDisplayed = true;
            }
        },
        showErrorDiv: function(errorTxt){

            if (!this.errors){
                this.errors             = document.createElement("div");
                this.errors.className   = "qw_errors_div";
                this.errors.textContent = errorTxt;
                this.$alistToolbar.append(this.errors);
            } 
        },
        // Insert Data to Table
        insertTableData: function(json){

            let str = '';
            let isOdd = ' rowspan="2" ';

            for ( let i=1; i<9; i++ ) {

                str += '<tr>';

                for (let j = 0; j < 8; j++) {

                    if ((i%2 === 0) && (j==0)){
                        // do nada
                    } else {
                        str += '<td '; 
                        str += ((i % 2 !== 0)&&(j==0)) ? isOdd : '';
                        str += '> '; 
                        str += json[i][j]; 
                        str += '</td>';
                    }
                }
                str += '</tr>'; 
            }

            this.$qwTbody.html(str);

            this.$qwTbody.slideDown('fast', function(){
                if ($(this).is(':visible'))
                    $(this).css('display','table-row-group');
            });

            // Apply colors on table.
            this.tableHover();
        },
        tableHover: function(){

            this.$qwTd              = this.$qwTbody.find('td');
            var that =  this;

            this.$qwTd.eq(0).hover( function(){
                that.$qwTd.eq(0).css('background-color', '#f5f5f5');
                that.$qwTd.eq(0).parent().css('background-color', '#f5f5f5');
                that.$qwTd.eq(0).parent().next().css('background-color', '#f5f5f5');    
            }, function(){
                that.$qwTd.eq(0).css('background-color', '');
                that.$qwTd.eq(0).parent().css('background-color', '');
                that.$qwTd.eq(0).parent().next().css('background-color', '');   
            });

            this.$qwTd.eq(15).hover( function(){
                that.$qwTd.eq(15).css('background-color', '#f5f5f5');
                that.$qwTd.eq(15).parent().css('background-color', '#f5f5f5');
                that.$qwTd.eq(15).parent().next().css('background-color', '#f5f5f5');   
            }, function(){
                that.$qwTd.eq(15).css('background-color', '');
                that.$qwTd.eq(15).parent().css('background-color', '');
                that.$qwTd.eq(15).parent().next().css('background-color', '');  
            });

            this.$qwTd.eq(30).hover( function(){
                that.$qwTd.eq(30).css('background-color', '#f5f5f5');
                that.$qwTd.eq(30).parent().css('background-color', '#f5f5f5');
                that.$qwTd.eq(30).parent().next().css('background-color', '#f5f5f5');   
            }, function(){
                that.$qwTd.eq(30).css('background-color', '');
                that.$qwTd.eq(30).parent().css('background-color', '');
                that.$qwTd.eq(30).parent().next().css('background-color', '');  
            });

            this.$qwTd.eq(45).hover( function(){
                that.$qwTd.eq(45).css('background-color', '#f5f5f5');
                that.$qwTd.eq(45).parent().css('background-color', '#f5f5f5');
                that.$qwTd.eq(45).parent().next().css('background-color', '#f5f5f5');   
            }, function(){
                that.$qwTd.eq(45).css('background-color', '');
                that.$qwTd.eq(45).parent().css('background-color', '');
                that.$qwTd.eq(45).parent().next().css('background-color', '');  
            });
        },
        incrementProgress: function(timer){

            if (this.progress == 99)
                clearInterval(timer);
            else 
                this.progress++;
        },
        // Insert Data to Chart
        insertChartData: function(json){

            var posList = [
                'left', 'right', 'top', 'bottom',
                'inside',
                'insideTop', 'insideLeft', 'insideRight', 'insideBottom',
                'insideTopLeft', 'insideTopRight', 'insideBottomLeft', 'insideBottomRight'
            ];

            this.qwChart.configParameters = {
                rotate: {
                    min: -90,
                    max: 90
                },
                align: {
                    options: {
                        left: 'left',
                        center: 'center',
                        right: 'right'
                    }
                },
                verticalAlign: {
                    options: {
                        top: 'top',
                        middle: 'middle',
                        bottom: 'bottom'
                    }
                },
                position: {
                    options: echarts.util.reduce(posList, function (map, pos) {
                        map[pos] = pos;
                        return map;
                    }, {})
                },
                distance: {
                    min: 0,
                    max: 100
                }
            };

            this.qwChart.config = {
                rotate: 90,
                align: 'left',
                verticalAlign: 'middle',
                position: 'insideBottom',
                distance: 15,
                onChange: function () {
                    var labelOption = {
                        normal: {
                            rotate: this.qwChart.config.rotate,
                            align: this.qwChart.config.align,
                            verticalAlign: this.qwChart.config.verticalAlign,
                            position: this.qwChart.config.position,
                            distance: this.qwChart.config.distance
                        }
                    };
                    this.qwChart.setOption({
                        series: [{
                            label: labelOption
                        }, {
                            label: labelOption
                        }, {
                            label: labelOption
                        }]
                    });
                }
            };

            var labelOption = {
                normal: {
                    show: true,
                    position: this.qwChart.config.position,
                    distance: this.qwChart.config.distance,
                    align: this.qwChart.config.align,
                    verticalAlign: this.qwChart.config.verticalAlign,
                    rotate: this.qwChart.config.rotate,
                    // formatter: '{c}  {name|{a}}',
                    formatter: '{name|{a}}',
                    fontSize: 16,
                    rich: {
                        name: {
                            // textBorderColor: '#fff', 
                            // color: '#333',
                            // color: '#717171',
                            color: '#525252',
                            shadowColor: 'transparent', 
                            shadowBlur: 0, 
                            textBorderColor: 'transparent',
                            textBorderWidth: 0, 
                            textShadowColor: 'transparent', 
                            textShadowBlur: 0
                        }
                    }
                }
            };

            option = {
                color: ['#007bff', '#00b0f0', 'red', '#e5323e'],
                tooltip: {
                    trigger: 'axis',
                    axisPointer: {
                        type: 'shadow'
                    }
                },
                legend: {
                    data: ['Inactives / Viewers', 'Inactives / Viewers / Less than 1min per day', 'Light no Macro'] 
                },
                toolbox: {
                    show: true,
                    orient: 'vertical',
                    left: 'right',
                    top: 'center',
                    feature: {
                        mark: {show: true},
                        // dataView: {show: true, readOnly: false},
                        // magicType: {show: true, type: ['line', 'bar', 'stack', 'tiled']},
                        restore: {show: true},
                        saveAsImage: {show: true}
                    }
                },
                calculable: true,
                xAxis: [
                    {
                        type: 'category',
                        axisTick: {show: false},
                        data: ['Excel', 'Word', 'PowerPoint', 'All 3 Apps']
                    }
                ],
                yAxis: [
                    {
                        type: 'value', 
                        name: 'Score'
                    }
                ],
                series: [
                    {
                        name: 'Light no Macro',
                        type: 'bar',
                        label: labelOption,
                        color: 'red',
                        data: [ [3, json[7][7]] ]
                    },
                    {
                        name: 'Inactives / Viewers',
                        type: 'bar',
                        barGap: 0,
                        label: labelOption,
                        data: [ json[1][7], json[3][7], json[5][7], json[8][7] ]
                    },
                    {
                        name: 'Inactives / Viewers / Less than 1min per day',
                        type: 'bar',
                        label: labelOption,
                        data: [ json[2][7], json[4][7], json[6][7] ]
                    }
                ]
            };

            // Set charts options
            this.qwChart.setOption(option);
            // Hide Loading
            this.qwChart.hideLoading();
        },
        // Show Main div on submition (only)
        showMainDiv: function(){
            // Show all contatner div
            this.$dataContainer.slideDown('slow');
        },
        // Sets a new value for the progress bar
        setProgressBarValue: function(value){

            this.progressBar.style.width = this.returnNumWithPrecent(value);
        },
        returnNumWithPrecent: function(num){

            return num.toString() + '%';
        },
        setProgressBarTo100: function(){
            var that = this;
            // Show Download Button
            this.progress = 100;
            setTimeout(function () {
                // Show Download Button
                that.progress = 0;
            }, 1000);
        }
    }
    // run object
    qwData.init();
})();

但我看到other examples在函数下编写功能而不是对象:

webApp = function (){ ... };

像例子:

var Background = (function() {
  'use strict';
  // placeholder for cached DOM elements
  var DOM = {};
  /* =================== private methods ================= */
  // cache DOM elements
  function cacheDom() {
    DOM.$background = $('#background');
  }

  // coordinate async assembly of image element and rendering
  function loadImage() {
    var baseUrl = 'https://source.unsplash.com/category',
        cat     = 'nature',
        size    = '1920x1080';
    buildElement(`${baseUrl}/${cat}/${size}`)
      .then(render);
  }

  // assemble the image element
  function buildElement(source) {
    var deferred = $.Deferred(function (task) {
      var image = new Image();
      image.onload = function () {
        task.resolve(image);
      };
      image.onerror = function () {
        task.reject();
      };
      image.src = source;
    });
    return deferred.promise();
  }

  // render DOM
  function render(image) { 
    DOM.$background
      .append(image)
      .css('opacity', 1);
  }

  /* =================== public methods ================== */
  // main init method
  function init() {
    cacheDom();
    loadImage();
  }

  /* =============== export public methods =============== */
  return {
    init: init
  };
}());

我有两个问题:

>使用一个对象和它内部设置函数,变量,等等有什么区别:

var webApp = {…};

和一个具有相同特征的函数变量(只有一个
    语法写得不同).就像我粘贴的链接中的示例一样.

var webApp = function (){ ... };

>在一个对象/函数中编写所有代码(如图,表,进度条等有些分离元素)的代码是否正确?这应该更好地分离到不同的对象?如果有更好的方法来编写此类代码,请提及我应该研究的内容.

解决方法:

互联网教程的一个问题是它们徘徊在相关点之外,很少有作者让它们保持最新. JS领域的事情发展得非常快,5年前的行业标准(例如jQuery)现在看起来很奇怪,当你仍然偶然发现它时.

所以,要实践我为了省略而唠叨别人的好习惯:

JavaScript模块状态,2018年中期,快速变化,#deprecated

一团糟.

首先你有ES 6模块. ES 6更名为ES 2015,模块部分被取出并制作成一个单独的规范,这意味着浏览器可能符合ES 2015标准,但仍然没有本机模块.然而,3年后,每个具有相关全球市场份额的浏览器(chrome,android chrome,firefox,iOS Safari)至少实现了原生模块系统的基本版本(Edge,Opera等).我不清楚,因为我相信规范允许路径更宽容(我们将在一分钟内回到那里),但这里是语法,相对或绝对文件路径,需要扩展:

import Foo from './foo.js'; // Import default export from foo.js, alias to 'Foo'
import { Foo } from './foo.js'; // Import named export 'Foo' from foo.js

export default function () {}; // exports a function as default, importer aliases
const Foo = class Foo {};
export Foo; // exports named class Foo

它们比其他任何东西都有很多优点(首先,你不需要特殊的工具或构建过程),但由于它们是最新的,它们还没有在JavaScript生态系统中得到广泛使用.因为他们很快就会来,人们有工作要做,他们实施了各种其他模块模式/工具/系统.最早的一个是你的问题中的一个,但是这个模式虽然总比没有好,但却有足够的问题让人们开始环顾四周.

AMD模块

另一个早期的产品是require.js的异步模块定义.虽然它具有一些引人注目的技术优势,但它实际上已经死了.

Common.js模块

node.js使用它自己的基于common.js模块的模块系统(基本上已成为common.js的事实风格)爆炸到了场景.人们开始说“嘿,能够在浏览器中做到这一点也很棒”,因此,浏览器化. Browserify是一个工具,它将遍历您的依赖图并将需求表达式转换为浏览器可以处理的内容(基本上,通过创建require函数). Node的模块有点不适合浏览器,但是在一个标准上的融合优于八千万个竞争性的adhoc实现.人们看着这三个竞争模块模式/系统(你的问题中的一个,AMD,common.js),并说我们可以统一这些.从而

通用模块定义

如果你看到野外的代码看起来像这样:

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node, CommonJS-like
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals (root is window)
        root.returnExports = factory(root.jQuery);
    }
}(this, function ($) {

那你看过UMD了.请注意它如何检查它所处的环境是为AMD还是common.js设置的.变形金刚被编写为将这两种样式转换为遗留代码和易读性问题(这是一个相当的样板).

但是人们想要更多:他们希望能够在代码中表达他们所有的webapp依赖关系(包括css和图像),并使用一个工具进行分片并有选择地加载它.此时,本机模块规范还在草案中,人们希望使用该语法.因此

Webpack模块

Webpack目前是当前使用的事实系统(虽然很多人仍然使用browserify). Webpack的模块语法如下所示:

import Foo from 'foo'; // imports default export from foo.js somewhere on PATH

这看起来很熟悉吗?非常相似(但与原生模块略有不同). Webpack还可以执行以下操作:

import 'Something.css'; // commonly seen in react apps
import 'logo.svg'; // ditto

这很方便,随着人们转向组件化系统,能够在该组件的入口点文件中表达所有组件依赖关系是很好的.不幸的是,HTML导入本来可以让你在没有构建步骤的情况下进行本地操作,这可能会导致死亡.

与本机模块系统的不兼容性,细微(路径和文件扩展名)和粗略(导入非js资产)是不幸的,这意味着一个或另一个将不得不改变,因为我试图编写本机模块 – 最近基于应用程序,并且很难使用库(几乎没有一个提供本机模块的味道).

使用什么是一种自以为是的问题,但如果您使用框架,请使用该框架的其他用户常用的任何内容. Common.js和webpack很常见,有很多工具可以消耗它们,这可能是你最好的选择.另一件要注意的是动态导入,已经在多个浏览器中登陆.

对不起,这一切都让人感到困惑,你恰好在过渡期间输入了JavaScript.

上一篇:如何在模块化应用程序中处理泛型类/接口?


下一篇:### 微信公众号生产环境运营的项目[培训机构的服务号项目]