仅执行一次代码的函数

时间:2013-12-03 16:57:17

标签: javascript function closures

我正在尝试编写一个函数,其中一部分只运行一次。到目前为止我已经完成了它的工作,但我理想的是它可以在不添加全局变量的情况下工作。我已经阅读了关于闭包但我要么不理解它们,要么我不能让我的实例工作。

请记住,这是我第一次尝试使用vanilla javascript而非jQuery的项目。所以没有jQuery的答案。

这是我的代码:

var videoLoaded = false;

function loadItem(element) {


    // If item is Video
    if( element.tagName == 'VIDEO' ) {

        if(videoLoaded != true) {

            // Load and play the video;
            element.setAttribute('preload', 'auto');
            element.play();
            videoLoaded = true;

            /* Push the dimensions through
             * to the videoFill function
             */
            element.addEventListener( 'loadedmetadata', function(e) {
                var dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
                videoFill(element, dimensions);
            });
        }

        dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
        videoFill(element, dimensions);

    }
}

感谢您的帮助!

5 个答案:

答案 0 :(得分:1)

首次通话后更换功能

function loadItem(element) {
    // Code        

    // replace function with dummy function
    // next time when it will be called, will do nothing
    loadItem = function() {
         dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
         videoFill(element, dimensions);
    };
}

答案 1 :(得分:1)

以下是如何使用闭包(在本例中为立即调用的函数表达式[IIFE])来防止创建全局变量:

var loadItem = (function() {  // This function will be immediately invoked
    var videoLoaded = false;  // This var only exists in our IIFE context, not global scope

    function loadItem(element) {

        if( element.tagName == 'VIDEO' ) {

            // loadItem() will still have access to videoLoaded even after the IIFE has completed and returned
            if(videoLoaded != true) {

                element.setAttribute('preload', 'auto');
                element.play();
                videoLoaded = true;

                element.addEventListener( 'loadedmetadata', function(e) {
                    var dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
                    videoFill(element, dimensions);
                });
            }

            dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
            videoFill(element, dimensions);

        }
    }

    return loadItem; // Return the function

}()); // Immediately invoke the IIFE closure

答案 2 :(得分:1)

使用像这样的帮手

var once = function (fn) {
  var ran = false;
  return function () {
    if (!ran) {
      ran = true;
      return fn.apply(null, arguments);
    }
  };
};

将您只希望运行一次的代码解压缩到函数

var runMeOnce = once(function (msg) {
    console.log(msg);
});


var doSomething = function () {
    setInterval(function () {
        runMeOnce("you will only see this once");
    }, 1000);
};

或者您可以采用OO方法并将其包装在类

var VideoLoader = function (element) {
    this.loaded = false;
    this.el = element;
};

VideoLoader.prototype.fill = function (dimensions) {
    // ?
};

VideoLoader.prototype.load = function () {

    var element = this.el,
        _this   = this;

    // If item is Video
    if( element.tagName == 'VIDEO' ) {

        if(this.loaded != true) {

            // Load and play the video;
            element.setAttribute('preload', 'auto');
            element.play();
            this.loaded = true;

            /* Push the dimensions through
             * to the videoFill function
             */
            element.addEventListener( 'loadedmetadata', function(e) {
                var dimensions = [
                    element.videoWidth,
                    element.videoHeight,
                    document.documentElement.clientWidth,
                    document.documentElement.clientHeight
                ];
                _this.fill(dimensions);
            });
        }

        dimensions = [
            element.videoWidth,
            element.videoHeight,
            document.documentElement.clientWidth,
            document.documentElement.clientHeight
        ];
        this.fill(dimensions);

    }
};

答案 3 :(得分:0)

使用函数的参数来存储全局(这样你不需要闭包):

var f = function(){if(!f.b)alert('x');f.b = true;}

以上功能会提醒" x"只有一次。

答案 4 :(得分:0)

videoLoaded不一定需要是全球性的。您可以使用模块模式:

var itemLoader = (function (videoFill) {
    'use strict';

    var videoLoaded = false;

    return {
        load: function (element) {
            var dimensions;

            if (element.tagName === 'VIDEO') {
                if (videoLoaded !== true) {
                    // Load and play the video;
                    element.setAttribute('preload', 'auto');
                    element.play();
                    videoLoaded = true;

                    /* Push the dimensions through
                     * to the videoFill function
                     */
                    element.addEventListener('loadedmetadata', function (e) {
                        var dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
                        videoFill(element, dimensions);
                    });
                }

                dimensions = [element.videoWidth, element.videoHeight, document.documentElement.clientWidth, document.documentElement.clientHeight]
                videoFill(element, dimensions);
            }
        }
    };
}(window.videoFill));

itemLoader.load(document.getElementById('your-video'));