การเรียก Javascript () & Apply () vs bind ()?


794

ฉันรู้แล้วapplyและcallมีฟังก์ชั่นที่คล้ายกันซึ่งตั้งค่าthis(บริบทของฟังก์ชั่น)

ความแตกต่างคือกับวิธีที่เราส่งอาร์กิวเมนต์ (manual vs array)

คำถาม:

แต่เมื่อไรฉันจึงควรใช้ bind()วิธีนี้?

var obj = {
  x: 81,
  getX: function() {
    return this.x;
  }
};

alert(obj.getX.bind(obj)());
alert(obj.getX.call(obj));
alert(obj.getX.apply(obj));

jsbin


9
ไม่ใช่ความผิดของคุณหากมีผู้ใช้ที่ดูคะแนนชื่อเสียงของ OP ก่อนที่จะโพสต์คำตอบหรือถอนตัวออก :)
Gabriel Llamas

54
โทรและใช้เรียกฟังก์ชั่นในขณะที่ผูกสร้างฟังก์ชั่น แม้ว่าcall()คุณจะผ่านการโต้แย้งเป็นรายบุคคลและapply()เป็นอาเรย์อาร์กิวเมนต์ สำหรับรายละเอียดเพิ่มเติมโปรดดูเอกสารที่เชื่อมโยงซึ่งควรจะตอบคำถามของคุณได้อย่างสมบูรณ์
Nope

3
kind of weird there is not an existing question about this :เกี่ยวกับเรื่องนั้น อาจเป็นเพราะbind()มีการเพิ่มหลังจากที่อีกสองมีอยู่แล้วใน JavaScript 1.8.5 - ECMA-262, ฉบับที่ 5 ในขณะที่call()และapply()ได้รับรอบตั้งแต่ JavaScript 1.3 - ECMA-262 ฉบับที่ 3 ดังนั้นมีคำถามเกี่ยวกับพวกเขาเช่น: สิ่งที่เป็นที่ความแตกต่างระหว่างการโทรและการใช้ ฉันแค่คาดเดา แต่เมื่อฉันสงสัยว่าตัวเอง
Nope

คุณต้องการวิธีการเหล่านี้ (โทร, สมัคร, ผูก) ที่นี่หรือไม่? หากไม่มีสิ่งนี้คุณสามารถเรียกใช้เมธอดและสิ่งนี้จะชี้ไปที่วัตถุเท่านั้น
Mahi

ชำระเงินลิงค์ - techyaura-blogs.blogspot.com/2020/05/…
techyaura

คำตอบ:


131

ฉันสร้างการเปรียบเทียบระหว่างวัตถุฟังก์ชั่นการเรียกใช้ฟังก์ชั่นcall/applyและbindในขณะที่ผ่านมา:

ป้อนคำอธิบายรูปภาพที่นี่

.bindอนุญาตให้คุณตั้งthisค่าตอนนี้ในขณะที่อนุญาตให้คุณเรียกใช้ฟังก์ชันในอนาคตเนื่องจากจะส่งคืนวัตถุฟังก์ชันใหม่


779

ใช้.bind()เมื่อคุณต้องการให้เรียกใช้ฟังก์ชันในภายหลังพร้อมบริบทบางอย่างซึ่งมีประโยชน์ในเหตุการณ์ ใช้.call()หรือ.apply()เมื่อคุณต้องการเรียกใช้ฟังก์ชันได้ทันทีและแก้ไขบริบท

เรียกใช้ / เรียกใช้ฟังก์ชั่นได้ทันทีในขณะที่ bindส่งคืนฟังก์ชันที่เมื่อดำเนินการในภายหลังจะมีชุดบริบทที่ถูกต้องสำหรับการเรียกใช้ฟังก์ชันต้นฉบับ วิธีนี้คุณสามารถรักษาบริบทในการเรียกกลับและเหตุการณ์แบบอะซิงก์ได้

ฉันทำสิ่งนี้มาก:

function MyObject(element) {
    this.elm = element;

    element.addEventListener('click', this.onClick.bind(this), false);
};

MyObject.prototype.onClick = function(e) {
     var t=this;  //do something with [t]...
    //without bind the context of this function wouldn't be a MyObject
    //instance as you would normally expect.
};

ฉันใช้อย่างกว้างขวางใน Node.js สำหรับการเรียกกลับ async ที่ฉันต้องการผ่านวิธีการของสมาชิก แต่ยังต้องการให้บริบทเป็นอินสแตนซ์ที่เริ่มต้นการดำเนินการ async

การผูกที่เรียบง่ายไร้เดียงสาจะเป็นเช่น:

Function.prototype.bind = function(ctx) {
    var fn = this;
    return function() {
        fn.apply(ctx, arguments);
    };
};

มีมากกว่านั้น (เช่นผ่าน args อื่น ๆ ) แต่คุณสามารถอ่านเพิ่มเติมเกี่ยวกับมันและดูการใช้งานจริงบน MDNMDN

หวังว่านี่จะช่วยได้


2
@RoyiNamir ที่ถูกต้องคุณสามารถใช้ฟังก์ชัน "bound" ที่ส่งคืนในภายหลังและบริบทจะได้รับการดูแล
ชาด

5
นั่นคือสิ่งที่bindส่งกลับ
ชาด

@RoyiNamir แก้ไขคำตอบของฉัน
Chad

4
นอกจากนี้คุณยังสามารถใช้การเชื่อมสำหรับงาน partials โดยส่งผ่านอาร์กิวเมนต์ก่อนที่ฟังก์ชันจะถูกเรียกใช้
Andrew Kirkegaard

