函數有普通函數和構造函數。在<script>標簽中寫下
function Person(name,age) {
this.name = name;
this.age = age;
this.eat = function () {
console.log(this.name + '在吃');
}
}
var p = new Person('jack',22);
p.eat(); // jack在吃
Person.isman = true;
console.log(p.__proto__ == Person.prototype); // true
console.log(Person.prototype.constructor == Person); // true
console.log(Person.__proto__ == Function.prototype); // true
console.log(typeof Person); // function
console.log(Person instanceof Object); // true
console.log(Person.isman); // true
如上是個構造函數,通常用大寫字母開頭。由上面輸出結果可知:
1、對象是通過new一個函數生成的
2、函數本身又是一個普通對象,可以存儲屬性等
3、對象的proto屬性指向構造函數原型鏈
4、構造函數的原型鏈中的constructor屬性指向構造函數自身
5、函數作為一個對象來看,他的proto屬性指向函數自身對象的生成函數Function的原型鏈
函數內部的this指針問題:
當函數作為構造函數,new函數生成對象時,this指針指向對象本身。若函數作為一個普通函數調用,比如
Person('jack',22)
這時this指向函數調用時的上下文環境,在這里指向window。
在js中,除了全局作用域和異常處理catch,就只有函數能形成獨立的作用域環境,作用域是用來隔離變量的。舉個經典例子。
var data = [];
for (var i = 0; i < 3; i++) {
data[i] = function () {
console.log(i);
}
}
data[0](); // 3
data[1](); // 3
data[2](); // 3
原因很簡單,是因為var的變量提升,i作為全局變量在for循環結束后變為了3。可以采用如下方法解決
var data = [];
for (var i = 0; i < 3; i++) {
data[i] = (function (j) {
// 參數j相當于 var j = i;
return function () {
console.log(j);
}
})(i)
}
data[0](); // 0
data[1](); // 1
data[2](); // 2
data[I]保存的是一個立刻執行的函數,該函數具有獨立的作用域,內部變量j保存了定義時接受的參數i,這樣,全局變量i的變化與j無關,輸出結果為j的值。
函數的生命周期問題。
在全局作用域代碼運行之初預編譯階段就會先聲明所有的函數,并在真正運行時利用new Function創建該函數對象保存到全局作用域并執行,執行時開辟內存空間形成該函數的獨立作用域,在里面聲明變量等,函數執行完畢作用域釋放。但是對閉包(一般是函數嵌套),如
function f1() {
var a = 10;
return function () {
console.log(a);
}
}
var f2 = f1(); // f1執行完畢
f2();
當函數f1執行完畢時候,因為f1函數返回值是一個函數,而該函數內部引用到了f1作用域內的值a,所以f1執行完畢后該作用域不能釋放,會被保留,直到f2執行完畢,f2變量銷毀f1的作用域才會釋放。也就是說閉包會延長函數作用域的生命周期。