一直以來在看這些手寫自定義方法,其實目的不是看實現結果,而是看過程的思路,從中會學習到一些邏輯的思惟,雖然都是一些簡單的小方法,可是仍是值得咱們一看的。javascript
第一個咱們就來看看這個call,可能你們都見慣不慣了,但仍是以call 爲例總結一下,apply 方法思路相同。首先咱們來看看自帶call方法的用途吧...java
var value = 'this is window';
var foo = {
value : 'this is foo'
}
function bar(name,age){
console.log(this.value);
}
bar.call(foo); //this is foo
複製代碼
運行結果是'this is foo' , call函數在這裏修改了bar運行時this的指向,至關於執行了foo.value,因此輸出的是foo對象下的value。那咱們本身封裝的思路就是這樣了:數組
Function.prototype.call2 = function(obj){
var obj = obj || window; //若是obj爲null,那麼咱們讓它指向window
obj.fn = this;
obj.fn();
delete obj.fn; //執行完後接的刪除這個臨時方法
}
var value = 'this is window';
var foo = {
value : 'this is foo'
}
function bar(name,age){
console.log(this.value);
}
bar(); //this is window
bar.call1(foo); //this is foo
複製代碼
在Function的原型上新建方法call2,傳遞第一個參數,也就是須要指向的那個對象,而後this指向當前調用call2 方法的對象,而後執行。 call方法是能夠接收參數的,因此咱們繼續來完善這個方法。app
Function.prototype.call2 = function(obj){
var obj = obj || window;
var arr = []; //臨時建立一個空的數組,來存放傳進來的參數
obj.fn = this;
for(var i = 1; i < arguments.length; i++){ //參數第一個是要指向的對象,因此咱們從第二個參數開始循環添加,i=1
arr.push('arguments['+i+']');
}
var result = eval('obj.fn('+arr.join()+')');
delete obj.fn;
return result;
}
複製代碼
arr 數組存後結果是 ["arguments[1]", "arguments[2]"...],arr.join()把它轉成字符串,因此咱們用到eval 方法,能夠把string字符串裏的內容運行,把結果賦值給result,返回出去。 完整的代碼是這樣的:函數
Function.prototype.call2 = function(obj){
var obj = obj || window;
var arr = [];
obj.fn = this;
for(var i = 1; i < arguments.length; i++){
arr.push('arguments['+i+']');
}
var result = eval('obj.fn('+arr.join()+')');
delete obj.fn;
return result;
}
var value = 'this is window';
var foo = {
value : 'this is foo'
}
function bar(name,age){
console.log(this.value);
console.log(name,age);
}
bar.call2(foo,'fly',30); //this is foo fly 30
複製代碼
這個也和call,apply 方法相似,bind方法返回的是一個綁定this後的函數,而且該函數並無執行,須要手動去調用,而call,apply是當即執行。有了上面的自定義方法call2 ,這裏bing我就簡短來講了,直接上代碼。學習
Function.prototype.bind2 = function(obj){
if(typeof this!== 'function'){
return this;
}
var arg = Array.prototype.slice.call(arguments,1); //從第二個參數開始截取
var that = this; //這裏指向當前調用者,函數
//建立返回的函數
function bindFn(){
var _this = this instanceof bindFn ? this : obj; // 返回的函數可能涉及到new 操做符調用,因此這裏須要判斷一下,當前的對象 是不是 bindFn對象的實例,不然返回傳進來的對象obj
return that.apply(_this,arg.concat(Array.prototype.slice.call(arguments)));
}
var fn = function(){}; // 建立空的函數,讓這個函數的原型接收當前函數的屬性和方法,而後吧實例賦值給bindFn的原型
fn.prototype = this.prototype;
bindFn.prototype = new fn();
return bindFn; //最後返回bindFn 函數
}
複製代碼