占位以后写
主要是理解
1. 任何对象都可以用来作为hastable使用.
2. hashtable的key接受任何类型.
3. 但不意味着任何类型都可以作为key,事实上 hashtable的key的类型只有string型, 接受的其他类型最终会被转换为string.
![]() |
![]() |
占位以后写
主要是理解
1. 任何对象都可以用来作为hastable使用.
2. hashtable的key接受任何类型.
3. 但不意味着任何类型都可以作为key,事实上 hashtable的key的类型只有string型, 接受的其他类型最终会被转换为string.
以前很少写window间通讯的脚本,一直以为Global 变量的访问范围和var的一样。今天在写Triglav作弊工具的时候突然发现了个奇怪的问题,让我重新思考了Global变量的作用域,顺便复习一下var和this。
This的作用域:作用与当前实例,并且只能使用this关键字访问。比如 a = new Object,这时候a就是一个实例。那么当a下有一个方法,无论这个方法是实例化前就写好的,还是实例化后用a.foo= function(){}添加上去的,在这个方法里,this关键字都指向a。
Sample:
FooClass = function()
{
this.Variable = "This is a public variable.";
this.Say = function()
{
alert(this.Variable);
}
}
foo = new FooClass();
foo.Say();
foo.Say2 = function()
{
alert(this.Variable);
}
foo.Say2();
注:
1) 上面这个例子中可以把this.Variable替换一下试试看。
2) 另外,方法中的this指向(俗称“上下文”)是可以通过call, apply等方法改变,这点与下面的var不同。
Var的作用域:Var变量(下称私有变量)只作用于变量申明时的所在函数(updated 9/19/08) 的花括号 "{ }"以内。也就是说,它的作用域是依附与代码本身的,你的代码写在哪,作用域就在哪,而且在运行时是不可以改变的。
FooClass = function()
{
var Var = "This is a variable which defined by var.";
this.ThisVar = "This is a variable which defined by this.";
var self = this;
this.Say = function()
{
setTimeout(function()
{
alert(Var);
alert(typeof this.ThisVar);
alert(self.ThisVar);
}, 1000);
}
}
foo = new FooClass;
foo.Say();
大家可以在上面的例子中看到,无论有几层{}的嵌套var声明的变量始终可以穿越他们,并且被scope内的变量访问到。
同时,在这个例子里,我们可以看到setTimeout中function的this并不是foo,typeof this.ThisVar返回的是undefined,但是我们在这里利用了var的特性,耍了个花招(var self = this),让不同上下文的方法能够访问到同一个实例。
Global变量:global变量javascript中可以直接用“variable_name = variable_value”来声明,也可以用"this.variable_name=xx“或者"var variable_name=xx“来声明,后两者要求声明表达式必须在最外最顶层,而且第一种声明可以在代码中的任意位置。要理解Global的作用域,首先要知道javascript中,任何一个window其实都是一个实例,而所有的global变量,都是属于window这个实例的。
而我们当前代码的上下文,如果没有特殊指定,都是在window实例下。换句话说,你可以直接使用this.variable_name来访问一个global变量----但是,这又与我们平时的使用习惯不一样,我相信大多数的jser在书写代码的习惯都是直接使用variable_name。而这种不使用this关键字访问global变量的方法和访问var声明的变量很相似--确实,在javascript中global变量其实是有双重特性的,它既可以使用this访问,也可以不使用this。当你使用this访问时,会先确定当前的上下文,再找到上下文中的指定变量。而如果没有this,那么毫无疑问会访问到代码文本所属的window下的某个global变量。
现在来看这种情况:假设我们有两个页面,分别为win1和win2。win2是由win1打开的,所以我们可以拿到win2的window对象,而且他们是在同一个域名下,不存在跨域访问的问题。
这时候做这样一件事:在win1下想做一个小小的hack,把win2下的CallLocalVar函数修改一下,让win2的代码在调用CallLocalVar函数时,先调用帽子函数(这时帽子函数其实算在win2的实例下),再由帽子函数调用回win2下原来的CallLocalVar。
这时候会有很有趣的事情发生,因为帽子函数是用win2.CallLocalVar = function(){}定义的,所以他的上下文应当是win2,但是又由于代码本身是在win1下写的,那么当帽子函数中global变量的访问方法是用“通常习惯的方式(无this)”方式访问的, 那么帽子函数最后会访问回win1下的global变量。
请看下面的例子:
win1.htm里的内容:
<script>
local = "this is win1 global variable";
win2 = window.open("win2.htm","win2");
setTimeout(function()
{
local.test = win2.CallLocal;
win2.CallLocal = function()
{
this.alert(local);
if (local.test)
{
//local.test();
}
}
}, 4000);
</script>
win2.htm的内容:
<body>
<script>
local = "this is win2 global variable";
function CallLocal()
{
alert(local);
}
</script>
<button onclick="CallLocal()">Wait 4 sec and then click</button>
</body>
好了,最后有个终级问题:如果将win2.htm中的<button onclick="Call....</button>替换成setTimeout(CallLocal, 10000)会怎么样?
大牛们的相关讨论:http://bbs.51js.com/viewthread.php?tid=79018
http://www.jibbering.com/faq/faq_notes/closures.html
运行以下代码,会发现每次hello()出来的值都增加了——虽然他们是属于不同实例,
ProtoBase = function()
{
var i = 0;
this.Get = function()
{
alert(i.toString());
i++;
}
}
ProtoDerived = function()
{
this.Hello = function()
{
this.Get();
}
}
ProtoDerived.prototype = new ProtoBase();
pd1 = new ProtoDerived();
pd2 = new ProtoDerived();
pd1.Hello();
pd2.Hello();
这是为什么呢?其实很简单,var申明的变量的可访问域是在其所属的“{ }”以内的所有代码块。因此,当Get被调用时,他所访问的i就是离他最近用 var 申明的私有i——他们是相同的。
Here is rough sample of json request which was written while i was writting a tool for getting to do items from todoist, the requester in this sample can do a ordered request, block the 2nd request before 1st requst complete.
var bIdle = true;
function RequestAPI(sAPIUrl, iProjectID, sToken, sCallbackName, sAddtionalParameter)
{
var argus = arguments;
if (bIdle)
{
bIdle = false;
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = sAPIUrl + '?project_id=' + iProjectID.toString() + '&token=' + sToken + '&callback=' + sCallbackName + ((sAddtionalParameter!=null)?"&" + sAddtionalParameter:"");
console.innerHTML +=script.src + "<br />";
script.onreadystatechange = ReleaseAPIScript;
document.getElementsByTagName('head')[0].appendChild(script);
}
else
{
setTimeout(function ()
{
RequestAPI.apply(window, argus);
}, 1000);
}
}
function ReleaseAPIScript()
{
if (this.readyState.toLowerCase() == "loaded")
{
var elmtScript = this;
// Release script after 1 min
setTimeout(function(){
document.getElementsByTagName('head')[0].removeChild(elmtScript);
}, 1000);
bIdle = true;
}
}