Getters \ setters สำหรับ Dummies


135

ฉันพยายามทำให้หัวของฉันอยู่รอบ ๆ getters และ setters และมันก็ไม่จมลงไปฉันอ่านJavaScript Getters and SettersและDefining Getters and Settersแต่ก็ไม่เข้าใจ

ใครสามารถระบุอย่างชัดเจน:

  1. สิ่งที่ผู้เริ่มต้นและผู้ตั้งถิ่นฐานตั้งใจจะทำและ
  2. ยกตัวอย่างง่ายๆบางอย่าง?

12
โดยส่วนตัวฉันไม่รู้ว่าคุณจะได้รับคำอธิบายที่ชัดเจนกว่าของจอห์นอย่างไร ...
Jason Bunting

ในโลก OO ให้ getter และ setter ช่วยเขียนคลาสที่ถูกห่อหุ้มอย่างถูกต้อง
เปลี่ยนแปลงที่มากเกินไป

โดยทั่วไปฉันเห็นแบบนี้คุณกำลังกำหนดโอเวอร์โหลดสำหรับรับและตั้งค่าคุณสมบัติและโอเวอร์โหลดเหล่านี้เป็นฟังก์ชัน แต่คุณไม่จำเป็นต้องโทรหาพวกเขา วิธีนี้คุณสามารถแทนที่a = setValue(5);ด้วยa = 5;และsetValue()จึงจะเรียกว่าภายใต้ประทุนที่จะทำสิ่งที่คุณต้องการ
Andrew

คำตอบ:


102

นอกจากคำตอบของ @ millimooseแล้ว setters ยังสามารถใช้เพื่ออัปเดตค่าอื่น ๆ

function Name(first, last) {
    this.first = first;
    this.last = last;
}

Name.prototype = {
    get fullName() {
        return this.first + " " + this.last;
    },

    set fullName(name) {
        var names = name.split(" ");
        this.first = names[0];
        this.last = names[1];
    }
};

ตอนนี้คุณสามารถตั้งค่าfullNameและfirstและlastจะมีการปรับปรุงและในทางกลับกัน

n = new Name('Claude', 'Monet')
n.first # "Claude"
n.last # "Monet"
n.fullName # "Claude Monet"
n.fullName = "Gustav Klimt"
n.first # "Gustav"
n.last # "Klimt"

2
@Akash: ไม่แม้ว่า Internet Explorer 9 จะรองรับObject.definePropertyฟังก์ชันใหม่กว่าที่สามารถกำหนด getters และ setters ได้
Matthew Crumley

9
ไม่เจ็บปวดจริงๆที่ MS ไม่สนับสนุน JS อย่างถูกต้องและพวกเขาไม่ทำให้ Silverlight ทำงานทุกที่ดังนั้นฉันต้องตั้งโปรแกรมทุกอย่างสองครั้งสำหรับ SL และอีกอันสำหรับส่วนที่เหลือของโลก :)
Akash Kava

2
@ Martin: คุณสามารถทำให้พวกเขาส่วนตัวโดยใช้เทคนิคเดียวกับในคำตอบของจอห์น หากคุณต้องการใช้ getters / setters จริงคุณจะต้องใช้this.__defineGetter__หรือObject.definePropertyฟังก์ชันที่ใหม่กว่า
Matthew Crumley

1
มีปัญหาเดียวกับวิธีการที่ระบุไว้ข้างต้นหากคุณต้องการเพิ่ม getters และ setters สำหรับคลาสที่มีอยู่แล้วระบบจะลบล้างต้นแบบและเมธอดดั้งเดิมจะไม่สามารถเข้าถึงได้
xchg.ca

1
วิธีนี้ไม่ได้เขียนทับName.prototype.constructor? ดูเหมือนจะเป็นทางเลือกที่ไม่ดีสำหรับคำตอบของมิลลิโม
r0estir0bbe

63

Getters และ Setters ใน JavaScript

ภาพรวม

Getters และ setters ใน JavaScript ถูกนำมาใช้สำหรับการกำหนดคุณสมบัติคำนวณหรือaccessors คุณสมบัติที่คำนวณคือคุณสมบัติที่ใช้ฟังก์ชันเพื่อรับหรือตั้งค่าวัตถุ ทฤษฎีพื้นฐานกำลังทำสิ่งนี้:

