函數是javascript中特殊的對象,能夠擁有屬性和方法,就像普通的對象擁有屬性和方法同樣。甚至能夠用Function()構造函數來建立新的函數對象。本文是深刻理解javascript函數系列第三篇——屬性和方法javascript
【length屬性】html
函數系列第二篇中介紹過,arguments對象的length屬性表示實參個數,而函數的length屬性則表示形參個數java
function add(x,y){ console.log(arguments.length)//3 console.log(add.length);//2 } add(1,2,3);
【name屬性】chrome
函數定義了一個非標準的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屬性,會返回空字符串,而ES6的name屬性會返回實際的函數名瀏覽器
var func1 = function () {}; func1.name //ES5: "" func1.name //ES6: "func1"
若是將一個具名函數賦值給一個變量,則ES5和ES6的name屬性都返回這個具名函數本來的名字app
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(); //red sayColor.call(this); //red sayColor.call(window); //red sayColor.call(o); //blue
//sayColor.call(o)等價於: o.sayColor = sayColor; o.sayColor(); //blue delete 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));//20 console.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()可能更合適
在非嚴格模式下,使用函數的call()或apply()方法時,null或undefined值會被轉換爲全局對象。而在嚴格模式下,函數的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');// false obj.hasOwnProperty = function (){ return true; }; obj.hasOwnProperty('toString');// true Object.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】將一個數組的值push到另外一個數組中
var a = []; Array.prototype.push.apply(a,[1,2,3]); console.log(a);//[1,2,3] Array.prototype.push.apply(a,[2,3,4]); console.log(a);//[1,2,3,2,3,4]
若是使用ES6中的不定參數則很是簡單
var a = [...[1,2,3],...[2,3,4]]; console.log(a);//[1,2,3,2,3,4]
【5】綁定回調函數的對象
因爲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.prototype.bind = function(context){ var self = this; return function(){ return self.apply(context,arguments); } }
一般,會把它實現得稍微複雜一點,使得能夠填入一些參數
Function.prototype.bind = function(context){ var self = this, context = [].shift.call(arguments), args = [].slice.call(arguments); return function(){ return self.apply(context,[].concat.call(args,[].slice.call(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函數系列第三篇——屬性和方法 - 小火柴的藍色理想 - 博客園https://www.cnblogs.com/xiaohuochai/p/5707378.html