你們都知道在函數中,最回味無窮的就是prototype屬性了,對於ECMAScript中的引用類型而言,prototype是保存它們實力方法的真正所在。數組
諸如toString()和valueOf()等方法都保存在prototype名下,只不過是經過各自對象的實例訪問。在建立自定義引用類型以及實現繼承時,prototype屬性的做用是極爲重要的。app
每一個函數都包含兩個非繼承而來的方法:apply()和call(),它們都是在特定的做用域中調用函數,實際上就是設置函數體內this對象的值。函數
1.apply()this
apply()接收兩個參數,第一個是在其中運行函數的做用域,另外一個是參數數組。其中第二個參數能夠是Array的實例,也能夠是arguments對象;spa
1 function sum(num1, num2) { 2 return num1 + num2; 3 } 4 function callSum1(num1, num2) { 5 return sum.apply(this, arguments); // 傳入arguments對象 6 } 7 function callSum2(num1, num2) { 8 return sum.apply(this, [num1, num2]); // 傳入數組 9 } 10 console.log(callSum1(10, 10)); // 20 11 console.log(callSum2(10, 10)); // 20
解釋:上述代碼callSum1()在執行sum()函數的時候傳入了this做爲this值(由於是在全局做用域中調用的,因此這個this就是window對象),以及第二個參數arguments;prototype
而callSum2()也調用了sum()函數,可是傳入的是this和一個數組;他們的執行結果是相同的;code
⚠️上述代碼執行是在非嚴格模式下,如果嚴格模式下this的值會是undefined;對象
2.call()blog
call()與apply()做用相同,區別僅在於接收參數的方式不一樣,call()的第一個參數也是this,可是從第二個參數就要逐個的進行列舉了;繼承
function callSum3(num1, num2) { return sum.call(this, num1, num2); } console.log(callSum3(10, 10)); // 20
總結一下call()和apply(),它們的真正用武之地是----擴充函數運行的做用域
舉個🌰:
window.color = "red"; var o = { color: 'blue' } function sayColor() { console.log(this.color); } sayColor(); // red sayColor.call(this); // red sayColor.apply(window); // red sayColor.call(o); // blue 解釋:這裏的this變成了對象o,而不是window
3.bind()
該方法會建立一個函數的實例,其this值會被綁定到傳給bind()函數的值,例如
// 建立了兩個函數實例,它們都須要手動的去執行一下 var exFunc = sayColor.bind(o); var exFunc1 = sayColor.bind(this); exFunc(); // blue exFunc1(); // red
最後:call()和apply()都會當即執行,而bind()會先建立一個函數實例,而後手動的去執行;它們都會繼承傳遞給它們的函數的屬性和方法哈哈哈。