ฉันต้องการทราบวิธีการแสดงรายการวิธีการทั้งหมดที่มีอยู่สำหรับวัตถุเช่น:
alert(show_all_methods(Math));
สิ่งนี้ควรพิมพ์:
abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random,round, sin, sqrt, tan, …
ฉันต้องการทราบวิธีการแสดงรายการวิธีการทั้งหมดที่มีอยู่สำหรับวัตถุเช่น:
alert(show_all_methods(Math));
สิ่งนี้ควรพิมพ์:
abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random,round, sin, sqrt, tan, …
คำตอบ:
คุณสามารถใช้Object.getOwnPropertyNames()
เพื่อรับคุณสมบัติทั้งหมดที่เป็นของวัตถุไม่ว่าจะนับได้หรือไม่ ตัวอย่างเช่น:
console.log(Object.getOwnPropertyNames(Math));
//-> ["E", "LN10", "LN2", "LOG2E", "LOG10E", "PI", ...etc ]
จากนั้นคุณสามารถใช้filter()
เพื่อรับวิธีการเท่านั้น:
console.log(Object.getOwnPropertyNames(Math).filter(function (p) {
return typeof Math[p] === 'function';
}));
//-> ["random", "abs", "acos", "asin", "atan", "ceil", "cos", "exp", ...etc ]
ในเบราว์เซอร์ ES3 (IE 8 และต่ำกว่า) คุณสมบัติของวัตถุในตัวนั้นไม่สามารถนับได้ วัตถุที่ชอบwindow
และdocument
ไม่ได้มีในตัวพวกมันถูกกำหนดโดยเบราว์เซอร์และน่าจะนับได้มากที่สุดจากการออกแบบ
จากECMA-262 Edition 3 :
วัตถุทั่วโลก
มีวัตถุสากลที่ไม่ซ้ำกัน (15.1) ซึ่งถูกสร้างขึ้นก่อนที่การควบคุมเข้าสู่บริบทการดำเนินการใด ๆ เริ่มแรกวัตถุทั่วโลกมีคุณสมบัติดังต่อไปนี้:•ในตัววัตถุเช่นคณิตศาสตร์, String, วันที่, parseInt ฯลฯแอตทริบิวต์เหล่านี้มี {}
•คุณสมบัติที่กำหนดไว้สำหรับโฮสต์เพิ่มเติม ซึ่งอาจรวมถึงคุณสมบัติที่มีค่าเป็นวัตถุทั่วโลกเอง; ตัวอย่างเช่นในโมเดลวัตถุเอกสาร HTML คุณสมบัติหน้าต่างของวัตถุทั่วโลกเป็นวัตถุทั่วโลกเองเมื่อตัวควบคุมเข้าสู่บริบทการดำเนินการและเมื่อประมวลผลรหัส ECMAScript อาจมีการเพิ่มคุณสมบัติเพิ่มเติมลงในวัตถุส่วนกลางและคุณสมบัติเริ่มต้นอาจมีการเปลี่ยนแปลง
ฉันควรชี้ให้เห็นว่าสิ่งนี้หมายความว่าวัตถุเหล่านั้นไม่ใช่คุณสมบัติที่นับได้ของวัตถุทั่วโลก หากคุณดูเอกสารข้อมูลจำเพาะที่เหลือคุณจะเห็นคุณสมบัติและวิธีการในตัวของวัตถุเหล่านี้ส่วนใหญ่มี{ DontEnum }
คุณสมบัติที่กำหนดไว้
อัปเดต: ผู้ใช้ CMS คนอื่น ๆ ได้นำข้อผิดพลาด IE เกี่ยวกับ{ DontEnum }
ความสนใจของฉัน
แทนที่จะตรวจสอบแอตทริบิวต์ DontEnum [Microsoft] JScript จะข้ามคุณสมบัติใด ๆ ในวัตถุใด ๆ ที่มีคุณสมบัติชื่อเดียวกันในห่วงโซ่ต้นแบบของวัตถุที่มีแอตทริบิวต์ DontEnum
ในระยะสั้นระวังเมื่อตั้งชื่อคุณสมบัติวัตถุของคุณ หากมีคุณสมบัติต้นแบบหรือวิธีการในตัวที่มีชื่อเดียวกัน IE จะข้ามไปเมื่อใช้for...in
ลูป
Object.getOwnPropertyNames()
ซึ่งจะส่งคืนคุณสมบัติและเมธอดที่ไม่สามารถนับได้
Object.getOwnPropertyNames(Array.prototype)
ไหมถ้าทำอย่างนั้น
ไม่สามารถใช้ ES3 ได้เนื่องจากคุณสมบัติมีDontEnum
แอตทริบิวต์ภายในซึ่งทำให้เราไม่สามารถระบุคุณสมบัติเหล่านี้ได้ ในทางตรงกันข้าม ES5 จัดเตรียม descriptor คุณสมบัติสำหรับการควบคุมความสามารถในการแจงนับของคุณสมบัติเพื่อให้ผู้ใช้กำหนดและคุณสมบัติเนทิฟสามารถใช้อินเทอร์เฟซเดียวกันและเพลิดเพลินไปกับความสามารถเดียวกันซึ่งรวมถึงการดูคุณสมบัติที่ไม่นับด้วยโปรแกรม
getOwnPropertyNames
ฟังก์ชั่นสามารถนำมาใช้เพื่อระบุมากกว่าคุณสมบัติทั้งหมดที่ส่งผ่านในวัตถุรวมทั้งผู้ที่ไม่ได้นับ จากนั้นtypeof
สามารถใช้การตรวจสอบอย่างง่ายเพื่อกรองข้อมูลที่ไม่ใช่ฟังก์ชั่น น่าเสียดายที่ Chrome เป็นเบราว์เซอร์เดียวที่ใช้งานได้ในปัจจุบัน
function getAllMethods(object) {
return Object.getOwnPropertyNames(object).filter(function(property) {
return typeof object[property] == 'function';
});
}
console.log(getAllMethods(Math));
บันทึก["cos", "pow", "log", "tan", "sqrt", "ceil", "asin", "abs", "max", "exp", "atan2", "random", "round", "floor", "acos", "atan", "min", "sin"]
ในลำดับใดไม่มี
var methods = [];
for (var m in obj) {
if (typeof obj[m] == "function") {
methods.push(m);
}
}
alert(methods.join(","));
obj
วิธีนี้คุณจะได้รับวิธีการทั้งหมดที่คุณสามารถเรียกร้อง ซึ่งรวมถึงวิธีการที่ "สืบทอด" จากต้นแบบ (เช่นgetMethods()
ใน java) หากคุณต้องการดูวิธีการที่กำหนดโดยตรงเท่านั้นobj
คุณสามารถตรวจสอบกับhasOwnProperty
:
var methods = [];
for (var m in obj) {
if (typeof obj[m] == "function" && obj.hasOwnProperty(m)) {
methods.push(m);
}
}
alert(methods.join(","));
document
หรือwindow
ฉันโชคดี ตรงไปตรงมามันเป็นสิ่งที่คาดไม่ถึงฉันไม่รู้ว่าทำไมมันไม่ทำงานกับคณิตศาสตร์เป็นต้น
document
และwindow
เป็นวัตถุที่มีคุณสมบัติมากมายที่จัดทำโดยเบราว์เซอร์พวกเขาไม่ได้เป็นส่วนหนึ่งของรันไทม์สคริปต์ วัตถุพื้นเมืองเป็นและแน่นอนคุณสมบัติไม่นับ
การสนับสนุนเบราว์เซอร์ที่ทันสมัยส่วนใหญ่console.dir(obj)
ซึ่งจะส่งคืนคุณสมบัติทั้งหมดของวัตถุที่สืบทอดผ่านตัวสร้าง ดูเอกสารประกอบของ Mozilla สำหรับข้อมูลเพิ่มเติมและการสนับสนุนเบราว์เซอร์ปัจจุบัน
console.dir(Math)
=> MathConstructor
E: 2.718281828459045
LN2: 0.6931471805599453
...
tan: function tan() { [native code] }
__proto__: Object
คำตอบอื่น ๆ ที่นี่ทำงานกับคณิตศาสตร์เช่นซึ่งเป็นวัตถุคงที่ แต่มันจะไม่ทำงานสำหรับอินสแตนซ์ของวัตถุเช่นวันที่ ฉันพบสิ่งต่อไปนี้ในการทำงาน:
function getMethods(o) {
return Object.getOwnPropertyNames(Object.getPrototypeOf(o))
.filter(m => 'function' === typeof o[m])
}
//example: getMethods(new Date()): [ 'getFullYear', 'setMonth', ... ]
https://jsfiddle.net/3xrsead0/
วิธีนี้ใช้ไม่ได้กับคำถามเดิม (คณิตศาสตร์) ดังนั้นให้เลือกวิธีการแก้ปัญหาตามความต้องการของคุณ ฉันโพสต์สิ่งนี้ที่นี่เพราะ Google ส่งคำถามนี้ให้ฉัน แต่ฉันต้องการทราบวิธีการทำเช่นนี้สำหรับอินสแตนซ์ของวัตถุ
คำตอบสั้น ๆ คือคุณทำไม่ได้เพราะMath
และDate
(จากส่วนหัวของฉันฉันแน่ใจว่ามีคนอื่น) ไม่ใช่วัตถุธรรมดา หากต้องการดูสิ่งนี้ให้สร้างสคริปต์ทดสอบอย่างง่าย:
<html>
<body>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
alert("Math: " + Math);
alert("Math: " + Math.sqrt);
alert("Date: " + Date);
alert("Array: " + Array);
alert("jQuery: " + jQuery);
alert("Document: " + document);
alert("Document: " + document.ready);
});
</script>
</body>
</html>
คุณเห็นมันนำเสนอเป็นวัตถุแบบเดียวกับที่เอกสารทำโดยรวม แต่เมื่อคุณลองและดูในวัตถุนั้นจริง ๆ คุณจะเห็นว่ามันเป็นรหัสเนทีฟ
Math
มีวิธีการแบบคงที่คุณสามารถเรียกโดยตรงเช่นMath.abs()
ในขณะที่Date
มีวิธีการคงเหมือนDate.now()
และวิธีการเช่นที่คุณจำเป็นต้องสร้างตัวอย่างใหม่ครั้งแรกต่อการเรียกร้องvar time = new Date()
time.getHours()
// The instance method of Date can be found on `Date.prototype` so you can just call:
var keys = Object.getOwnPropertyNames(Date.prototype);
// And for the static method
var keys = Object.getOwnPropertyNames(Date);
// But if the instance already created you need to
// pass its constructor
var time = new Date();
var staticKeys = Object.getOwnPropertyNames(time.constructor);
var instanceKeys = Object.getOwnPropertyNames(time.constructor.prototype);
แน่นอนคุณจะต้องกรองคีย์ที่ได้รับสำหรับวิธีการแบบสแตติกเพื่อรับชื่อวิธีการที่แท้จริงเนื่องจากคุณสามารถรับlength, name
ที่ไม่ใช่ฟังก์ชันในรายการ
แต่ถ้าเราต้องการได้รับวิธีการที่ใช้ได้ทั้งหมดจากคลาสที่ขยายคลาสอื่น?
แน่นอนคุณจะต้องสแกนผ่านรากของต้นแบบเช่นการใช้
__proto__
เพื่อประหยัดเวลาของคุณคุณสามารถใช้สคริปต์ด้านล่างเพื่อรับวิธีแบบคงที่และวิธีการแบบลึก
// var keys = new Set();
function getStaticMethods(keys, clas){
var keys2 = Object.getOwnPropertyNames(clas);
for(var i = 0; i < keys2.length; i++){
if(clas[keys2[i]].constructor === Function)
keys.add(keys2[i]);
}
}
function getPrototypeMethods(keys, clas){
if(clas.prototype === void 0)
return;
var keys2 = Object.getOwnPropertyNames(clas.prototype);
for (var i = keys2.length - 1; i >= 0; i--) {
if(keys2[i] !== 'constructor')
keys.add(keys2[i]);
}
var deep = Object.getPrototypeOf(clas);
if(deep.prototype !== void 0)
getPrototypeMethods(keys, deep);
}
// ====== Usage example ======
// To avoid duplicate on deeper prototype we use `Set`
var keys = new Set();
getStaticMethods(keys, Date);
getPrototypeMethods(keys, Date);
console.log(Array.from(keys));
หากคุณต้องการได้รับวิธีการจากอินสแตนซ์ที่สร้างอย่าลืมที่จะผ่านconstructor
มัน
ฉันเชื่อว่ามีเหตุผลทางประวัติศาสตร์ที่เรียบง่ายว่าทำไมคุณไม่สามารถระบุวิธีการของวัตถุในตัวเช่น Array ได้ นี่คือเหตุผล:
เมธอดคือคุณสมบัติของต้นแบบวัตถุพูด Object.prototype นั่นหมายความว่าวัตถุ - อินสแตนซ์ทั้งหมดจะสืบทอดวิธีการเหล่านั้น นั่นเป็นเหตุผลที่คุณสามารถใช้วิธีการเหล่านั้นกับวัตถุใด ๆ ตัวอย่างเช่น. toString ()
ดังนั้นหากวิธีการนับได้และฉันจะพูดซ้ำมากกว่า {a: 123} ด้วย: "สำหรับ (คีย์ใน {a: 123}) {... }" จะเกิดอะไรขึ้น ลูปนั้นจะถูกดำเนินการกี่ครั้ง?
มันจะถูกทำซ้ำหนึ่งครั้งสำหรับปุ่มเดียว 'a' ในตัวอย่างของเรา แต่ยังหนึ่งครั้งสำหรับทุกคุณสมบัตินับจำนวนของ Object.prototype ดังนั้นหากวิธีการนับจำนวน (โดยค่าเริ่มต้น) แล้วห่วงใด ๆ มากกว่าวัตถุใด ๆ จะห่วงมากกว่าวิธีการสืบทอดทั้งหมดของมันเช่นกัน
Object.getOwnPropertyNames(Array.prototype)
เช่น