1 js静态属性和实例属性javascript
原型属性在实例化以后做为类的实例属性。可是实例属性在实例化以后却不能做为原型属性。html
[javascript] view plaincopyjava
<html> ruby
<head> 闭包
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 函数
<title>测试</title> 测试
</head> ui
<body> this
<mce:script type="text/javascript"><!-- google
function Man(name, age) {
//定义实例属性
this.name = name;
this.age = age;
}
//定义静态属性。默认性别是男,不排除变性,^v^
Man.sex = '男';
//定义原型属性
Man.prototype.phone = '123456';
//除了name.sex和Man.prototype.phone其他所有是Undefined
alert(Man.sex + "-----" + Man.prototype.phone + "--" + Man.name + "--" + Man.age + "--" + Man.phone);
var man = new Man("Tom", 24);
alert(Man.sex + "--" + man.name + "--" + man.age + "--" + man.phone);
/**
* 经过例子说明:原型属性在实例化以后做为类的实例属性。
* 可是实例属性在实例化以后却不能做为原型属性。
*/
// --></mce:script>
</body>
</html>
2
不太会写堂而皇之的开场白,直接进入主题。
咱们看一道题,出处为javaeye的某贴——这世界就是这样,有些人喜欢制造问题,有人喜欢解决问题。制造问题的人为解决问题的人带来就业机会……
var
a=100;
var
b=
true
;
function
test(){
alert(a);
alert(b);
b=
false
;
alert(b);
var
a=200;
alert(a/2);
alert(++Math.PI);
alert(Math.PI++);
}
test();
|
运行代码
为何第一个alert为undefined,而第二个为true。这问题也能够延伸为——alert(b)时怎么就会找外部的b,而alert(a)时就不会往外面找?!
咱们都明白局部变量的优先级大于全局变量,或者说内围做用域的变量的优先级比外围的高。当JS引擎在当前做用域找不到此变量时,它就往外围的做用域找。不过,在这以前,有一个严肃的问题是,究竟当前做用域存不存在这个变量。像javascript这样的解释型语言,基本分为两个阶段,编译期(下面为符合大多数语言的称呼习惯,改叫预编译)与运行期。在预编译阶段,它是用函数来划分做用域,而后逐层为其以 var 声明的变量(下略称为var变量)与函数定义开辟内存空间,再而后对var变量进行特殊处理,通通赋初始值为undefined,以下图:
由上图,咱们即可以推知,当前网页拥有两个a,一个b,一个test函数。若是在运行期用到除此之外的东东,如c函数或d变量啦,就会报未定义错误(用eval等非正常手段生成变量与函数的状况除外),此外,它们最多出现未赋值警告。
javascript的运行期是在为var变量与函数定义分配空间后当即执行,而且是逐行往下执行的。
第1行它为外围做用域的a赋值为100
第2行它为外围做用域的b赋值为true
第3行进行test的做用域,咱们简称为内围做用域。
第4行就当即调用内围做用域的a,这时它尚未来得及赋值呢!不过它已经声明过了,所以默认为其赋值为undefined(在预编译阶段,见图),因而alert为undefined
第5行就调用b时,JS引擎就拿起我画的图看了(笑),发现test的做用域内没有b,眼睛往外望,发现b了,而b在第二行就赋值为true,因而alert为true。
第6行为一个赋值操做,把外围的b变量改赋为false。因而到第7行时,alert为false。如下说法不说了。
做为对比,咱们改写一下例子:
var
a=100;
var
b=
true
;
function
test(){
alert(a);
alert(b);
var
b=
false
;
alert(b);
var
a=200;
alert(a/2);
alert(++Math.PI);
alert(Math.PI++);
}
test();
|
这时在test函数的做用域内,b也被声明了。
掌握预编译为var变量与函数定义分配空间这一事实后,许多问题就迎刃而解。咱们看犀牛书上的一个例子。
var
scope =
"global"
;
function
f() {
alert(scope);
var
scope =
"local"
;
alert(scope);
}
f();
|
答案呼之欲出!
咱们来看更复杂的例子。
Object.prototype.test =
'wrong'
;
var
test =
'right'
;
(
function
f() {
alert(test);
})();
|
这个问题的难点在于,运行期时,又生成一同名变量,它是附着于Object.prototype,究竟哪个距离F()的做用域近一些呢?!测试结果是var test。因而咱们有了下图:
因而咱们明白了,原来定义在函数外面的var变量并不位于window做用域的下一层。
咱们继续加深难度。
(
function
f() {
alert(test);
})();
Object.prototype.test =
'ccc'
;
Object.test =
"bbb"
window.test =
"aaa"
;
|
报未定义错误,由于预编译期时没有符合要求的var变量,而在运行期时,和它同名的变量在调用时(第2行)也还没有创建起来!
若是这样呢?!
Object.test =
"bbb"
;
Object.prototype.test =
'ccc'
;
window.test =
"aaa"
;
(
function
f() {
alert(test);
})();
|
估计有不少人猜是bbb,实际上是ccc!有人就不解了,不是对象的属性的优先级比其原型属性的优先级高吗???
无错,的确如此,不过对象的属性是这样定义的:
var
o = {test:
"eee"
}
|
Object.test = “XXX”这样定义,为类属性,或称静态属性。类属性优先级都是比实例属性低的
经过这图也教育咱们,必定要用局部变量啊,要不,一层层往上爬,效率是多么低啊。另外,这图也告诉咱们,window是一个多么高级的存在啊(微软最爱听),Object都比它低一等,更别提什么继承问题啦!(在FF与IE中)
//颠覆常识的存在
alert(window
instanceof
Object);
|
运行代码
搞定这个咱们看最难的一题。类属性,实例属性,原型属性,极晚绑定的属性都考到了!不过实例属性与类属性已超出本文的讨论范围,恕不讨论了。这些也不太难,很容易google到的,本身google吧。
function
foo(){
foo.abc =
function
(){alert(
'def'
)}
this
.abc =
function
(){alert(
'xyz'
)}
abc =
function
(){alert(
'@@@@@'
)};
var
abc =
function
(){alert(
'$$$$$$'
)}
}
foo.prototype.abc =
function
(){alert(
'456'
);}
foo.abc =
function
(){alert(
'123'
);}
var
f =
new
foo();
f.abc();
foo.abc();
abc();
|
蓝色理想的人说这题出得很差,有错。我说,有错才好,这样才能考出水平!十秒内作出正确答案,说明学会了。
答案:
运行代码
最后概括一下,JS引擎有两个设置变量的机会。第一次在预编译时期,全部var变量会分配到各自的做用域中,值一概为undefined。第二次在运行期,因为是逐行执行,所以是可变的。咱们能够经过eval与Function动态生成新的变量,它们的做用域都是可制定的,其余赋值语句,只是把变量固定于顶层做用域(window)中,或是仅仅是从新赋值。咱们也能够用delete来删除对象的属性,迫使其往外走同名变量。with闭包会在其引用的对象的属性被删除后,在闭包的外围寻找与此属性同名的变量。