1
คุณเพิ่งนำการผูกกลับมาใช้ใหม่ไม่มีความแตกต่างจริงๆ ไม่ว่าคุณจะใช้วิธีการปิดล้อมในการปิดที่มีการเข้าถึงตัวแปรขอบเขตที่เก็บบริบท รหัสของคุณนั้นเป็น polyfill ที่ฉันโพสต์
ชาด

446

พวกเขาทั้งหมดแนบสิ่งนี้เข้ากับฟังก์ชั่น (หรือวัตถุ) และความแตกต่างอยู่ในการเรียกใช้ฟังก์ชั่น (ดูด้านล่าง)

โทรแนบสิ่งนี้ในฟังก์ชั่นและดำเนินการฟังก์ชั่นทันที:

var person = {  
  name: "James Smith",
  hello: function(thing) {
    console.log(this.name + " says hello " + thing);
  }
}

person.hello("world");  // output: "James Smith says hello world"
person.hello.call({ name: "Jim Smith" }, "world"); // output: "Jim Smith says hello world"

ผูกแนบสิ่งนี้ในฟังก์ชั่นและจะต้องมีการเรียกแยกต่างหากเช่นนี้

var person = {  
  name: "James Smith",
  hello: function(thing) {
    console.log(this.name + " says hello " + thing);
  }
}

person.hello("world");  // output: "James Smith says hello world"
var helloFunc = person.hello.bind({ name: "Jim Smith" });
helloFunc("world");  // output: Jim Smith says hello world"

หรือเช่นนี้

...    
var helloFunc = person.hello.bind({ name: "Jim Smith" }, "world");
helloFunc();  // output: Jim Smith says hello world"

ใช้คล้ายกับการโทรยกเว้นว่าจะต้องใช้วัตถุเหมือนอาร์เรย์แทนที่จะแสดงข้อโต้แย้งทีละรายการ:

function personContainer() {
  var person = {  
     name: "James Smith",
     hello: function() {
       console.log(this.name + " says hello " + arguments[1]);
     }
  }
  person.hello.apply(person, arguments);
}
personContainer("world", "mars"); // output: "James Smith says hello mars", note: arguments[0] = "world" , arguments[1] = "mars"                                     

1
นี่หมายถึงความแตกต่างคือการผูกมัดคือการปิดหรือไม่?
เกรกอรี่อาร์

คุณเพิ่งสอนฉันเกี่ยวกับคุณลักษณะการโต้แย้งที่ใช้ภายในฟังก์ชันผ่านข้อมูลโค้ดของคุณ ขอแนะนำให้พูดถึง"use strict"เพื่อหลีกเลี่ยงการแทนที่คำหลักที่สงวนไว้ดังกล่าว +1
RBT

@ Max เห็นด้วย ฉันได้ส่งการแก้ไขประเด็น "สิ่งนี้" ผิดหรือไม่สมเหตุสมผลจนกว่าเราจะใช้การเชื่อมโยง / โทร / สมัคร
iono

1
ขอบคุณสำหรับคำแนะนำในการปรับปรุง ฉันแก้ไขคำตอบของฉันเล็กน้อย @iono ข้อเสนอแนะของคุณมีความไม่ถูกต้องบางอย่างดังนั้นจึงไม่สามารถอนุมัติได้ แต่แก้ไขคำตอบของฉันเองแล้ว หวังว่าตอนนี้มันจะครอบคลุมมากขึ้น
CuriousSuperhero

200

ตอบในรูปแบบ SIMPLEST

  • โทรใช้ฟังก์ชันและอนุญาตให้คุณส่งผ่านข้อโต้แย้งทีละรายการ
  • ใช้ฟังก์ชั่นเรียกใช้และช่วยให้คุณสามารถส่งผ่านข้อโต้แย้งเป็นอาร์เรย์
  • Bindส่งคืนฟังก์ชันใหม่ที่อนุญาตให้คุณส่งผ่านอาร์เรย์นี้และอาร์กิวเมนต์จำนวนเท่าใดก็ได้

ใช้กับการโทรและตัวอย่างการผูก

โทร

var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};

function say(greeting) {
    console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}

say.call(person1, 'Hello'); // Hello Jon Kuperman
say.call(person2, 'Hello'); // Hello Kelly King

ใช้

var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};

function say(greeting) {
    console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}

say.apply(person1, ['Hello']); // Hello Jon Kuperman
say.apply(person2, ['Hello']); // Hello Kelly King

ผูก

var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};

function say() {
    console.log('Hello ' + this.firstName + ' ' + this.lastName);
}

var sayHelloJon = say.bind(person1);
var sayHelloKelly = say.bind(person2);

sayHelloJon(); // Hello Jon Kuperman
sayHelloKelly(); // Hello Kelly King

เมื่อใช้แต่ละ

โทรและสมัครได้เปลี่ยนได้สวย เพียงตัดสินใจว่าการส่งอาเรย์เป็นเรื่องง่ายขึ้นหรือรายการอาร์กิวเมนต์ที่คั่นด้วยเครื่องหมายจุลภาค

ฉันจำได้เสมอว่าอันไหนที่จำได้ว่า Call for comma (รายการแยก) และ Apply for for Array

การผูกนั้นต่างกันเล็กน้อย ส่งคืนฟังก์ชันใหม่ โทรและสมัครใช้งานฟังก์ชั่นปัจจุบันทันที

ผูกเป็นสิ่งที่ดีสำหรับหลายสิ่งหลายอย่าง เราสามารถใช้ฟังก์ชั่นแกงในตัวอย่างด้านบน เราสามารถใช้ฟังก์ชั่นสวัสดีที่เรียบง่ายและเปลี่ยนเป็น helloJon หรือ helloKelly นอกจากนี้เรายังสามารถใช้สำหรับกิจกรรมเช่น onClick ที่เราไม่รู้ว่าจะถูกไล่ออกเมื่อใด แต่เรารู้ว่าเราต้องการให้มีบริบทใด

การอ้างอิง: codeplanet.io


8
คำตอบที่น่ากลัวถ้าเป็นโพสต์คำถามของฉันฉันให้เครื่องหมายถูกกับคุณ
AmerllicA

ในcallและapplyมันเป็นไปตามนั้นหรือไม่ถ้าคุณไม่มีthisเมธอดด้านในคุณจะกำหนดอาร์กิวเมนต์แรกเป็นnull?
Daryll Santos

1
@DaryllSantos ตาม MDN: ตัวเลือกนี้ ค่านี้ให้ไว้สำหรับการเรียกใช้ฟังก์ชัน โปรดทราบว่านี่อาจไม่ใช่ค่าจริงที่เห็นโดยวิธีการ: หากวิธีนั้นเป็นฟังก์ชันในโหมดที่ไม่เข้มงวด null และ undefined จะถูกแทนที่ด้วยวัตถุทั่วโลกและค่าดั้งเดิมจะถูกแปลงเป็นวัตถุ ดังนั้นถ้าคุณไม่ใช้สิ่งนี้ในฟังก์ชั่นมันไม่สำคัญ
Amit Shah

4
call = = เครื่องหมายจุลภาค, ใช้ == อาเรย์เป็นเคล็ดลับการท่องจำเล็ก ๆ น้อย ๆ ที่ดี
drlff

var person1 = {firstName: 'Jon', lastName: 'Kuperman'}; function say(greeting) { console.log(greeting + ' ' + this.firstName + ' ' + this.lastName); } say.apply(person1, ['Hello']); // Hello Jon Kupermanทำงานได้อย่างสมบูรณ์แบบและส่งออก VM128: 4 สวัสดี Jon Kuperman
Pratik

53

จะช่วยให้การตั้งค่าthisเป็นอิสระจากวิธีการเรียกใช้ฟังก์ชั่น สิ่งนี้มีประโยชน์มากเมื่อทำงานกับการเรียกกลับ:

  function sayHello(){
    alert(this.message);
  }

  var obj = {
     message : "hello"
  };
  setTimeout(sayHello.bind(obj), 1000);

เพื่อให้ได้ผลลัพธ์เดียวกันโดยมีcallลักษณะดังนี้:

  function sayHello(){
    alert(this.message);
  }

  var obj = {
     message : "hello"
  };
  setTimeout(function(){sayHello.call(obj)}, 1000);

5
การใช้งาน.bind()สิ่งที่คุณเห็นก่อนหน้านี้ไม่ถูกต้อง เมื่อคุณใช้fn.bind(obj)ฟังก์ชั่นอื่น ๆ จะถูกส่งกลับ (ไม่ใช่สิ่งที่คุณสร้างมาก่อน) และไม่มีความสามารถในการเปลี่ยนค่าthisของbindedฟังก์ชั่นภายใน ส่วนใหญ่ใช้สำหรับthisประกันการโทรกลับ แต่ในตัวอย่างของคุณไม่มีความแตกต่างในผลลัพธ์ แต่fn !== fn.bind(obj);ขอให้สังเกตว่า
ValeriiVasin

@InviS ฉันไม่เข้าใจความคิดเห็นของคุณ - ทำไมถึงไม่มีความแตกต่าง?
jantimon

2
ความแตกต่างในการโทรและนำไปใช้คือ ในการเรียกคุณผ่านข้อโต้แย้งเป็นสตริงคั่นด้วยเครื่องหมายจุลภาคในขณะที่ใช้คุณสามารถส่งข้อโต้แย้งในรูปแบบของอาร์เรย์ ส่วนที่เหลือเหมือนกัน
Ashish Yadav

สตริงคั่นด้วยเครื่องหมายจุลภาค?? เพิ่ง ผ่านการขัดแย้งกันโดยคั่นด้วยเครื่องหมายจุลภาค !!
Sudhansu Choudhary

46

สมมติว่าเรามีmultiplicationฟังก์ชั่น

function multiplication(a,b){
console.log(a*b);
}

ให้สร้างฟังก์ชั่นมาตรฐานโดยใช้ bind

var multiby2 = multiplication.bind(this,2);

ตอนนี้ multiby2 (b) เท่ากับการคูณ (2, b);

multiby2(3); //6
multiby2(4); //8

ถ้าฉันผ่านพารามิเตอร์ทั้งสองเป็นตัวเชื่อมโยง

var getSixAlways = multiplication.bind(this,3,2);

ตอนนี้ getSixAlways () เท่ากับการคูณ (3,2);

getSixAlways();//6

แม้ผ่านพารามิเตอร์ส่งกลับ 6; getSixAlways(12); //6

var magicMultiplication = multiplication.bind(this);

สิ่งนี้จะสร้างฟังก์ชั่นการคูณใหม่และกำหนดให้กับ magicMultiplication

โอ้ไม่เรากำลังซ่อนฟังก์ชันการคูณลงใน magicMultiplication

การโทร magicMultiplicationจะส่งคืนค่าว่างfunction b()

ในการดำเนินการมันทำงานได้ดี magicMultiplication(6,5); //30

โทรและสมัครได้อย่างไร

magicMultiplication.call(this,3,2); //6

magicMultiplication.apply(this,[5,2]); //10

ในคำง่าย ๆbindสร้างฟังก์ชั่นcallและapplyดำเนินการฟังก์ชั่นในขณะที่applyคาดว่าพารามิเตอร์ในอาร์เรย์


อธิบายได้ดีมาก!
CatalinBerta

