1. 程式人生 > >JavaScript函式基礎知識

JavaScript函式基礎知識

函式

函式的定義

函式可以通過關鍵字 function 來定義。實質上function 物件是 Function函式的例項化物件。

下面是定義的例子

function fn(args){ //關鍵字定義函式
    var vari = args;
    console.log(vari)
}
var fn = new Function( //通過建構函式 定義函式
'args',
'var vari = args;console.log(vari)'
)

函式的呼叫

函式的呼叫可以分為4種
1. 函式
2. 方法
3. 建構函式
4. call, apply 呼叫

函式呼叫

這裡只做簡單的例子說明,函式呼叫:

function a(){
    console.log(123)
}
a()// ===> 123

var some_var  = a() 
    some_var //===> 123

方法呼叫

一個方法 ,就是一個物件的屬性裡的 javascript函式。

var a = {} //JavaScript 物件
a.fn = function(){} // a物件的方法a
a.vari = 123; //a物件的屬性vari

方法呼叫其實和呼叫函式一樣,只不過我們呼叫的函式是物件裡面的一個屬性:

var example = function(){
    this.fn = function(){
        console.log('test')
    }
}
var obj = new exmaple();
obj.fn()// ===> test 

建構函式的呼叫

如果函式或者方法前面帶有關鍵字 new,她就構成了建構函式呼叫。建構函式呼叫和普通的函式呼叫在實參處理,呼叫上下文和返回值方面都有不同;

var o = new Object();
var o = new Object;

建構函式呼叫會建立一個新的空物件,這個物件繼承 繼承 建構函式的prototype屬性。

var con = function(){
    this.asd = 123;
}
con.prototype = {
    test:'this is con's prototype'
}
var c_obj  = new con();
    c_obj.test() // ====> 'this is con's prototype'

建構函式試圖初始化這個新建立的物件,並將這個物件做其呼叫上下文,因此建構函式可以使用this關鍵字來引用這個新物件。

間接呼叫

物件名稱 [型別]引數 預設 必填 [型別]返回 描述
call object,arg1, arg2, ,argN window / call(object,arg1,…argN)
apply [物件]object,[array][arg1, arg2, ,argN] window / / apply(object,arg1,…argN)
function a(){}
a.call();

函式屬性,方法,建構函式

這裡主要討論 prototype,call,apply,Function

函式的prototype

每一個函式包涵一個prototype屬性,這個屬性是指向一個物件的引用,這個物件稱為“原型物件”(prototype object)。當函式用作建構函式呼叫時,新建立的物件會從原型物件(__proto__)上面繼承屬性。

所以prototype是在描述,當function例項化以後需要繼承哪個物件的屬性,而且這個被繼承的屬性將被例項化物件中的屬性 __proto__引用。

就是說prototype是描述繼承關係,實質上物件繼承的繼承 靠 __proto__ 屬性來實現。
當然 prototype 是函式的屬性,而__proto__ 是物件的屬性

var animal= function(){
    this.eat = function(){
        console.lof('i can eat')
    }
}
var cat = function(){
    this.sleep = function(){
    console.log('i can sleep')
    }
}
cat.prototype = new animal()
var my_cat = new cat();

my_cat.eat() //  ===> i can eat
my_cat.sleep()  // ===> i can sleep

我們可以看看 my_cat 物件中的屬性:

這裡寫圖片描述

my_cat.prototype ==== > undefined
my_cat.\__proto__  ==== > animal 物件
my_cat.\__proto__.constructor == function animal ....   

注意:不要試圖修改例項化物件的 __proto__ 。
1. 並不是所有平臺都支援__proto__屬性,修改會帶來相容性問題;
2. 大部分平臺都會對原型物件的索引進行優化,修改會破壞原有的原型鏈,這會影響效能;
3. 原型物件是公用物件,修改該物件會影響其他繼承該物件的 物件
4. 替換物件這會影響整個繼承層次的結構

方法 call、apply

call&apply 這個兩個是 function的屬性,繼承Function.prototype;

這兩個屬性的效果一個,只是傳入引數不一樣。

這兩個方法常用於方法的複用,和物件繼承;

繼承

var animal = function(){
    this.eat = function(){
        console.log('eat')
    }
}

var cat = function(){
    animal.call(this) // animal.apply(this)
    this.sleep = function(){
        console.log('sleep')
    }

var cat_case = new cat();
cat_case.eat() // ===> eat
cat_case.sleep() // ===> sleep

複用

alert(Math.max(5,7,9,3,1,6));   //9   

//但是在很多情況下,我們需要找出陣列中最大的元素。   

var arr=[5,7,9,1];  
//alert(Math.max(arr));    // 這樣卻是不行的。NaN   

//要這樣寫   
function getMax(arr){  
    var arrLen=arr.length;  
    for(var i=0,ret=arr[0];i<arrLen;i++){  
        ret=Math.max(ret,arr[i]);  
    }  
    return ret;  
}  

alert(getMax(arr)); //9   

//換用apply,可以這樣寫   
function getMax2(arr){  
    return Math.max.apply(null,arr);  
}  

alert(getMax2(arr)); //9   

//兩段程式碼達到了同樣的目的,但是getMax2卻優雅,高效,簡潔得多。   

bind方法

這裡的bind 方法討論ES3 相容。從名字就能看出,這個方法主要作用就是將函式繫結至某個物件。當函式f()上呼叫bind()方法並傳入一個物件o座位引數,這個方法將返回一個新的函式。呼叫新的函式將會把原始的函式f( )當做o的方法來呼叫。傳入新函式的任何實參都將傳入原始函式,如:

function f(y){
    return this.x + y
}
var o = {x:1}
var g = f.bind(o);
g(2) // ==> 3

bind除了繫結一個函式至物件上,他還附帶一些其他應用:除了第一個實參以外,傳入bind的實參都會繫結至this,這個附帶的應用是一種比常見的程式設計技術,有時也被稱為‘柯里化’。下列例子就是柯里化的例子

var sum = function(x,y){return x + y} 

var succ = sum.bind(null,1);
succ(2) // ==> 3

function f(y,z){return this.x + y + z }
var g = f.bind({x:1},2)
g(3) // ⇒ 6 

Function 建構函式

本文開頭說過,function是Function的例項化物件,也就是說,我們可以通過 new 關鍵字來 例項化一個函式:

var f = new Function('x','y','return x+ y')

這幾乎等價於

var f = function(x,y){ return x + y }

不建議使用這種方式 定義函式

參考:
《JavaScript權威指南》 作者:David Flanagan
《Effective JavaScript》 作者: David Herman