我不确定如何标题这个问题,但我正在使用带有构造函数的揭示模块模式,并注意到一些使我感到困惑的行为。这段代码的实际目的与我的问题无关,我只是想了解我看到的这种行为。
以下是我遇到的问题代码:
var ajaxModule = (function() {
//private
var data,callBack,type,dataType,url,
//public
constructor;
constructor = function(callBack,data,type,dataType,url) {
//Required
callBack = callBack || null;
data = data || null;
//Defaults
type = type || 'POST';
dataType = dataType || 'json';
url = url || 'DBConnect.php';
};
//methods
function setAjaxQuery() {
log('in setAjaxQuery')
dir(callBack);
dir(data);
dir(type);
dir(dataType);
dir(url);
};
constructor.prototype = {
constructor: ajaxModule,
setAjaxQuery: setAjaxQuery,
};
return constructor;
}());
现在称之为:
var ajax = new ajaxModule('someObject','someData');
ajax.setAjaxQuery();
现在这样做我看到setAjaxQuery函数中所有这些console.dir()命令都未定义。
我发现问题是参数名称与局部变量相同。我通过这样的方式解决了这个问题:
constructor = function(zcallBack,zdata,ztype,zdataType,zurl) {
//Required
callBack = zcallBack || null;
data = zdata || null;
//Defaults
type = ztype || 'POST';
dataType = zdataType || 'json';
url = zurl || 'DBConnect.php';
}
我的问题是为什么会发生这种情况?当名称相同时,javascript正在做什么导致这个问题?
答案 0 :(得分:1)
添加参数时,它们会为您提供的名称保留本地范围。由于外部作用域具有您尝试访问的那些名称的版本,因此无法重用这些名称,否则碰撞将导致仅使用本地作用域。由于第二个调用函数只能访问外部作用域,因此无法检索内部作用域中设置的值。
词汇范围可能会变得奇怪,但让我们考虑一个例子:
function x(){
var a = 5; // scoped to x
var b = 10; // scoped to x
function c() {
var a = 10; // scoped to c, this is equivalent to having an argument named a
return a + b; // b is scoped to x
}
return c; // scoped to x
}
我对这些案例的建议是使用参数化来解决问题:
var ajaxModule = (function() {
//private
var inner = {
data: null,
callBack: null,
type: 'POST',
dataType: 'json',
url: 'DBConnect.php'
},
//public
constructor;
constructor = function(callBack,data,type,dataType,url) {
//Required
inner.callBack = callBack || null;
inner.data = data || null;
//Defaults
inner.type = type || 'POST';
inner.dataType = dataType || 'json';
inner.url = url || 'DBConnect.php';
};
//methods
function setAjaxQuery() {
log('in setAjaxQuery')
dir(inner.callBack);
dir(inner.data);
dir(inner.type);
dir(inner.dataType);
dir(inner.url);
};
constructor.prototype = {
constructor: ajaxModule,
setAjaxQuery: setAjaxQuery,
};
return constructor;
}());
通过这种方式,您可以同时保持命名约定并通过(内部)明确声明范围。
答案 1 :(得分:1)
构造函数创建范围。构造函数中的参数定义该范围内的局部变量。因此,当您为变量赋值" callback"时,它引用构造函数范围中的变量,而不是父范围中的变量。
setAjaxQuery方法定义了它自己的范围。在此范围内,当您访问"回调"时,它引用父范围中的变量,该变量未被触及且未定义。
function(){
var abc = null;//scope outer
function A(abc){
abc = "something";
//abc here refers to the variable in the local scope i.e. parameter of function A.
//abc variable in outer scope is still null.
}
function B(){
console.log( abc );
//abc here refers to the variable in the outer scope which was never changed.
}
}