3
+1 สำหรับ "ในคำง่าย ๆbindสร้างฟังก์ชั่นcallและapplyดำเนินการฟังก์ชั่นในขณะที่applyคาดหวังว่าพารามิเตอร์ในอาร์เรย์"
Josh Buchea

32

ทั้งสองFunction.prototype.call()และFunction.prototype.apply()เรียกใช้ฟังก์ชันที่มีthisค่าที่กำหนดและส่งคืนค่าส่งคืนของฟังก์ชันนั้น

Function.prototype.bind()ในทางกลับกันสร้างฟังก์ชั่นใหม่ที่มีที่กำหนด thisค่าที่และส่งกลับฟังก์ชันนั้นโดยไม่ต้องดำเนินการ

ดังนั้นลองใช้ฟังก์ชั่นที่มีลักษณะดังนี้:

var logProp = function(prop) {
    console.log(this[prop]);
};

ทีนี้มาดูวัตถุที่มีลักษณะดังนี้:

var Obj = {
    x : 5,
    y : 10
};

เราสามารถผูกฟังก์ชันของเรากับวัตถุของเราดังนี้:

Obj.log = logProp.bind(Obj);

ตอนนี้เราสามารถรันObj.logที่ใดก็ได้ในรหัสของเรา:

Obj.log('x'); // Output : 5
Obj.log('y'); // Output : 10

ที่ ๆ มันน่าสนใจมาก ๆ ก็คือเมื่อคุณไม่เพียง แต่ผูกค่าสำหรับthisแต่ยังสำหรับอาร์กิวเมนต์prop:

Obj.logX = logProp.bind(Obj, 'x');
Obj.logY = logProp.bind(Obj, 'y');

ตอนนี้เราสามารถทำสิ่งนี้:

Obj.logX(); // Output : 5
Obj.logY(); // Output : 10

23

ผูก : มันผูกฟังก์ชั่นที่มีค่าและบริบทที่ให้ไว้ แต่มันไม่ได้ดำเนินการฟังก์ชั่น ในการใช้งานฟังก์ชั่นที่คุณต้องการจะเรียกใช้

call : มันรันฟังก์ชันที่มีบริบทและพารามิเตอร์ที่ให้ไว้

ใช้ : มันรันฟังก์ชั่นที่มีบริบทที่ให้บริการและ พารามิเตอร์เป็นอาร์เรย์


ง่ายและอ่อนน้อมถ่อมตน!
Habeeb Perwad

18