var user = { /* ... object with getters and setters ... */ };
user.phone = '+1 (123) 456-7890'; // updates a database
console.log( user.areaCode ); // displays '123'
console.log( user.area ); // displays 'Anytown, USA'

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

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

รับ / ตั้งค่าคำหลัก

ECMAScript 5 รองรับgetและsetคำสำคัญสำหรับการกำหนดคุณสมบัติที่คำนวณ ทำงานร่วมกับเบราว์เซอร์ที่ทันสมัยทั้งหมดยกเว้น IE 8 และต่ำกว่า

var foo = {
    bar : 123,
    get bar(){ return bar; },
    set bar( value ){ this.bar = value; }
};
foo.bar = 456;
var gaz = foo.bar;

ผู้รับและ Setters ที่กำหนดเอง

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

var foo = {
    _bar : 123,
    get : function( name ){ return this[ '_' + name ]; },
    set : function( name, value ){ this[ '_' + name ] = value; }
};
foo.set( 'bar', 456 );
var gaz = foo.get( 'bar' );

หรือเพื่อวิธีการที่กะทัดรัดยิ่งขึ้นอาจใช้ฟังก์ชันเดียว

var foo = {
    _bar : 123,
    value : function( name /*, value */ ){
        if( arguments.length < 2 ){ return this[ '_' + name ]; }
        this[ '_' + name ] = value;
    }
};
foo.value( 'bar', 456 );
var gaz = foo.value( 'bar' );

หลีกเลี่ยงการทำสิ่งนี้ซึ่งอาจทำให้โค้ดขยายตัวได้

var foo = {
    _a : 123, _b : 456, _c : 789,
    getA : function(){ return this._a; },
    getB : ..., getC : ..., setA : ..., setB : ..., setC : ...
};

สำหรับตัวอย่างข้างต้นชื่อคุณสมบัติภายในจะมีการขีดล่างเพื่อไม่ให้ผู้ใช้เพียงแค่ทำfoo.barเทียบกับfoo.get( 'bar' )และได้รับค่าที่ "ไม่ได้ปรุง" คุณสามารถใช้โค้ดเงื่อนไขเพื่อทำสิ่งต่างๆได้โดยขึ้นอยู่กับชื่อของคุณสมบัติที่เข้าถึง (ผ่านnameพารามิเตอร์)

Object.defineProperty ()

การใช้Object.defineProperty()เป็นอีกวิธีหนึ่งในการเพิ่ม getters และ setters และสามารถใช้กับอ็อบเจกต์หลังจากกำหนดได้แล้ว นอกจากนี้ยังสามารถใช้เพื่อตั้งค่าพฤติกรรมที่กำหนดและระบุได้ ไวยากรณ์นี้ใช้ได้กับ IE 8 ด้วย แต่น่าเสียดายที่มีเฉพาะวัตถุ DOM เท่านั้น

var foo = { _bar : 123 };
Object.defineProperty( foo, 'bar', {
    get : function(){ return this._bar; },
    set : function( value ){ this._bar = value; }
} );
foo.bar = 456;
var gaz = foo.bar;

__defineGetter __ ()

สุดท้าย__defineGetter__()เป็นอีกทางเลือกหนึ่ง เลิกใช้แล้ว แต่ยังคงใช้กันอย่างแพร่หลายในเว็บจึงไม่น่าจะหายไปในเร็ว ๆ นี้ ใช้งานได้กับทุกเบราว์เซอร์ยกเว้น IE 10 และต่ำกว่า แม้ว่าตัวเลือกอื่น ๆ จะทำงานได้ดีบนที่ไม่ใช่ IE ด้วยดังนั้นตัวเลือกนี้จึงไม่มีประโยชน์

var foo = { _bar : 123; }
foo.__defineGetter__( 'bar', function(){ return this._bar; } );
foo.__defineSetter__( 'bar', function( value ){ this._bar = value; } );

สิ่งที่น่าสังเกตก็คือในตัวอย่างหลัง ๆ ชื่อภายในจะต้องแตกต่างจากชื่อผู้เข้าถึงเพื่อหลีกเลี่ยงการเรียกซ้ำ (เช่นการfoo.barโทรfoo.get(bar)เรียกการfoo.barโทรfoo.get(bar)... )

ดูสิ่งนี้ด้วย

MDN get , set , Object.defineProperty () , __defineGetter __ () , __defineSetter __ ()
MSDN IE8 Getter Support


1
ในแนวทางที่กะทัดรัดกว่านั้นthis[ '_' + name ] = value;อาจเป็นได้this[ '_' + name ] = arguments[1];และไม่จำเป็นต้องระบุvalueอาร์กิวเมนต์
Redhart

1
ตัวอย่าง: var foo = { bar : 123, get bar(){ return bar; }, set bar( value ){ this.bar = value; } }; foo.bar = 456; ยกข้อยกเว้น: Uncaught RangeError: ขนาดสแต็กการเรียกสูงสุดเกินที่ Object.set bar [เป็น bar] (<anonymous>: 4: 32) ที่ Object.set bar [as bar] (<anonymous>: 4: 32 ) ที่ Object.set bar [as bar] (<anonymous>: 4: 32) ที่ Object.set bar [as bar] (<anonymous>: 4: 32) ที่ Object.set bar [as bar] (<anonymous> : 4: 32) ที่ Object.set bar [as bar] (<anonymous>: 4: 32)
nevf

2
ชื่อ set / get ต้องแตกต่างจากชื่อคุณสมบัติ ดังนั้นแทนที่จะเป็นbar: 123และthis.bar = valueอื่น ๆ เปลี่ยนสิ่งเหล่านี้เป็น_bar ตัวอย่าง ดู: hongkiat.com/blog/getters-setters-javascript
nevf

@nevf ขอบคุณสำหรับการแก้ไข! ใช่โดยปกติจะมีคุณสมบัติการคำนวณ "ของจริง" ภายในหนึ่งเป็นชื่อเหมือนหรือ_foo mFooถ้ามันเหมือนกับ getter / setter มันจะทำให้เกิดการวนซ้ำแบบไม่มีที่สิ้นสุดเนื่องจากการวนซ้ำและ Stack Overflow ™ ;-) เพราะเมื่อคุณพูดว่า a = b มันจะเรียก a.get (b) ซึ่งตัวเองเรียกว่า a = b ซึ่งเรียก a.get (b), ...
Beejor

58

คุณจะใช้มันเพื่อใช้คุณสมบัติที่คำนวณ

ตัวอย่างเช่น:

function Circle(radius) {
    this.radius = radius;
}

Object.defineProperty(Circle.prototype, 'circumference', {
    get: function() { return 2*Math.PI*this.radius; }
});

Object.defineProperty(Circle.prototype, 'area', {
    get: function() { return Math.PI*this.radius*this.radius; }
});

c = new Circle(10);
console.log(c.area); // Should output 314.159
console.log(c.circumference); // Should output 62.832

(CodePen)


โอเคฉันคิดว่าฉันเริ่มเข้าใจแล้ว ฉันกำลังพยายามกำหนด getter ให้กับคุณสมบัติ length ของวัตถุอาร์เรย์ แต่ได้รับข้อผิดพลาด: "การประกาศความยาว var ซ้ำ" และรหัสมีลักษณะดังนี้: obj = []; obj .__ defineGetter __ ('length', function () (ส่งคืน this.length;});

1
นั่นเป็นเพราะวัตถุ Array มีคุณสมบัติความยาวในตัวอยู่แล้ว หากอนุญาตให้มีการประกาศซ้ำการเรียกความยาวใหม่จะเรียกคืนไม่สิ้นสุด ลองเรียกคุณสมบัติ "my_length" หรือบางอย่าง
มิลลิโมส

เพื่อกำหนด getters Object.definePropertiesทั้งในหนึ่งคำสั่งการใช้งาน
r0estir0bbe

คุณไม่สามารถสร้าง {"area": ​​function () {return ... }} ได้หรือ เพียงแค่กำหนดให้เป็นคุณสมบัติของวัตถุ
RegarBoy

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

16

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

Getter:

var settings = {
    firstname: 'John',
    lastname: 'Smith',
    get fullname() { return this.firstname + ' ' + this.lastname; }
};

console.log(settings.fullname);

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

เซ็ตเตอร์:

var address = {
    set raw(what) {
        var loc = what.split(/\s*;\s*/),
        area = loc[1].split(/,?\s+(\w{2})\s+(?=\d{5})/);

        this.street = loc[0];
        this.city = area[0];
        this.state = area[1];
        this.zip = area[2];
    }
};

address.raw = '123 Lexington Ave; New York NY  10001';
console.log(address.city);

... จะเข้าสู่New Yorkคอนโซล ชอบ getters, settersจะเรียกว่ามีไวยากรณ์เช่นเดียวกับการตั้งค่าวัตถุคุณสมบัติ แต่ยังวิธีแฟนซีอื่นเพื่อเรียกฟังก์ชั่นโดยไม่ต้อง ()

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


ฉันยังไม่เข้าใจประโยชน์ของการใช้ get and set เทียบกับการสร้าง getMethod หรือ setMethod ประโยชน์เพียงอย่างเดียวที่คุณสามารถเรียกได้ว่าไม่มี ()? ต้องมีเหตุผลอื่นที่เพิ่มลงในจาวาสคริปต์
Andreas

@Andreas Getters และ setters ทำตัวเหมือนคุณสมบัติเมื่อถูกเรียกซึ่งสามารถช่วยให้ชัดเจนถึงวัตถุประสงค์ที่ตั้งใจไว้ พวกเขาไม่ได้ปลดล็อกความสามารถที่ขาดหายไป แต่การใช้สามารถช่วยคุณจัดระเบียบความคิดของคุณได้ นั่นคือประโยชน์ที่แท้จริง ในตัวอย่างที่ใช้ได้จริงฉันเคยใช้ getter เพื่อขยายวัตถุ Google Maps ฉันจำเป็นต้องคำนวณมุมม้วนกล้องเพื่อที่ฉันจะได้หมุนแผ่นแผนที่ให้แบนไปที่ขอบฟ้า Google ทำสิ่งนี้โดยอัตโนมัติที่ส่วนหลังทันที แต่ในเวลานั้นมันเป็นประโยชน์สำหรับฉันในการเรียกคืนmaps.rollเป็นทรัพย์สินมากกว่าmaps.roll()ค่าตอบแทนของ มันเป็นเพียงความชอบ
rojo

ดังนั้นจึงเป็นเพียงแค่น้ำตาลในการสังเคราะห์เพื่อทำให้โค้ดดูสะอาดขึ้นโดยไม่ต้องใช้ () ฉันไม่เห็นว่าทำไมคุณถึงทำตัวอย่างของคุณไม่ได้maps.roll()
Andreas

@Andreas ใครบอกว่าทำไม่ได้? อย่างที่ฉันพูดมันเป็นเพียงวิธีที่ช่วยให้ฉันจัดระเบียบความคิด การเข้ารหัสเป็นศิลปะ คุณไม่ต้องถาม Bob Ross ว่าทำไมเขาต้องใช้สีเหลืองสดเมื่อเขาสามารถใช้สีส้มได้ คุณอาจไม่เห็นความจำเป็นในตอนนี้ แต่วันหนึ่งเมื่อคุณตัดสินใจว่าภาพวาดของคุณต้องการสีเหลืองที่ไหม้เล็กน้อยมันจะอยู่บนจานสีของคุณ
rojo

:) สิ่งหนึ่งที่ฉันเห็นว่ารับและตั้งค่าไวยากรณ์คือการรันอัตโนมัติหากใช้เป็นคุณสมบัติของคุณสมบัติ
Andreas

11

Getters และ setters จะสมเหตุสมผลก็ต่อเมื่อคุณมีคุณสมบัติส่วนตัวของคลาส เนื่องจาก Javascript ไม่มีคุณสมบัติคลาสส่วนตัวอย่างที่คุณคิดจาก Object Oriented Languages ​​จึงอาจเข้าใจได้ยาก นี่คือตัวอย่างหนึ่งของอ็อบเจ็กต์ตัวนับส่วนตัว สิ่งที่ดีเกี่ยวกับวัตถุนี้คือไม่สามารถเข้าถึงตัวแปรภายใน "count" จากภายนอกวัตถุได้

var counter = function() {
    var count = 0;

    this.inc = function() {
        count++;
    };

    this.getCount = function() {
        return count;
    };
};

var i = new Counter();
i.inc();
i.inc();
// writes "2" to the document
document.write( i.getCount());

หากคุณยังคงสับสนให้ดูที่บทความ Crockford บนสมาชิกเอกชนใน Javascript


