เมื่อวานฉันไปสัมภาษณ์ และมี gg ถามฉันเกี่ยวกับความรู้เกี่ยวกับ js บ้าง มีคำถามเกี่ยวกับการใช้ call และ Apply แม้ว่าฉันจะเคยใช้วิธี call เมื่อ 365 วันก่อน แต่ก็ยังไม่สามารถตอบได้ วันนั้นผมจะสรุปแบบเจาะลึกในวันนี้
โทรและนำไปใช้ ฟังก์ชันคือการผูกฟังก์ชันกับวัตถุอื่นเพื่อเรียกใช้
คำจำกัดความรูปแบบและพารามิเตอร์ของทั้งสอง:
โทร ( thisArg [, arg1, arg2, ... ] ); // รายการพารามิเตอร์, arg1, arg2, ...
ใช้ (thisArg [, argArray] ); // อาร์เรย์พารามิเตอร์, argArray
ตัวชี้นี้ภายในสองฟังก์ชันข้างต้นจะได้รับการกำหนด thisArg ซึ่งสามารถตระหนักถึงวัตถุประสงค์ของการเรียกใช้ฟังก์ชันเป็นวิธีการของวัตถุอื่น
1. การใช้งานการโทรที่เรียบง่าย
ก่อนอื่น มาดูตัวอย่างง่ายๆ (การโทร):
คัดลอกรหัสรหัสดังต่อไปนี้:
<!doctype html>
<html>
<หัว>
<title> โทรสมัคร </title>
</หัว>
<ร่างกาย>
<input type="text" id="idTxt" value="input text">
<script type="text/javascript">
ค่า var = "var สากล";
ฟังก์ชัน mFunc()
-
this.value = "สมาชิก var";
-
ฟังก์ชั่น gFunc()
-
การแจ้งเตือน (this.value);
-
window.gFunc();// แสดง gFunc, global var
gFunc.call(window);// แสดง gFunc, global var
gFunc.call(new mFunc());// แสดง mFunc, สมาชิก var
gFunc.call(document.getElementById('idTxt'));// แสดงองค์ประกอบ, ป้อนข้อความ
</สคริปต์>
<ภาษาสคริปต์ = "จาวาสคริปต์">
var func = ฟังก์ชั่นใหม่ ()
-
this.a = "ฟังก์ชั่น";
-
var func2 = ฟังก์ชัน(x)
-
var a = "func2";
การแจ้งเตือน (this.a);
การแจ้งเตือน(x);
-
func2.call(func, "func2");// แสดง func และ func2
</สคริปต์>
</ร่างกาย>
</html>
จากนั้นผลการวิ่งจะเป็นดังนี้:
เวอร์ชันสากลเวอร์ชันสากล
สมาชิก var
ป้อนข้อความ
ฟังก์ชั่น
ฟังก์ชั่น2
สภาพแวดล้อมการทดสอบ: Google Chrome10.0.648.45
สุดท้ายวิเคราะห์ผลลัพธ์
1. หน้าต่างวัตถุส่วนกลางเรียกใช้ฟังก์ชัน gFunc และชี้ไปที่วัตถุหน้าต่าง ดังนั้น this.value จึงเป็น global var
2. ฟังก์ชัน gFunc เรียกใช้เมธอดการโทร ซึ่งจะชี้ไปที่ออบเจ็กต์หน้าต่างพารามิเตอร์แรกตามค่าเริ่มต้น ดังนั้น this.value จึงเป็น var ส่วนกลางด้วย
3. ฟังก์ชัน gFunc เรียกใช้เมธอดการโทร ซึ่งจะมีค่าเริ่มต้นเป็นพารามิเตอร์ตัวแรก new mFunc() ซึ่งเป็นอ็อบเจ็กต์ของ mFunc
4. ฟังก์ชัน gFunc เรียกวิธีการเรียก ตามค่าเริ่มต้น สิ่งนี้จะชี้ไปที่ตัวควบคุมข้อความอินพุตพารามิเตอร์แรก นั่นคือ ตัวควบคุมที่มี id='idTxt' ดังนั้น this.value จึงเป็นข้อความอินพุตค่าของตัวควบคุมอินพุต
5. ฟังก์ชัน func2 เรียกวิธีการเรียก นี่เป็นค่าเริ่มต้นที่วัตถุฟังก์ชัน func พารามิเตอร์แรก ดังนั้น this.value จึงเป็น this.a ซึ่งก็คือ func
6. ฟังก์ชั่น func2 เรียกวิธีการโทร พารามิเตอร์ตัวที่สองเป็นของพารามิเตอร์ของฟังก์ชันวัตถุ func2 ดังนั้น alert(x) จึงเป็นพารามิเตอร์ตัวที่สอง func2
2. เรียกการใช้และการปรับปรุงการสืบทอด
js ใช้การเรียกเพื่อจำลองการสืบทอด
รหัสทดสอบ:
คัดลอกรหัสรหัสดังต่อไปนี้:
<!doctype html>
<html>
<หัว>
<title> โทร - สมัครเพื่อรับมรดก </title>
</หัว>
<ร่างกาย>
<script type="text/javascript">
ฟังก์ชั่น baseA()// คลาสฐาน A
-
this.member = "สมาชิก baseA";
this.showSelfA = ฟังก์ชั่น()
-
window.alert(นี้.สมาชิก);
-
-
ฟังก์ชั่น baseB()// เบสคลาส B
-
this.member = "สมาชิก baseB";
this.showSelfB = ฟังก์ชั่น()
-
window.alert(นี้.สมาชิก);
-
-
ฟังก์ชั่นขยาย AB()// สืบทอดคลาสจาก A และ B
-
baseA.call(this);// เรียกหา A
baseB.call(this);// เรียก B
-
window.onload = ฟังก์ชั่น()
-
var ขยาย = ขยาย AB ใหม่ ();
extension.showSelfA();// แสดง A
extension.showSelfB();// แสดง B
-
</สคริปต์>
</ร่างกาย>
</html>
ผลการวิ่งมีดังนี้:สมาชิกฐานบี
สมาชิกฐานบี
สภาพแวดล้อมการทดสอบ: Google Chrome10.0.648.45
การวิเคราะห์ผลลัพธ์:
ผลลัพธ์ที่คาดหวังควรเป็นของเอาต์พุตสมาชิก baseA และสมาชิก baseB แต่เอาต์พุตจริงคือสมาชิก baseB และสมาชิก baseB
(ได้รับการทดสอบใน IE9, 8, 6, Maxthon, Chrome, FF, Opera, Safari, 360 และเบราว์เซอร์อื่น ๆ และผลลัพธ์ที่ได้คืออย่างหลัง: สมาชิก baseB)
ณ จุดนี้เครื่องจักรไม่ผิดที่ต้องวิเคราะห์เชิงลึก
เราอาจคิดง่ายๆ ว่ามันมีสาเหตุมาจากสิ่งนี้ สิ่งนี้ชี้ไปที่วัตถุ baseB สองครั้ง แต่เป็นเช่นนั้นจริงหรือ
เพื่อสำรวจสาระสำคัญ เราใช้เครื่องมือแก้ไขข้อบกพร่องของเบราว์เซอร์ Chrome เพื่อตั้งค่าเบรกพอยต์และแก้ไขข้อบกพร่อง และพบว่า:
เมื่อเรียก extend.showSelfA(); สิ่งนี้จะชี้ไปที่ขยาย AB (ไม่ใช่ไปที่วัตถุ baseB ตามที่เราคาดเดาสองครั้ง)
เหตุผลที่แท้จริงก็คือ สมาชิกตัวแปรสมาชิกของอ็อบเจ็กต์ขยาย AB ถูกเขียนทับโดยสมาชิกสมาชิกของ baseB เมื่อมันถูกสร้างอินสแตนซ์โดย baseB.call(this) นั่นคือ สมาชิกสมาชิกของ extendAB ถูกกำหนดจากสมาชิก baseA ไปยัง สมาชิกฐานบี
แน่นอนว่า เราสามารถแก้ไขโค้ด baseA ด้านบนได้เล็กน้อยเพื่อตรวจสอบความถูกต้องของการวิเคราะห์การดีบักของเรา:
คัดลอกรหัสรหัสดังต่อไปนี้:
ฟังก์ชั่น baseA()// คลาสฐาน A
-
this.memberA = "baseA member"; // เปลี่ยนสมาชิกเป็น memberA เพื่อแยกแยะสมาชิกใน baseB
this.showSelfA = ฟังก์ชั่น()
-
window.alert(this.memberA); // แสดง memberA
-
-
เรียกใช้เบราว์เซอร์เช่น Chrome อีกครั้ง ผลลัพธ์จะเป็นดังนี้:
สมาชิกฐาน A
สมาชิกฐานบี
ผลลัพธ์เหมือนกับที่เราคาดไว้ และข้อมูลการแก้ไขข้อบกพร่องของ Chrome ยังยืนยันความถูกต้องของเราด้วย:
การปรับปรุงการสืบทอด (ต้นแบบ)
วิธีการจำลองการสืบทอดข้างต้นไม่ใช่วิธีที่ดีที่สุดหลังจากการวิเคราะห์อย่างรอบคอบ
เนื่องจากทุกครั้งที่กำหนดเมธอดสมาชิกในฟังก์ชัน (คลาส) จะทำให้เกิดสำเนาของอินสแตนซ์ ดังนั้นคุณจึงใช้ต้นแบบต้นแบบเพื่อทำการปรับปรุงได้
ตัวอย่างของการปรับปรุงมีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
<!doctype html>
<html>
<หัว>
<title> โทร - สมัครต้นแบบ </title>
</หัว>
<ร่างกาย>
<script type="text/javascript">
วาร์คลาส = {
สร้าง: function()// สร้าง Function
-
ฟังก์ชันส่งคืน()
-
this.initialize.apply (สิ่งนี้ ข้อโต้แย้ง);
-
-
-
var Person = Class.create();// สร้างคลาส Person
Person.prototype = {// เริ่มต้นต้นแบบ
เริ่มต้น: ฟังก์ชั่น (obj1, obj2)
-
นี้.obj1 = obj1;
นี้.obj2 = obj2;
-
showSelf: ฟังก์ชั่น ()
-
alert("obj: " + this.obj1 + " และ " + this.obj2);
-
-
// คลาสอินสแตนซ์
var person = บุคคลใหม่ ("ชาย", "ผู้หญิง");// สองพารามิเตอร์
person.showSelf();// แสดงบุคคล
</สคริปต์>
</ร่างกาย>
</html>
ผลการวิ่งมีดังนี้:
obj: ชายและหญิง