นี่คือหนึ่งในบทความที่ดีที่จะแสดงให้เห็นถึงความแตกต่างในหมู่bind(), apply()และcall()สรุปว่ามันเป็นด้านล่าง

  • bind()ช่วยให้เราสามารถตั้งค่าได้อย่างง่ายดายว่าวัตถุใดที่จะผูกพันกับสิ่งนี้เมื่อมีการเรียกใช้ฟังก์ชันหรือวิธีการ

    // This data variable is a global variable​
    var data = [
        {name:"Samantha", age:12},
        {name:"Alexis", age:14}
    ]
    var user = {
        // local data variable​
        data    :[
            {name:"T. Woods", age:37},
            {name:"P. Mickelson", age:43}
        ],
        showData:function (event) {
            var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1​
            console.log (this.data[randomNum].name + " " + this.data[randomNum].age);
        }
    }
    
    // Assign the showData method of the user object to a variable​
    var showDataVar = user.showData;
    showDataVar (); // Samantha 12 (from the global data array, not from the local data array)​
    /*
    This happens because showDataVar () is executed as a global function and use of this inside 
    showDataVar () is bound to the global scope, which is the window object in browsers.
    */
    
    // Bind the showData method to the user object​
    var showDataVar = user.showData.bind (user);
    // Now the we get the value from the user object because the this keyword is bound to the user object​
    showDataVar (); // P. Mickelson 43​
  • bind() ให้เรายืมวิธี

    // Here we have a cars object that does not have a method to print its data to the console​
    var cars = {
        data:[
           {name:"Honda Accord", age:14},
           {name:"Tesla Model S", age:2}
       ]
    }
    
    // We can borrow the showData () method from the user object we defined in the last example.​
    // Here we bind the user.showData method to the cars object we just created.​
    cars.showData = user.showData.bind (cars);
    cars.showData (); // Honda Accord 14​

    ปัญหาอย่างหนึ่งของตัวอย่างนี้คือเรากำลังเพิ่มวิธีการใหม่showDataในcarsวัตถุและเราอาจไม่ต้องการทำเช่นนั้นเพียงเพื่อยืมวิธีเนื่องจากวัตถุรถยนต์อาจมีคุณสมบัติหรือชื่อวิธีการshowDataอยู่แล้ว เราไม่ต้องการเขียนทับมันโดยไม่ตั้งใจ ตามที่เราจะเห็นในการสนทนาของเราApplyและCallด้านล่างมันเป็นสิ่งที่ดีที่สุดที่จะยืมวิธีการอย่างใดอย่างหนึ่งโดยใช้ApplyหรือCallวิธีการ

  • bind() ช่วยให้เราสามารถฟังก์ชั่นแกง

    Function Curryingหรือที่เรียกว่าบางส่วนของฟังก์ชั่นการใช้งานคือการใช้ฟังก์ชั่น (ที่ยอมรับอย่างน้อยหนึ่งข้อโต้แย้ง) ที่ส่งกลับฟังก์ชั่นใหม่ที่มีข้อโต้แย้งบางอย่างที่ตั้งไว้แล้ว

    function greet (gender, age, name) {
        // if a male, use Mr., else use Ms.​
        var salutation = gender === "male" ? "Mr. " : "Ms. ";
        if (age > 25) {
            return "Hello, " + salutation + name + ".";
        }else {
            return "Hey, " + name + ".";
        }
     }

    เราสามารถใช้ฟังก์ชั่นbind()แกงนี้ได้greet

    // So we are passing null because we are not using the "this" keyword in our greet function.
    var greetAnAdultMale = greet.bind (null, "male", 45);
    
    greetAnAdultMale ("John Hartlove"); // "Hello, Mr. John Hartlove."
    
    var greetAYoungster = greet.bind (null, "", 16);
    greetAYoungster ("Alex"); // "Hey, Alex."​
    greetAYoungster ("Emma Waterloo"); // "Hey, Emma Waterloo."
  • apply()หรือcall()การตั้งค่านี้ค่า

    apply, callและbindเมธอดทั้งหมดใช้เพื่อตั้งค่านี้เมื่อเรียกใช้เมธอดและพวกมันทำในวิธีที่แตกต่างกันเล็กน้อยเพื่อให้ใช้การควบคุมโดยตรงและความสามารถรอบด้านในโค้ด JavaScript ของเรา

    กระบวนการapplyและcallวิธีการเกือบจะเหมือนกันเมื่อตั้งค่านี้ยกเว้นว่าคุณส่งพารามิเตอร์ฟังก์ชันapply ()เป็นอาร์เรย์ในขณะที่คุณต้องแสดงรายการพารามิเตอร์แต่ละรายการเพื่อส่งผ่านไปยังcall ()วิธีการนั้น

    นี่คือตัวอย่างหนึ่งที่ใช้callหรือapplyตั้งค่านี้ในฟังก์ชันการเรียกกลับ

    // Define an object with some properties and a method​
    // We will later pass the method as a callback function to another function​
    var clientData = {
        id: 094545,
        fullName: "Not Set",
        // setUserName is a method on the clientData object​
        setUserName: function (firstName, lastName)  {
            // this refers to the fullName property in this object​
            this.fullName = firstName + " " + lastName;
        }
    };
    
    function getUserInput (firstName, lastName, callback, callbackObj) {
         // The use of the Apply method below will set the "this" value to callbackObj​
         callback.apply (callbackObj, [firstName, lastName]);
    }
    
    // The clientData object will be used by the Apply method to set the "this" value​
    getUserInput ("Barack", "Obama", clientData.setUserName, clientData);
    // the fullName property on the clientData was correctly set​
    console.log (clientData.fullName); // Barack Obama
  • ฟังก์ชั่นยืมด้วยapplyหรือcall

    • วิธีการอาร์เรย์ยืม

      มาสร้างarray-likeวัตถุและยืมวิธีการอาร์เรย์เพื่อใช้งานกับวัตถุที่เหมือนอาร์เรย์ของเรา

      // An array-like object: note the non-negative integers used as keys​
      var anArrayLikeObj = {0:"Martin", 1:78, 2:67, 3:["Letta", "Marieta", "Pauline"], length:4 };
      
       // Make a quick copy and save the results in a real array:
       // First parameter sets the "this" value​
       var newArray = Array.prototype.slice.call (anArrayLikeObj, 0);
       console.log (newArray); // ["Martin", 78, 67, Array[3]]​
      
       // Search for "Martin" in the array-like object​
       console.log (Array.prototype.indexOf.call (anArrayLikeObj, "Martin") === -1 ? false : true); // true​

      อีกกรณีทั่วไปคือแปลงargumentsเป็นอาร์เรย์ดังต่อไปนี้

        // We do not define the function with any parameters, yet we can get all the arguments passed to it​
       function doSomething () {
          var args = Array.prototype.slice.call (arguments);
          console.log (args);
       }
      
       doSomething ("Water", "Salt", "Glue"); // ["Water", "Salt", "Glue"]
    • ยืมวิธีอื่น ๆ

      var gameController = {
           scores  :[20, 34, 55, 46, 77],
           avgScore:null,
           players :[
                {name:"Tommy", playerID:987, age:23},
                {name:"Pau", playerID:87, age:33}
           ]
       }
       var appController = {
           scores  :[900, 845, 809, 950],
           avgScore:null,
           avg     :function () {
                   var sumOfScores = this.scores.reduce (function (prev, cur, index, array) {
                        return prev + cur;
               });
               this.avgScore = sumOfScores / this.scores.length;
           }
         }
         // Note that we are using the apply () method, so the 2nd argument has to be an array​
         appController.avg.apply (gameController);
         console.log (gameController.avgScore); // 46.4​
         // appController.avgScore is still null; it was not updated, only gameController.avgScore was updated​
         console.log (appController.avgScore); // null​
  • ใช้apply()เพื่อเรียกใช้งานฟังก์ชั่นแปรผัน

นี่Math.maxคือตัวอย่างหนึ่งของฟังก์ชั่นตัวแปร arity

// We can pass any number of arguments to the Math.max () method​
console.log (Math.max (23, 11, 34, 56)); // 56

แต่ถ้าเรามีจำนวนของตัวเลขให้ส่งผ่านไปMath.maxล่ะ? เราทำสิ่งนี้ไม่ได้:

var allNumbers = [23, 11, 34, 56];
// We cannot pass an array of numbers to the the Math.max method like this​
console.log (Math.max (allNumbers)); // NaN

นี่คือที่apply ()วิธีการที่จะช่วยให้เราดำเนินการฟังก์ชั่น variadic แทนการข้างต้นเราจะต้องผ่านอาร์เรย์ของตัวเลขโดยใช้apply () ดังนี้:

var allNumbers = [23, 11, 34, 56];
// Using the apply () method, we can pass the array of numbers:
console.log (Math.max.apply (null, allNumbers)); // 56

8

เรียกใช้ฟังก์ชั่นการเรียกใช้ทันที:

func.call(context, arguments);
func.apply(context, [argument1,argument2,..]);

การผูกไม่ได้เรียกใช้ฟังก์ชันในทันที แต่ส่งคืนฟังก์ชันการใช้ที่ห่อหุ้ม(สำหรับการดำเนินการในภายหลัง):

function bind(func, context) {
    return function() {
        return func.apply(context, arguments);
    };
}

7

วากยสัมพันธ์

  • โทร (thisArg, arg1, arg2, ... )
  • ใช้ (thisArg, argsArray)
  • ผูก (thisArg [, arg1 [, arg2 [, ... ]]])

ที่นี่

  • thisArg เป็นวัตถุ
  • argArray เป็นวัตถุอาร์เรย์
  • arg1, arg2, arg3, ... เป็นอาร์กิวเมนต์เพิ่มเติม

function printBye(message1, message2){
    console.log(message1 + " " + this.name + " "+ message2);
}

var par01 = { name:"John" };
var msgArray = ["Bye", "Never come again..."];

printBye.call(par01, "Bye", "Never come again...");
//Bye John Never come again...

printBye.call(par01, msgArray);
//Bye,Never come again... John undefined

//so call() doesn't work with array and better with comma seperated parameters 

//printBye.apply(par01, "Bye", "Never come again...");//Error

printBye.apply(par01, msgArray);
//Bye John Never come again...

var func1 = printBye.bind(par01, "Bye", "Never come again...");
func1();//Bye John Never come again...

var func2 = printBye.bind(par01, msgArray);
func2();//Bye,Never come again... John undefined
//so bind() doesn't work with array and better with comma seperated parameters


6

ความแตกต่างพื้นฐานระหว่าง Call, Apply และ Bind คือ:

การเชื่อมโยงจะถูกใช้หากคุณต้องการให้บริบทการดำเนินการของคุณมาในภายหลังในรูปภาพ

Ex:

var car = { 
  registrationNumber: "007",
  brand: "Mercedes",

  displayDetails: function(ownerName){
    console.log(ownerName + ' this is your car ' + '' + this.registrationNumber + " " + this.brand);
  }
}
car.displayDetails('Nishant'); // **Nishant this is your car 007 Mercedes**

สมมุติว่าฉันต้องการใช้วิธีนี้กับตัวแปรอื่น ๆ

var car1 = car.displayDetails('Nishant');
car1(); // undefined

หากต้องการใช้การอ้างอิงของรถยนต์ในตัวแปรอื่น ๆ ที่คุณควรใช้

var car1 = car.displayDetails.bind(car, 'Nishant');
car1(); // Nishant this is your car 007 Mercedes

มาพูดเกี่ยวกับการใช้ฟังก์ชั่นผูกที่กว้างขวางยิ่งขึ้น

var func = function() {
 console.log(this)
}.bind(1);

func();
// Number: 1

ทำไม? เพราะตอนนี้ func เชื่อมโยงกับหมายเลข 1 หากเราไม่ใช้การเชื่อมในกรณีนี้มันจะชี้ไปที่ Global Object

var func = function() {
 console.log(this)
}.bind({});

func();
// Object

โทร, นำไปใช้จะใช้เมื่อคุณต้องการรันคำสั่งในเวลาเดียวกัน

var Name = { 
    work: "SSE",
    age: "25"
}

function displayDetails(ownerName) {
    console.log(ownerName + ", this is your name: " + 'age' + this.age + " " + 'work' + this.work);
}
displayDetails.call(Name, 'Nishant')
// Nishant, this is your name: age25 workSSE

In apply we pass the array
displayDetails.call(Name, ['Nishant'])
// Nishant, this is your name: age25 workSSE

4

โทรสมัครและผูก และแตกต่างกันอย่างไร

ให้เรียนรู้การโทรและสมัครโดยใช้คำศัพท์ทุกวัน

คุณมีรถยนต์สามคันyour_scooter , your_car and your_jetที่ขึ้นต้นด้วยกลไกแบบเดียวกัน (วิธีการ) เราได้สร้างวัตถุที่มีวิธีการautomobilepush_button_engineStart

var your_scooter, your_car, your_jet;
var automobile = {
        push_button_engineStart: function (runtime){
        console.log(this.name + "'s" + ' engine_started, buckle up for the ride for ' + runtime + " minutes");
    }
}

ให้เข้าใจเมื่อมีการโทรและใช้งาน ช่วยให้สมมติว่าคุณเป็นวิศวกรและคุณมีyour_scooter, your_carและyour_jetซึ่งไม่ได้มาพร้อมกับ push_button_engine_start push_button_engineStartและคุณต้องการที่จะใช้บุคคลที่สาม

หากคุณเรียกใช้บรรทัดของรหัสต่อไปนี้พวกเขาจะให้ข้อผิดพลาด ทำไม?

//your_scooter.push_button_engineStart();
//your_car.push_button_engineStart();
//your_jet.push_button_engineStart();


automobile.push_button_engineStart.apply(your_scooter,[20]);
automobile.push_button_engineStart.call(your_jet,10);
automobile.push_button_engineStart.call(your_car,40);

ดังนั้นตัวอย่างข้างต้นจะทำให้ your_scooter, your_car, your_jet มีคุณสมบัติจากวัตถุรถยนต์

ลองดำดิ่งลึกลงไปที่ นี่เราจะแบ่งบรรทัดด้านบนของรหัส automobile.push_button_engineStartกำลังช่วยให้เราได้รับวิธีการใช้งาน

นอกจากนี้เรายังใช้ใช้หรือโทรโดยใช้เครื่องหมายจุด automobile.push_button_engineStart.apply()

