首頁 >web前端 >js教程 >javascript中call詳解

javascript中call詳解

php中世界最好的语言
php中世界最好的语言原創
2018-03-14 13:25:313313瀏覽

這次帶給大家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中文网其它相关文章!

推荐阅读:

spring boot的定时任务应该如何使用

javaScript使用call和apply

以上是javascript中call詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn