函數是JavaScript最有趣的部分之一,它可以是最簡單的函數,也可以是最複雜的函數。一些額外的功能還可以通過閉包來實現。由於函數也是對象,所以通過函數指針來操作函數是最非常簡單的,以下是幾種函數使用的高級技巧。
安全的類型檢測
var arr = ["1", "2", "hello"];
console.log(arr instanceof Array); //true
以上代碼要想返回true,value必須是一個數組,並且與Array構造函數在同一個全局作用域下。如果value是在另一個frame中定義的,那麼以上代碼會返回false。 var arr = ["red", "hello", 1, 2, true];
console.log(Object.prototype.toString.call(arr)); //[object Array]
用這個方法檢測arr,返回一個"[object Array]",說明該變量屬於原生數組對象。 //該函數用於檢測某變量是否是原生數組對象
function isArray (value) {
return (Object.prototype.toString.call(value));
}
var arr = ["red", "hello", 1, 2, true];
console.log(isArray(arr)); //[object Array]
同理,也可以創建一個函數用於檢測某函數是原生對象還是自定義對象。
//該函數用於檢測某變量是否是原生函數
function isFunction (value) {
return (Object.prototype.toString.call(value));
}
var func = function () {alert("hi");};
console.log(isFunction(func)); //[object Function]
也可以創建一個函數用於檢測某正則表達式是否是原生正則表達式。
//該函數用於檢測某正則表達式是否是原生正則表達式
function isRegExp (value) {
return (Object.prototype.toString.call(value));
}
var parent = /.a/gi;
console.log(isRegExp(parent)); //[object RegExp]
//該函數用於檢測某對象是否是原生對象
function isObject (value) {
return (Object.prototype.toString.call(value));
}
var obj = {naem: "tom", age: 21}
console.log(isObject(obj)); //[object Object] 非原生對象
檢測JSON對象:
//該函數用於檢測某對象是否是原生對象
function isObject (value) {
return (Object.prototype.toString.call(value));
}
var isJSON = window.JSON;
var json = Object.prototype.toString.call(JSON);
console.log(isObject(isJSON)); //[object JSON]
console.log(isObject(json)); //[object String]
在WEB開發中區分原生對象與非原生對象是非常重要的。
作用域安全的構造函數
function Person (name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
console.log(this.name);
};
}
//使用new實例化一個對象
var person1 = new Person("Tom", 21, "WEB前端");
function Person (name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function () { console.log(this.name); }; } //使用new實例化一個對象 var person1 = new Person("Tom", 21, "WEB前端");
console.log(person1.age); //21person1.sayName(); //Tom
Person構造函數使用this對象給三個屬性賦值:name、age和job。當使用new創建新對象時,this對象就會指向這個新對象,同時給它分配這個三個屬性。
function Person (name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
console.log(this.name);
};
}
//使用new實例化一個對象
var person1 = new Person("Tom", 21, "WEB前端");
console.log(person1.age); //21
person1.sayName(); //Tom
//不使用new關鍵字,直接調用Person(),將屬性添加到了window對象上
var person2 = Person("Bob", 22, "Doctor");
console.log(window.name); //Bob
console.log(window.age); //22
window.sayName(); //Bob
原本是給person實例的三個屬性被添加到了window對象上,沒有使用new操作符,這裏的構造函數是作爲普通函數調用的,即"var person = Person()"就相當於“Person()”,this對象晚綁定,解析器將this對象解析爲window對象了。原來的window的name屬性量用於標識鏈接目標和frme的,這裏name屬性將覆蓋window對象原來的屬性,因爲所導致其它錯誤。
function Person (name, age, job) {
//首先檢測this對象是否爲正確類型的實例,即是否爲Person類型的實例。
if (this instanceof Person) { //現有的實例環境中,判斷this是否指向Person
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
console.log(this.name); //返回一個新的實例(那麼以上賦值操作就沒有執行)
};
} else {
return new Person(name, age, job); //如果檢測出this不是正確類型的實例則創建實例並返回
}
}
//首先使用new操作符創建新實例
var person1 = new Person("Tom", 21, "WEB前端");
console.log(person1.age); //21
person1.sayName(); //Tom
//接着不使用new,直接調用Person()作爲普通函數。
var person2 = Person("Bob", 22, "Doctor");
console.log(person2.name); //Bob
console.log(person2.age); //22
person2.sayName(); //Bob
構造函數竊取模式的繼承
function Person (sides) {
//首先檢測this對象是否爲Person的實例。
if (this instanceof Person) { 判斷this是否指向Person
this.sides = sides;
this.getArea = function () {
return 0;
};
} else {
return new Person(sides); //如果檢測出this不是正確類型的實例則創建實例並返回
}
}
function Rec (w, h) {
Person.call(this, 2); //想借用構造函數模式來繼承Person的屬性和方法
this.w = w;
this.h = h;
this.getArea = function () {
return this.w * this.h;
};
}
var rec = new Rec(10, 10);
console.log(rec.sides); //undefined
構造函數竊取模式結合原型鏈實現繼承
function Person (sides) {
//首先檢測this對象是否爲正確類型的實例,即是否爲Person類型的實例。
if (this instanceof Person) {
this.sides = sides;
this.getArea = function () {
return 0;
};
} else {
return new Person(sides); //如果檢測出this不是Person的實例,則創建實例並返回
}
}
function Rec (w, h) {
Person.call(this, 2); //借用構造函數模式繼承
this.w = w;
this.h = h;
this.getArea = function () {
return this.w * this.h;
};
}
Rec.prototype = new Person(); //原型鏈實現繼承:原型對象等於另一個對象的實例。
var rec = new Rec(10, 10);
console.log(rec.sides); //2 sides的值
通過原型鏈繼承,使Rec的實例也變成Person的實例,“Person.call(this. 2)“會按原意執行,最終爲Rec添加了sides屬性,這樣Rec的實例也就繼承了Person的屬性sides。