39
ฉันไม่เห็นด้วย. ตัวรับและตัวตั้งค่ายังมีประโยชน์อย่างมากสำหรับการห่อหุ้มข้อมูลซึ่งนิยามอาจไม่ใช่แค่ตัวแปรธรรมดา อาจเป็นประโยชน์หากคุณต้องการเปลี่ยนลักษณะการทำงานของระบบที่ก่อนหน้านี้ใช้คุณสมบัติง่ายๆและสิ่งอื่น ๆ ที่อาจขึ้นอยู่กับ นอกจากนี้ตัวอย่างของคุณแสดงเฉพาะ "pseudo getters" ซึ่งเป็นเพียงฟังก์ชันเท่านั้น ตัวรับ JavaScript จริงจะปรากฏเป็นค่าที่เรียบง่าย (และเข้าถึงได้โดยไม่มีสัญกรณ์ฟังก์ชัน) ดังนั้นพลังที่แท้จริงของพวกเขา
devios1

ไม่แน่ใจว่าฉันจะเรียกว่าทรงพลัง บางสิ่งที่ปรากฏเป็น X แต่จริงๆแล้ว Y นั้นไม่จำเป็นต้องชัดเจน ฉันไม่คาดคิดว่าvar baz = foo.barจะมีพฤติกรรมซ่อนเร้นอยู่เบื้องหลัง ผมจะคาดหวังว่าจากการfoo.getBar()อย่างไร
AgmLauncher

8

ฉันคิดว่าบทความแรกที่คุณลิงก์ระบุไว้ค่อนข้างชัดเจน:

ข้อได้เปรียบที่ชัดเจนในการเขียน JavaScript ในลักษณะนี้คือคุณสามารถใช้ค่าที่คลุมเครือซึ่งคุณไม่ต้องการให้ผู้ใช้เข้าถึงได้โดยตรง

เป้าหมายคือการห่อหุ้มและแยกเขตข้อมูลออกไปโดยอนุญาตให้เข้าถึงผ่าน a get()หรือset()วิธีการเท่านั้น ด้วยวิธีนี้คุณสามารถจัดเก็บฟิลด์ / ข้อมูลไว้ภายในได้ทุกวิธีที่คุณต้องการ แต่ส่วนประกอบภายนอกจะอยู่ห่างจากอินเทอร์เฟซที่คุณเผยแพร่เท่านั้น สิ่งนี้ช่วยให้คุณทำการเปลี่ยนแปลงภายในโดยไม่ต้องเปลี่ยนอินเทอร์เฟซภายนอกทำการตรวจสอบความถูกต้องหรือตรวจสอบข้อผิดพลาดภายในset()วิธีการ ฯลฯ


6

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

var employee = {
    first: "Boris",
    last: "Sergeev",
    get fullName() {
        return this.first + " " + this.last;
    },
    set fullName(value) {
        var parts = value.toString().split(" ");
        this.first = parts[0] || "";
        this.last = parts[1] || "";
    },
    email: "boris.sergeev@example.com"
};

ผลลัพธ์สุดท้าย:

console.log(employee.fullName); //Boris Sergeev
employee.fullName = "Alex Makarenko";

console.log(employee.first);//Alex
console.log(employee.last);//Makarenko
console.log(employee.fullName);//Alex Makarenko

2

สิ่งที่สับสนเกี่ยวกับเรื่องนี้ ... getters เป็นฟังก์ชันที่เรียกเมื่อคุณได้รับคุณสมบัติ setters เมื่อคุณตั้งค่า ตัวอย่างเช่นถ้าคุณทำ

obj.prop = "abc";

คุณกำลังตั้งค่าคุณสมบัติ prop หากคุณใช้ getters / setters ฟังก์ชัน setter จะถูกเรียกโดยมี "abc" เป็นอาร์กิวเมนต์ นิยามฟังก์ชัน setter ภายในอ็อบเจ็กต์จะมีลักษณะดังนี้:

set prop(var) {
   // do stuff with var...
}

ฉันไม่แน่ใจว่าใช้งานได้ดีแค่ไหนในเบราว์เซอร์ ดูเหมือนว่า Firefox ยังมีไวยากรณ์ทางเลือกที่มีเมธอดพิเศษ ("magic") ที่ขีดเส้นใต้สองครั้ง ตามปกติ Internet Explorer ไม่รองรับสิ่งนี้


