JavaScript 范围和全局变量

javascript scope and global variables

本文关键字:全局变量 范围 JavaScript      更新时间:2023-09-26

我在对象中使用函数时尽量避免使用全局变量。我想调用其他函数中的函数并使用第一个函数范围内的变量。例如:

var showForecast = {
  'init': function () {
    this.getData();
  },
  'buildView': function(){
    var code = "Hey, you're from " + this.data.city;
    $('body').append(code);
  },
  'getData': function () {
    $.getJSON('http://ipinfo.io/', function (data) {
      console.log(data);
      showForecast.buildView();
    })
  }
}

显然它不起作用。我想在buildView内部使用data,而不会使data成为全局变量。我认为使用 this 是正确的做法,因为我从定义data的函数调用buildView。如何实现这一点?谢谢。

您可以传递以下信息:

var showForecast = {
'init': function () {
    this.getData();
},
'buildView': function(data){
    var code = 'Hey, you''re from ' + data.city;
    $('body').append(code);
},
'getData': function () {
    $.getJSON('http://ipinfo.io/', function (data) {
        console.log(data);
        showForecast.buildView(data);
    })
}
}

无法访问数据变量本身。它在本地作用域为您传递给getJSON的匿名函数(并且getJSON将其作为参数传递,这超出了您的控制范围(。

您必须将值复制到某处。

在您的特定示例中,除了全局作用域之外,getDatabuildView之间没有共享的作用域。因此,如果您想通过作用域传递值,那么全局是您自己的(糟糕的(选项。

您可以简单地将其作为参数传递:

showForecast.buildView(data);

或者,您可以将其存储为属性:

showForecast.myData = data;

我喜欢Vinny的回答。

一种回合的方法是用它制作一个模块:

var showForecast = function(){
    var data;
    var init = function () {
        this.getData();
    };
    var buildView = function(){
        var code = 'Hey, you''re from ' + this.data.city;
        $('body').append(code);
    };
    var getData = function () {
        $.getJSON('http://ipinfo.io/', function (data) {
            console.log(data);
            this.data = data;
            showForecast.buildView();
        })
    };
    return {
        'init': init,
        'buildView': buildView,
        'getData': getData
    };
}();

这样,var data的范围仅限于函数。它就像一个私有变量。

当您试图避免全局时,您应该考虑使用命名空间。在Javascript中没有所谓的命名空间。但是您可以使用此处提到的小型实用程序方法来定义自己。

http://www.zachleat.com/web/namespacing-outside-of-the-yahoo-namespace/

一种帮助创建自定义命名空间的实用工具方法。

jQuery.namespace = function() {
    var a=arguments, o=null, i, j, d;
    for (i=0; i<a.length; i=i+1) {
        d=a[i].split(".");
        o=window;
        for (j=0; j<d.length; j=j+1) {
            o[d[j]]=o[d[j]] || {};
            o=o[d[j]];
        }
    }
    return o;
};

定义命名空间

jQuery.namespace( 'jQuery.showForecast' );    

使用揭示模块模式定义方法

https://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript

 jQuery.showForecast = (function() {
  var data;
  var init = function() { 
    getData();
  }
  var buildView = function() {
    var code = "Hey, you're from " + data.city;
    $('body').append(code);
  }
  var getData = function() {        
    $.getJSON('http://ipinfo.io/', function(_data) {
      console.log(data);
      data = _data;
      buildView();
    })
  }
  return {
    init: init
  };
})(); // Execute it immediately

用法:

您只能访问 init 方法,因为它暴露在外部。

jQuery.showForecast.init()

定义另一个命名空间

jQuery.namespace( 'jQuery.showForecast.extended' );
jQuery.showForecast.extended = {
// Define some more
};