這次帶給大家javascript中call詳解,使用javascript中call的注意事項有哪些,下面就是實戰案例,一起來看一下。
首先要先了解函數本身會有一些自己的屬性,例如:
length:形參的數量;
name:函數名稱;
prototype:類別的原型,原型上定義的方法都是目前這個類別的實例的公有方法;
proto:把函數當作一個普通對象,指向Function這個類別的原型
函數在整個JavaScript中是最複雜也是最重要的知識,對於一個函數來說,會存在多種角色:
function Fn() { var num = 500; this.x = 100; } Fn.prototype.getX = function () { console.log(this.x); } Fn.aaa = 1000;var f = new Fn; f.num // undefinedf.aaa // undefined12345678910111213 var res = Fn(); // res是undefined Fn中的this是window
角色一:普通函數,對於Fn而言,它本身是一個普通的函數,執行的時候會形成私有的作用域,然後進行形參賦值、預解析、程式碼執行、執行完成後記憶體銷毀;
角色二:類,它有自己的實例,f就是Fn作為類別而產生的一個實例,也有一個叫做prototype的屬性是自己的原型,它的實例都可以指向自己的原型;
角色三:普通對象,Fn和var obj = {} 中的obj一樣,就是一個普通的物件(所有的函數都是Function的實例),它作為物件可以有一些自己的私有屬性,也可以透過proto找到Function.prototype;
函數的以上三種角色,可能大多數同學對於角色一和角色二都是沒有任何疑問的,不過對於角色三可能會稍有疑惑,那麼畫張圖來理解下吧:
函數作為普通對象.png
call深入
call的基本使用
var ary = [12, 23, 34]; ary.slice();
以上兩行簡單的程式碼的執行過程為:ary這個實例透過原型鏈的尋找機制找到Array .prototype上的slice方法,讓找到的slice方法執行,在執行slice方法的過程中才把ary數組進行了截取。
注意:slice方法執行之前有一個在原型上尋找的過程(目前實例中沒有找到,再根據原型鏈查找)。
當知道了一個物件呼叫方法會有一個查找過程之後,我們再看:
var obj = {name:’iceman’}; function fn() { console.log(this); console.log(this.name); } fn(); // this –> window // obj.fn(); // Uncaught TypeError: obj.fn is not a function fn.call(obj);
call方法的作用:先尋找call方法,最後透過原型鏈在Function的原型中找到call方法,然後讓call方法執行,在執行call方法的時候,讓fn方法中的this變成第一個參數值obj,最後再把fn這個函數執行。
2.2、call方法原理
模擬Function中內建的call方法,寫一個myCall方法,探討call方法的執行原理
function sum(){ console.log(this); }function fn(){ console.log(this); }var obj = {name:'iceman'};Function.prototype.myCall = function (context) { // myCall方法中的this就是当前我要操作和改变其this关键字的那个函数名 // 1、让fn中的this关键字变为context的值->obj // 让this这个函数中的"this关键字"变为context // eval(this.toString().replace("this","obj")); // 2、让fn方法在执行 // this();};1234567891011121314151617
#fn.myCall( obj);// myCall方法中原來的this是fn
sum.myCall(obj);// myCall方法中原來的this是sum
當fn.myCall(obj); 這行程式碼執行的時候,根據this的尋找規律,在myCall方法前面有”.”,那麼myCall中的this就是fn。執行myCall的方法,在第一步會將方法體中this換為傳入的對象,並且執行原來的this, 注意:是執行原來的this(我在學這一塊的時候這裡理解了好久),在本例中就是執行fn。
看完以上那段話是不是有些懵逼了呢?哈哈,沒事,接下來看下面例子,理解一下。
call方法經典範例
function fn1() { console.log(1); }function fn2() { console.log(2); }123456
輸出一
fn1.call(fn2); // 1
首先fn1透過原型鏈尋找機制找到Function.prototype上的call方法,並且讓call方法執行,此時call這個方法中的this就是要操作的fn1。在call方法程式碼執行的過程過程中,先讓fn1中的「this關鍵字」變成fn2,然後再讓fn1這個方法執行。
注意:在執行call方法的時候,fn1中的this的確會變成fn2,但是在fn1的方法體中輸出的內容中並沒有涉及到任何和this相關的內容,所以還是輸出1.
輸出二
fn1.call.call(fn2); // 2
首先fn1透過原型鏈找到Function.prototype上的call方法,然後再讓call方法透過原型再找到Function原型上的call(因為call本身的值也是函數,所以同樣可以讓Function.prototype),在第二次找到call的時候再讓方法執行,方法中的this是fn1.call,先讓這個方法中的this變成fn2,然後再讓fn1.call執行。
這個例子有點繞了,不過一步一步來理解。在最開始的時候,fn1.call.call(fn2) 這行程式碼的最後一個call中的this是fn1.call,根據前面的理解可以知道fn1.call 的原理大致為:
Function.prototype.call = function (context) { // 改变fn中的this关键字 // eval(....); // 让fn方法执行 this(); // 此时的this就是fn1};1234567
將上面的程式碼寫為另一種形式:
Function.prototype.call = test1;function test1 (context) { // 改变fn中的this关键字 // eval(....); // 让fn方法执行 this(); // 此时的this就是fn1};12345678
我們知道,這兩種形式的寫法的作用是一樣的。那麼此時可以將 fn1.call.call(fn2) 寫成 test1.call(fn2) ,call中的的this就是test1:
Function.prototype.call = function (context) { // 改变fn中的this关键字 // eval(....); // 让fn方法执行 this(); // 此时的this就是test1};1234567
注意:此時call中的的this就是test1。
然後再將call中this替換為fn2,那麼test1方法變成:
Function.prototype.call = function (context) { // 省略其他代码 fn2(); };12345
所以最后是fn2执行,所以最后输出2。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上是javascript中call詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!