標籤:包含 回調 ict 最大 參考 屬性工作表 全域對象 rom return
前面的話
函數是javascript中特殊的對象,可以擁有屬性和方法,就像普通的對象擁有屬性和方法一樣。甚至可以用Function()建構函式來建立新的函數對象。本文是深入理解javascript函數系列第三篇——屬性和方法
屬性
【length屬性】
函數系列第二篇中介紹過,arguments對象的length屬性工作表示實參個數,而函數的length屬性則表示形參個數
function add(x,y){ console.log(arguments.length)//3 console.log(add.length);//2}add(1,2,3);
【name屬性】
函數定義了一個非標準的name屬性,通過這個屬性可以訪問到給定函數指定的名字,這個屬性的值永遠等於跟在function關鍵字後面的標識符,匿名函數的name屬性為空白
//IE11-瀏覽器無效,均輸出undefined//chrome在處理匿名函數的name屬性時有問題,會顯示函數運算式的名字function fn(){};console.log(fn.name);//‘fn‘var fn = function(){};console.log(fn.name);//‘‘,在chrome瀏覽器中會顯示‘fn‘var fn = function abc(){};console.log(fn.name);//‘abc‘
[注意]name屬性早就被瀏覽器廣泛支援,但是直到ES6才將其寫入了標準
ES6對這個屬性的行為做出了一些修改。如果將一個匿名函數賦值給一個變數,ES5的name屬性,會返回Null 字元串,而ES6的name屬性會返回實際的函數名
var func1 = function () {};func1.name //ES5: ""func1.name //ES6: "func1"
如果將一個具名函數賦值給一個變數,則ES5和ES6的name屬性都返回這個具名函數原本的名字
var bar = function baz() {};bar.name //ES5: "baz"bar.name //ES6: "baz"
Function建構函式返回的函數執行個體,name屬性的值為“anonymous”
(new Function).name // "anonymous"
bind返回的函數,name屬性值會加上“bound ”首碼
function foo() {};foo.bind({}).name // "bound foo"(function(){}).bind({}).name // "bound "
【prototype屬性】
每一個函數都有一個prototype屬性,這個屬性指向一個對象的引用,這個對象稱做原型對象(prototype object)。每一個函數都包含不同的原型對象。將函數用做建構函式時,新建立的對象會從原型對象上繼承屬性
function fn(){};var obj = new fn;fn.prototype.a = 1;console.log(obj.a);//1
方法
【apply()和call()】
每個函數都包含兩個非繼承而來的方法:apply()和call()。這兩個方法的用途都是在特定的範圍中調用函數,實際上等於函數體內this對象的值
要想以對象o的方法來調用函數f(),可以這樣使用call()和apply()
f.call(o);f.apply(o);
假設o中不存在m方法,則等價於:
o.m = f; //將f儲存為o的臨時方法o.m(); //調用它,不傳入參數delete o.m; //將臨時方法刪除
下面是一個實際的例子
window.color = "red";var o = {color: "blue"};function sayColor(){ console.log(this.color);}sayColor(); //redsayColor.call(this); //redsayColor.call(window); //redsayColor.call(o); //blue
//sayColor.call(o)等價於:o.sayColor = sayColor;o.sayColor(); //bluedelete o.sayColor;
apply()方法接收兩個參數:一個是在其中運行函數的範圍(或者可以說成是要調用函數的母對象,它是調用上下文,在函數體內通過this來獲得對它的引用),另一個是參數數組。其中,第二個參數可以是Array的執行個體,也可以是arguments對象
function sum(num1, num2){ return num1 + num2;}//因為運行函數的範圍是全域範圍,所以this代表的是window對象function callSum1(num1, num2){ return sum.apply(this, arguments);}function callSum2(num1, num2){ return sum.apply(this, [num1, num2]);}console.log(callSum1(10,10));//20console.log(callSum2(10,10));//20
call()方法與apply()方法的作用相同,它們的區別僅僅在於接收參數的方式不同。對於call()方法而言,第一個參數是this值沒有變化,變化的是其餘參數都直接傳遞給函數。換句話說,在使用call()方法時,傳遞給函數的參數必須逐個列舉出來
function sum(num1, num2){ return num1 + num2;}function callSum(num1, num2){ return sum.call(this, num1, num2);}console.log(callSum(10,10)); //20
至於是使用apply()還是call(),完全取決於採取哪種函數傳遞參數的方式最方便。如果打算直接傳入arguments對象,或者包含函數中先接收到的也是一個數組,那麼使用apply()肯定更方便;否則,選擇call()可能更合適
在非strict 模式下,使用函數的call()或apply()方法時,null或undefined值會被轉換為全域對象。而在strict 模式下,函數的this值始終是指定的值
var color = ‘red‘;function displayColor(){ console.log(this.color);}displayColor.call(null);//red
var color = ‘red‘;function displayColor(){ ‘use strict‘; console.log(this.color);}displayColor.call(null);//TypeError: Cannot read property ‘color‘ of null
應用
【1】調用對象的原生方法
var obj = {};obj.hasOwnProperty(‘toString‘);// falseobj.hasOwnProperty = function (){ return true;};obj.hasOwnProperty(‘toString‘);// trueObject.prototype.hasOwnProperty.call(obj, ‘toString‘);// false
【2】找出數組最大元素
javascript不提供找出數組最大元素的函數。結合使用apply方法和Math.max方法,就可以返回數組的最大元素
var a = [10, 2, 4, 15, 9];Math.max.apply(null, a);//15
【3】將類數組對象轉換成真正的數組
Array.prototype.slice.apply({0:1,length:1});//[1]
或者
[].prototype.slice.apply({0:1,length:1});//[1]
【4】綁定回呼函數的對象
由於apply方法(或者call方法)不僅綁定函數執行時所在的對象,還會立即執行函數,因此不得不把綁定語句寫在一個函數體內。更簡潔的寫法是採用下面介紹的bind方法
var o = {};o.f = function () { console.log(this === o);}var f = function (){ o.f.apply(o);};$(‘#button‘).on(‘click‘, f);
【bind()】
bind()是ES5新增的方法,這個方法的主要作用就是將函數綁定到某個對象
當在函數f()上調用bind()方法並傳入一個對象o作為參數,這個方法將返回一個新的函數。以函數調用的方式調用新的函數將會把原始的函數f()當做o的方法來調用,傳入新函數的任何實參都將傳入原始函數
[注意]IE8-瀏覽器不支援
function f(y){ return this.x + y; //這個是待綁定的函數}var o = {x:1};//將要綁定的對象var g = f.bind(o); //通過調用g(x)來調用o.f(x)g(2);//3
相容代碼
function bind(f,o){ if(f.bind){ return f.bind(o); }else{ return function(){ return f.apply(o,arguments); } }}
bind()方法不僅是將函數綁定到一個對象,它還附帶一些其他應用:除了第一個實參之外,傳入bind()的實參也會綁定到this,這個附帶的應用是一種常見的函數式編程技術,有時也被稱為‘柯裡化‘(currying)
var sum = function(x,y){ return x+y;}var succ = sum.bind(null,1);succ(2); //3,x綁定到1,並傳入2作為實參y
function f(y,z){ return this.x + y + z;}var g = f.bind({x:1},2);g(3); //6,this.x綁定到1,y綁定到2,z綁定到3
使用bind()方法實現柯裡化可以對函數參數進行拆分
function getConfig(colors,size,otherOptions){ console.log(colors,size,otherOptions);}var defaultConfig = getConfig.bind(null,‘#c00‘,‘1024*768‘);defaultConfig(‘123‘);//‘#c00 1024*768 123‘defaultConfig(‘456‘);//‘#c00 1024*768 456‘
【toString()】
函數的toString()執行個體方法返回函數代碼的字串,而靜態toString()方法返回一個類似‘[native code]‘的字串作為函數體
function test(){ alert(1);//test}test.toString();/*"function test(){ alert(1);//test }"*/Function.toString();//"function Function() { [native code] }"
【toLocaleString()】
函數的toLocaleString()方法和toString()方法返回的結果相同
function test(){ alert(1);//test}test.toLocaleString();/*"function test(){ alert(1);//test }"*/Function.toLocaleString();//"function Function() { [native code] }"
【valueOf()】
函數的valueOf()方法返回函數本身
function test(){ alert(1);//test}test.valueOf();/*function test(){ alert(1);//test }*/typeof test.valueOf();//‘function‘Function.valueOf();//Function() { [native code] }
參考資料
【1】 W3School-Javascript進階教程——Function對象 http://www.w3school.com.cn/js/
【2】 阮一峰Javascript標準參考教程——函數的屬性和方法 http://javascript.ruanyifeng.com/grammar/
【3】《javascript權威指南(第6版)》第8章 函數
【4】《javascript進階程式設計(第3版)》第5章 參考型別
【5】《javascript DOM編程藝術(第2版)》第2章 javascript文法
【6】《javascript語句精粹》第4章 函數
深入理解javascript函數系列第三篇