this
this表示當前對象如果在全局作用范圍內使用this則指代當前頁面對象window 如果在函數中使用this則this指代什麼是根據運行時此函數在什麼對象上被調用 我們還可以使用apply和call兩個全局方法來改變函數中this的具體指向
先看一個在全局作用范圍內使用this的例子
代碼如下:
<script type=>
console
log( === window);
console
log(window
alert ===
alert);
console
log(
parseInt(
));
</script>
函數中的this是在運行時決定的而不是函數定義時如下
代碼如下:
foo() {
console
log(
fruit);
}
fruit = ;
foo();
pack = {
fruit:
foo: foo
};
pack
foo();
全局函數apply和call可以用來改變函數中this的指向如下
代碼如下:
foo() {
console
log(
fruit);
}
fruit = ;
pack = {
fruit:
};
foo
apply(window);
foo
apply(pack);
注apply和call兩個函數的作用相同唯一的區別是兩個函數的參數定義不同
因為在JavaScript中函數也是對象所以我們可以看到如下有趣的例子
代碼如下:
foo() {
( === window) {
console
log();
}
}
foo
boo = () {
( === foo) {
console
log();
} ( === window) {
console
log();
}
};
foo();
foo
boo();
foo
boo
apply(window);
prototype
prototype本質上還是一個JavaScript對象 並且每個函數都有一個默認的prototype屬性
如果這個函數被用在創建自定義對象的場景中我們稱這個函數為構造函數 比如下面一個簡單的場景
代碼如下:
Person(name) {
name = name;
}
Person
prototype = {
getName: () {
name;
}
}
zhang = Person();
console
log(zhang
getName());
作為類比我們考慮下JavaScript中的數據類型 字符串(String)數字(Number)數組(Array)對象(Object)日期(Date)等 我們有理由相信在JavaScript內部這些類型都是作為構造函數來實現的比如
Array() {
}
arr = Array( );
arr = [ ];
同時對數組操作的很多方法(比如concatjoinpush)應該也是在prototype屬性中定義的
實際上JavaScript所有的固有數據類型都具有只讀的prototype屬性(這是可以理解的因為如果修改了這些類型的prototype屬性則哪些預定義的方法就消失了) 但是我們可以向其中添加自己的擴展方法
Arrayprototypemin = () {
min = [];
( i = ; i < length; i++) {
([i] < min) {
min = [i];
}
}
min;
};
consolelog([ ]min());
注意這裡有一個陷阱向Array的原型中添加擴展方法後當使用forin循環數組時這個擴展方法也會被循環出來
下面的代碼說明這一點(假設已經向Array的原型中擴展了min方法)
arr = [ ];
total = ;
( i arr) {
total += parseInt(arr[i] );
}
consolelog(total);
解決方法也很簡單
arr = [ ];
total = ;
( i arr) {
(arrhasOwnProperty(i)) {
total += parseInt(arr[i] );
}
}
consolelog(total);
constructor
constructor始終指向創建當前對象的構造函數比如下面例子
代碼如下:
arr = [
];
console
log(arr
constructor === Array);
Foo = () { };
console
log(Foo
constructor === Function);
obj = Foo();
console
log(obj
constructor === Foo);
console
log(obj
constructor
constructor === Function);
但是當constructor遇到prototype時有趣的事情就發生了
我們知道每個函數都有一個默認的屬性prototype而這個prototype的constructor默認指向這個函數如下例所示
代碼如下:
Person(name) {
name = name;
};
Person
prototype
getName = () {
name;
};
p = Person();
console
log(p
constructor === Person);
console
log(Person
prototype
constructor === Person);
console
log(p
constructor
prototype
constructor === Person);
當時當我們重新定義函數的prototype時(注意和上例的區別這裡不是修改而是覆蓋) constructor的行為就有點奇怪了如下示例
代碼如下:
Person(name) {
name = name;
};
Person
prototype = {
getName: () {
name;
}
};
p = Person();
console
log(p
constructor === Person);
console
log(Person
prototype
constructor === Person);
console
log(p
constructor
prototype
constructor === Person);
為什麼呢?
原來是因為覆蓋Personprototype時等價於進行如下代碼操作
代碼如下:
Person
prototype = Object({
getName: () {
name;
}
});
而constructor始終指向創建自身的構造函數所以此時Personprototypeconstructor === Object即是
代碼如下:
Person(name) {
name = name;
};
Person
prototype = {
getName: () {
name;
}
};
p = Person();
console
log(p
constructor === Object);
console
log(Person
prototype
constructor === Object);
console
log(p
constructor
prototype
constructor === Object);
怎麼修正這種問題呢?方法也很簡單重新覆蓋Personprototypeconstructor即可
代碼如下:
Person(name) {
name = name;
};
Person
prototype = Object({
getName: () {
name;
}
});
Person
prototype
constructor = Person;
p = Person();
console
log(p
constructor === Person);
console
log(Person
prototype
constructor === Person);
console
log(p
constructor
prototype
constructor === Person);
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/20262.html