2

คุณสามารถกำหนดวิธีการอินสแตนซ์สำหรับคลาส js ผ่านต้นแบบของตัวสร้าง

ต่อไปนี้เป็นโค้ดตัวอย่าง:

// BaseClass

var BaseClass = function(name) {
    // instance property
    this.name = name;
};

// instance method
BaseClass.prototype.getName = function() {
    return this.name;
};
BaseClass.prototype.setName = function(name) {
    return this.name = name;
};


// test - start
function test() {
    var b1 = new BaseClass("b1");
    var b2 = new BaseClass("b2");
    console.log(b1.getName());
    console.log(b2.getName());

    b1.setName("b1_new");
    console.log(b1.getName());
    console.log(b2.getName());
}

test();
// test - end

และสิ่งนี้ควรใช้กับเบราว์เซอร์ใดก็ได้คุณสามารถใช้ nodejs เพื่อเรียกใช้โค้ดนี้ได้


1
นี่เป็นเพียงการสร้างเมธอด getName และ setName ใหม่ สิ่งเหล่านี้ไม่เกี่ยวข้องกับการสร้างทรัพย์สิน!
uzay95

2

ฉันค่อนข้างสับสนกับคำอธิบายที่อ่านเพราะฉันพยายามเพิ่มคุณสมบัติให้กับต้นแบบที่มีอยู่ซึ่งฉันไม่ได้เขียนดังนั้นการเปลี่ยนต้นแบบจึงดูเหมือนเป็นแนวทางที่ผิด ดังนั้นสำหรับลูกหลานต่อไปนี้เป็นวิธีที่ฉันเพิ่มlastคุณสมบัติในArray:

Object.defineProperty(Array.prototype, "last", {
    get: function() { return this[this.length - 1] }
});

ดีกว่าการเพิ่มฟังก์ชัน IMHO


1

หากคุณกำลังอ้างถึงแนวคิดของ accessors เป้าหมายง่ายๆคือการซ่อนที่เก็บข้อมูลพื้นฐานจากการจัดการโดยพลการ กลไกที่รุนแรงที่สุดสำหรับสิ่งนี้คือ

function Foo(someValue) {
    this.getValue = function() { return someValue; }
    return this;
}

var myFoo = new Foo(5);
/* We can read someValue through getValue(), but there is no mechanism
 * to modify it -- hurrah, we have achieved encapsulation!
 */
myFoo.getValue();

หากคุณกำลังอ้างถึงคุณสมบัติ JS getter / setter ที่แท้จริงเช่น defineGetter/ defineSetterหรือ{ get Foo() { /* code */ } }เป็นที่น่าสังเกตว่าในเครื่องยนต์สมัยใหม่ส่วนใหญ่การใช้คุณสมบัติเหล่านี้ในภายหลังจะช้ากว่าที่เป็นอยู่มาก เช่น. เปรียบเทียบประสิทธิภาพของ

var a = { getValue: function(){ return 5; }; }
for (var i = 0; i < 100000; i++)
    a.getValue();

เทียบกับ

var a = { get value(){ return 5; }; }
for (var i = 0; i < 100000; i++)
    a.value;

-1

ฉันมีหนึ่งสำหรับพวกคุณที่อาจจะดูน่าเกลียดเล็กน้อย แต่มันก็ทำได้สำเร็จในทุกแพลตฟอร์ม

function myFunc () {

var _myAttribute = "default";

this.myAttribute = function() {
    if (arguments.length > 0) _myAttribute = arguments[0];
    return _myAttribute;
}
}

ด้วยวิธีนี้เมื่อคุณโทร

var test = new myFunc();
test.myAttribute(); //-> "default"
test.myAttribute("ok"); //-> "ok"
test.myAttribute(); //-> "ok"

หากคุณต้องการเพิ่มพูนสิ่งต่างๆ .. คุณสามารถแทรกการตรวจสอบแบบ:

if (arguments.length > 0 && typeof arguments[0] == "boolean") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "number") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "string") _myAttribute = arguments[0];

หรือยิ่งไปกว่านั้นด้วยการตรวจสอบ typeof ขั้นสูง: รหัส type.of () ที่ codingforums.com


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