ตอนนี้ใช้และโทรรับสองพารามิเตอร์

  1. บริบท
  2. ข้อโต้แย้ง

ดังนั้นที่นี่เราตั้งบริบทในบรรทัดสุดท้ายของรหัส

automobile.push_button_engineStart.apply(your_scooter,[20])

ความแตกต่างระหว่างการโทรและนำไปใช้เป็นเพียงการใช้ที่ยอมรับพารามิเตอร์ในรูปแบบของอาร์เรย์ในขณะที่การโทรก็สามารถยอมรับรายการของอาร์กิวเมนต์ที่คั่นด้วยเครื่องหมายจุลภาค

ฟังก์ชั่น JS Bind คืออะไร?

ฟังก์ชั่นการผูกนั้นเป็นพื้นซึ่งผูกบริบทของบางสิ่งบางอย่างแล้วเก็บไว้ในตัวแปรสำหรับการดำเนินการในระยะต่อมา

มาทำให้ตัวอย่างก่อนหน้าของเราดียิ่งขึ้น your_car, your_jet and your_scooterก่อนหน้านี้เราใช้วิธีการที่อยู่ในวัตถุรถยนต์และใช้มันเพื่อให้ ตอนนี้ลองนึกภาพว่าเราต้องการแยกจากpush_button_engineStartกันเพื่อเริ่มรถยนต์ของเราทีละขั้นตอนของการประหารชีวิตที่เราต้องการ

var scooty_engineStart = automobile.push_button_engineStart.bind(your_scooter);
var car_engineStart = automobile.push_button_engineStart.bind(your_car);
var jet_engineStart = automobile.push_button_engineStart.bind(your_jet);


setTimeout(scooty_engineStart,5000,30);
setTimeout(car_engineStart,10000,40);
setTimeout(jet_engineStart,15000,5);

ยังไม่พอใจใช่ไหม

มาทำให้ชัดเจนเหมือนหยดน้ำตา ใช้เวลาในการทดลอง เราจะกลับไปที่การโทรและใช้แอปพลิเคชันฟังก์ชั่นและลองเก็บค่าของฟังก์ชั่นเป็นข้อมูลอ้างอิง

การทดลองด้านล่างล้มเหลวเนื่องจากการเรียกและนำไปใช้ถูกเรียกใช้ทันทีดังนั้นเราจึงไม่เคยไปถึงขั้นตอนของการจัดเก็บการอ้างอิงในตัวแปรซึ่งเป็นที่ที่ฟังก์ชันการผูกจะขโมยการแสดง

var test_function = automobile.push_button_engineStart.apply(your_scooter);


3

การโทร: การโทรจะเรียกใช้ฟังก์ชันและอนุญาตให้คุณส่งอาร์กิวเมนต์แบบตัวต่อตัว

นำไปใช้:ใช้เรียกใช้ฟังก์ชันและอนุญาตให้คุณส่งอาร์กิวเมนต์เป็นอาร์เรย์

ผูก:ผูกส่งกลับฟังก์ชั่นใหม่ช่วยให้คุณสามารถผ่านในอาร์เรย์นี้และจำนวนของข้อโต้แย้งใด ๆ

var person1 = {firstName: 'Raju', lastName: 'king'};
var person2 = {firstName: 'chandu', lastName: 'shekar'};

function greet(greeting) {
    console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}
function greet2(greeting) {
        console.log( 'Hello ' + this.firstName + ' ' + this.lastName);
    }


greet.call(person1, 'Hello'); // Hello Raju king
greet.call(person2, 'Hello'); // Hello chandu shekar



greet.apply(person1, ['Hello']); // Hello Raju king
greet.apply(person2, ['Hello']); // Hello chandu shekar

var greetRaju = greet2.bind(person1);
var greetChandu = greet2.bind(person2);

greetRaju(); // Hello Raju king
greetChandu(); // Hello chandu shekar


2

โทร (): - ที่ นี่เราผ่านการขัดแย้งฟังก์ชั่นเป็นรายบุคคลไม่ได้อยู่ในรูปแบบอาร์เรย์

var obj = {name: "Raushan"};

var greeting = function(a,b,c) {
    return "Welcome "+ this.name + " to "+ a + " " + b + " in " + c;
};

console.log(greeting.call(obj, "USA", "INDIA", "ASIA"));

ใช้ (): - ที่ นี่เราผ่านข้อโต้แย้งฟังก์ชั่นในรูปแบบอาร์เรย์

var obj = {name: "Raushan"};

var cal = function(a,b,c) {
    return this.name +" you got " + a+b+c;
};

var arr =[1,2,3];  // array format for function arguments
console.log(cal.apply(obj, arr)); 

ผูก (): -

       var obj = {name: "Raushan"};

       var cal = function(a,b,c) {
            return this.name +" you got " + a+b+c;
       };

       var calc = cal.bind(obj);
       console.log(calc(2,3,4));

2

การโทรด้วย JavaScript ()

const person = {
    name: "Lokamn",
    dob: 12,
    print: function (value,value2) {
        console.log(this.dob+value+value2)
    }
}
const anotherPerson= {
     name: "Pappu",
     dob: 12,
}
 person.print.call(anotherPerson,1,2)

ใช้ JavaScript ()

    name: "Lokamn",
    dob: 12,
    print: function (value,value2) {
        console.log(this.dob+value+value2)
    }
}
const anotherPerson= {
     name: "Pappu",
     dob: 12,
}
 person.print.apply(anotherPerson,[1,2])

** ฟังก์ชั่นการโทรและการใช้งานคือการโทรที่แตกต่างกันรับอาร์กิวเมนต์ที่แยกกัน แต่ใช้อาร์เรย์เช่น: [1,2,3] **

ผูก JavaScript ()

    name: "Lokamn",
    dob: 12,
    anotherPerson: {
        name: "Pappu",
        dob: 12,
        print2: function () {
            console.log(this)
        }
    }
}

var bindFunction = person.anotherPerson.print2.bind(person)
 bindFunction()

1

ลองนึกภาพการผูกไม่สามารถใช้ได้ คุณสามารถสร้างมันได้อย่างง่ายดายดังนี้

var someFunction=...
var objToBind=....

var bindHelper =  function (someFunction, objToBind) {
    return function() {
        someFunction.apply( objToBind, arguments );
    };  
}

bindHelper(arguments);

1
    function sayHello() {
            //alert(this.message);
            return this.message;
    }
    var obj = {
            message: "Hello"
    };

    function x(country) {
            var z = sayHello.bind(obj);
            setTimeout(y = function(w) {
//'this' reference not lost
                    return z() + ' ' + country + ' ' + w;
            }, 1000);
            return y;
    }
    var t = x('India')('World');
    document.getElementById("demo").innerHTML = t;

0

แนวคิดหลักที่อยู่เบื้องหลังวิธีการทั้งหมดนี้คือฟังก์ชั่นการขุดวัตถุโบราณฟังก์ชั่น

การยืมฟังก์ชั่นช่วยให้เราสามารถใช้วิธีการของวัตถุหนึ่งกับวัตถุที่แตกต่างกันโดยไม่ต้องทำสำเนาของวิธีการนั้นและเก็บรักษาไว้ในสองแห่ง มันสามารถทำได้โดยการใช้ โทร() , . ใช้ () หรือ bind () ซึ่งทั้งหมดนี้มีอยู่เพื่อกำหนดวิธีการที่เรายืมอย่างชัดเจน

  1. การเรียกใช้ฟังก์ชันจะเรียกใช้ทันทีและอนุญาตให้คุณส่งผ่านข้อโต้แย้งทีละรายการ
  2. สมัครจะเรียกฟังก์ชั่นได้ทันทีและช่วยให้คุณสามารถที่จะผ่านในการขัดแย้งเป็นอาร์เรย์
  3. ผูกกลับฟังก์ชั่นใหม่และคุณสามารถเรียก / เรียกมันได้ทุกเวลาที่คุณต้องการโดยการเรียกใช้ฟังก์ชั่น

ด้านล่างเป็นตัวอย่างของวิธีการทั้งหมดนี้

let name =  {
    firstname : "Arham",
    lastname : "Chowdhury",
}
printFullName =  function(hometown,company){
    console.log(this.firstname + " " + this.lastname +", " + hometown + ", " + company)
}

โทร

อาร์กิวเมนต์แรกเช่นชื่อในวิธีการโทรอยู่เสมอการอ้างอิงถึงตัวแปร (นี้) และหลังจะเป็นตัวแปรฟังก์ชั่น

printFullName.call(name,"Mumbai","Taufa");     //Arham Chowdhury, Mumbai, Taufa

ใช้

ใช้วิธีการเช่นเดียวกับวิธีการโทรที่แตกต่างกันเพียงอย่างเดียวคือฟังก์ชั่นข้อโต้แย้งจะถูกส่งผ่านในรายการอาร์เรย์

printFullName.apply(name, ["Mumbai","Taufa"]);     //Arham Chowdhury, Mumbai, Taufa

ผูก

วิธีการผูกเป็นเช่นเดียวกับการโทรยกเว้นว่าการผูกกลับฟังก์ชั่นที่สามารถนำมาใช้ในภายหลังโดยการเรียกมัน (ไม่เรียกทันที)

let printMyNAme = printFullName.bind(name,"Mumbai","Taufa");

printMyNAme();      //Arham Chowdhury, Mumbai, Taufa

printMyNAme () เป็นฟังก์ชันที่เรียกใช้ฟังก์ชัน

ด้านล่างคือลิงค์สำหรับ jsfiddle

https://codepen.io/Arham11/pen/vYNqExp


-1

ฉันคิดว่าสถานที่เดียวกันของพวกเขาคือ: พวกเขาทั้งหมดสามารถเปลี่ยนค่าของฟังก์ชั่นนี้ความแตกต่างของพวกเขาคือ: ฟังก์ชั่นการผูกจะกลับมาฟังก์ชั่นใหม่เป็นผล; วิธีการเรียกและนำไปใช้จะดำเนินการฟังก์ชั่นได้ทันที แต่การใช้สามารถรับอาร์เรย์เป็น params และมันจะแยกอาร์เรย์ที่แยกออกจากกันและยังฟังก์ชั่นการผูกสามารถ Currying


-3

ฟังก์ชั่นการผูกควรใช้เมื่อเราต้องการกำหนดฟังก์ชั่นที่มีบริบทเฉพาะสำหรับเช่น

var demo = {
           getValue : function(){ 
             console.log('demo object get value       function') 
            }
           setValue : function(){  
              setTimeout(this.getValue.bind(this),1000)           
           }
 }

ในตัวอย่างด้านบนถ้าเราเรียกใช้ฟังก์ชั่น demo.setValue () และส่งผ่านฟังก์ชั่น this.getValue โดยตรงจากนั้นมันจะไม่เรียกใช้ฟังก์ชัน ฟังก์ชั่นการใช้ผูก มันหมายความว่าเราส่งผ่านฟังก์ชั่นที่มีบริบทของวัตถุตัวอย่างเท่านั้นไม่เรียกใช้ฟังก์ชันที่เรียกใช้

หวังว่าคุณจะเข้าใจ

สำหรับข้อมูลเพิ่มเติมโปรดดู ฟังก์ชั่นผูก javascript รู้ในรายละเอียด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.