2011-11-07 36 views
11

Có mẫu JavaScript bắt chước thuộc tính đối tượng "Được bảo vệ" như những gì bạn thấy bằng các ngôn ngữ như C++ không ?? Về cơ bản, tôi muốn tạo một đối tượng A có một số thuộc tính đối tượng "được bảo vệ" có thể được truy cập CHỈ từ các phương thức được xác định từ nguyên mẫu của đối tượng A. tức là - KHÔNG thể truy cập công khai từ không phương pháp prototyped của A.Cách tạo thuộc tính đối tượng được bảo vệ trong JavaScript

Ví dụ, lý tưởng sẽ như vậy:

function A(){ 
    var prop1 = 1;  
} 

A.prototype.myFunc = function(){ 
    var newVar = this.prop1; //newVar now is equivalent to 1 
} 

var instanceOfA = new A(); 
var newVar2 = instanceOfA.prop1; //error given as prop1 is "protected"; hence undefined in this case 

BTW - tôi không muốn các mô hình của các hàm thành viên đặc quyền truy cập vào tài sản riêng kể từ khi chức năng thành viên vẫn còn nào.

+2

Không ............ –

+6

Lời khuyên của tôi, như thường lệ, là không ép buộc khả năng hiển thị vào JavaScript. * Một số * điều có thể với đóng cửa vv, nhưng ngôn ngữ không được thiết kế cho điều đó. Nó sẽ làm cho mã của bạn phức tạp hơn. Thay vào đó, hãy ghi lại các phương thức của bạn một cách chính xác như riêng tư hoặc công khai và nếu các nhà phát triển khác không tuân theo đặc tả của bạn, đó là vấn đề của họ. –

+0

Btw, các đối tượng nguyên mẫu có thể được tăng cường (chúng không bị đóng kín) - không có gì ngăn cản kẻ xâm nhập thêm các phương thức mới vào đối tượng nguyên mẫu. Vì vậy, có một tài sản có thể truy cập chỉ thông qua các phương pháp nguyên mẫu sẽ không được an toàn anyway (ngay cả khi nó đã có thể). –

Trả lời

12

Không có thuộc tính đối tượng chỉ có thể truy cập từ các phương thức được tạo mẫu của A và không phải từ phương thức không được tạo mẫu của A. Ngôn ngữ không có loại tính năng đó và tôi không biết bất kỳ công việc xung quanh/hack nào để triển khai nó.

Sử dụng Doug Crockford's methods, bạn có thể tạo thuộc tính thành viên chỉ có thể truy cập từ các phương thức không được xác định trước được xác định trước (các phương thức được xác định trong hàm tạo). Vì vậy, nếu bạn đang cố gắng giới hạn quyền truy cập chỉ vào một tập hợp các phương thức được xác định trước, điều này sẽ thực hiện điều đó. Khác hơn thế, tôi nghĩ bạn không may mắn.

Nếu bạn muốn các ý tưởng khác, bạn có thể nhận thêm trợ giúp nếu bạn mô tả thêm về những gì bạn đang thực sự cố gắng thực hiện trong mã của mình thay vì chỉ mô phỏng đối tượng địa lý bằng ngôn ngữ khác. Javascript là rất nhiều khác biệt so với C + + rằng nó tốt hơn để bắt đầu từ các nhu cầu của vấn đề hơn là cố gắng tìm một tương tự với một số tính năng C++.

4

Đây có lẽ là những gì bạn đang tìm kiếm: http://javascript.crockford.com/private.html

+0

Tôi đồng ý. Bài báo Doug Crockford đó là 'mô tả dứt khoát' của các tùy chọn cho quyền riêng tư của biến thành viên. Đây là những gì có sẵn. Tất cả chúng đều hơi hacks vì mọi biến thành viên chính thức được hỗ trợ bởi ngôn ngữ là công khai, nhưng bạn có thể có được sự riêng tư theo nhiều cách khác nhau bằng cách sử dụng các bao đóng. – jfriend00

+2

@Ericson OP nói rằng anh ấy không quan tâm đến các chức năng đặc quyền ... –

+3

Tôi cũng muốn chỉ ra rằng trong khi bạn có thể làm những gì Crockford có trong bài viết đó, không có nghĩa là bạn nên làm điều đó. Chương trình trong ngôn ngữ X như bạn đang lập trình cho ngôn ngữ X, không phải ngôn ngữ Y. Điều đó nói rằng, có một số sử dụng hợp pháp cho (! AHEM!) các biến riêng tư (tôi nghĩ rằng miệng mình chỉ đổ máu bằng cách nói) trong JS, nhưng tôi sẽ không đi sâu vào nó, vì những sử dụng đó không thực sự liên quan gì đến thiết kế lớp để nói. –

9

Bạn không thể làm điều đó trong Javascript.

+0

Bạn có thể giải thích tại sao tôi nhận được -1 không? Những gì tôi viết hoàn toàn đúng trong JS. Bạn không thể tạo các thuộc tính được bảo vệ trong JS. Không còn gì nữa. –

+4

Điều này đúng, cố gắng giả vờ khác là có hại hơn nhiều so với việc chấp nhận thực tế dễ dàng này. – Esailija

+5

{{citation needed}} – Offirmo

0

Hãy nhìn vào cách giải quyết của Maks trên trang web của mình đề xuất: Emulating protected members in JavaScript

Nó giả lập mức protected tiếp cận với các phương pháp và các thuộc tính của một đối tượng.

5

Tôi đã tìm ra cách để tạo thành viên được bảo vệ. Do tôi gọi là nhà xây dựng cơ bản và trả về một đối tượng với các thành viên được bảo vệ cùng một lúc:

var protected = BaseClass.call(this); 

đây một ví dụ:

function SignedIntegerArray(size) 
{ 
    var public = this; 
    var protected = {}; 

    // private property: 
    var _maxSize = 10000; 
    // protected property: 
    protected.array = []; 
    // public property: 
    public.Length = size; 

    if(!isInteger(size) || size < 0 || size > _maxSize) { throw "argument exception"; } 
    for(var index = 0; index != size; index++) { protected.array[index] = 0; } 

    // private method: 
    function isInteger(i) { return i == i + 0 && i == ~~i; } 
    // protected method: 
    protected.checkIndex = function(index) { return index >= 0 && index < size; } 
    // public methods: 
    public.SetValue = function(index, value) { if(protected.checkIndex(index) && isInteger(value)) { protected.array[index] = value; } }; 
    public.GetValue = function(index) { if(protected.checkIndex(index)) { return protected.array[index]; } else { throw "index out of range exception"; }} 

    return protected; 
} 

function FloatArray(size, range) 
{ 
    var public = this; 
    var protected = SignedIntegerArray.call(this, size); // call the base constructor and get the protected members 

    // new private method, "isInteger" is hidden... 
    function isFloat(argument) { return argument != ~~argument; } 
    // ...but "checkIndex" is accessible 
    public.SetValue = function(index, value) { if(protected.checkIndex(index) && isFloat(value) && value >= public.MinValue && value <= public.MaxValue) { protected.array[index] = value; } }; 

    // new public properties: 
    public.MinValue = -range; 
    public.MaxValue = range; 

    return protected; // for sub-classes 
} 

function newObject(className, args) { return new function() { className.apply(this, args)}} // you need to use function.call or function.apply to initialize an object. otherwise the protected-object is empty. 
window.addEventListener("load", function() 
{ 
    var o = newObject(FloatArray, [4, 50.0]); 
    o.SetValue(3, 2.1); 
    console.log(o.GetValue(3)); 
    console.log(o.Length); // property from the base-class 
}); 
+0

Nhược điểm của phương pháp này là bạn lãng phí bộ nhớ cho mỗi isntance, bởi vì mỗi cá thể có các hàm trùng lặp thay vì sử dụng lại các phương thức trên các nguyên mẫu. Vì vậy, trong 100 trường hợp, bạn có 100 phiên bản của các hàm được định nghĩa trong hàm tạo, trong khi với các phương thức mẫu thử, bạn chỉ có một cá thể hàm. Xem điều này cho một phương pháp không lãng phí bộ nhớ: https://github.com/philipwalton/mozart – trusktr

2
function ClassA(init) 
{ 
    var protected = {}; 
    protected.prop = init * 10; 
    if(this.constructor != ClassA) { return protected; } 
} 

function ClassB() 
{ 
    var protected = ClassA.call(this, 5); //console.log(protected.prop); 
} 

//var a = new ClassA(123); 
//var b = new ClassB(); 
1

Tôi đã quan tâm để tìm ra cách để trả lời của bạn câu hỏi, và đây là những gì tôi có thể làm.

Bạn sẽ cần helper này:

var ProtectedHandler = (function() { 
    /// <Sumarry> 
    /// Tool to handle the protected members of each inheritance. 
    /// </Summary> 
    /// <param name="current">Current protected variable.</param> 
    /// <param name="args">The arguments variable of the object.</param> 
    /// <param name="callback">The function to initialise the variable in the 'object'.</param> 
    /// <param name="isParent">Is this the ultimate base object.</param> 
    function ProtectedHandler(current, args, callback, isParent) { 
     this.child = getChild(args); 
     if (callback) 
      this.callback = callback; 

     if (isParent) 
      this.overrideChild(current); 
    } 

    // Get the ProtectedHandler from the arguments 
    var getChild = function (args) { 
     var child = null; 
     if (args.length > 0 && (child = args[args.length - 1]) && child.constructor === ProtectedHandler) 
      return child; 
    }; 

    // Chain Initialise the protected variable of the object and its inheritances. 
    ProtectedHandler.prototype.overrideChild = function (newValue) { 
     if (this.callback != null) { 
      this.callback(newValue); 
     } 
     if (this.child != null) { 
      this.child.overrideChild(newValue); 
     } 
    }; 

    // Static function to create a new instance of the protectedHandler object. 
    ProtectedHandler.handle = function (protected, arguments, callback, isParent) { 
     return new ProtectedHandler(protected, arguments, callback, isParent); 
    }; 

    return ProtectedHandler; 
})(); 

helper này sẽ cho phép bạn xử lý nhiều tài sản thừa kế. Bí quyết là sao chép biến được bảo vệ từ đối tượng cơ sở sang đối tượng mới của bạn (con).

Để chứng minh bạn nó làm việc, đây là một ví dụ:

// That's the default extends function from typescript (ref: http://www.typescriptlang.org/) 
var __extends = this.__extends || function (d, b) { 
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; 
    function __() { this.constructor = d; } 
    __.prototype = b.prototype; 
    d.prototype = new __(); 
}; 

var BaseClass = (function() {   
    function BaseClass() { 
     // Members 
     var private = {}, 
      protected = {}, 
      public = this; 

     // Constructor 
     ProtectedHandler.handle(protected, arguments, function() { 
      protected.type = "BaseClass"; 
     }, true); 

     // Methods 
     protected.saySomething = function() { 
      return "Hello World"; 
     }; 

     public.getType = function() { 
      return protected.type; 
     }; 
    } 

    return BaseClass; 
})(); 



var Person = (function (_super) { 
    __extends(Person, _super); 

    function Person(name) { 
     // Members 
     var private = {}, 
      protected = {}, 
      public; 

     // Constructor 
     _super.call(public = this, ProtectedHandler.handle(protected, arguments, function (p) { 
      protected = p; //This is required to copy the object from its base object. 
      protected.name = name; 
      protected.type = "Person"; 
     })); 

     //Method 
     public.getName = function() { 
      return protected.name; 
     }; 

     public.saySomething = function() { 
      return protected.saySomething(); 
     }; 
    } 
    return Person; 
})(BaseClass); 


var Child = (function (_super) { 
    __extends(Child, _super); 

    function Child(name) { 
     // Members 
     var private = {}, 
      protected = {}, 
      public; 

     // Constructor 
     _super.call(public = this, name, ProtectedHandler.handle(protected, arguments, function (p) { 
      protected = p; //This is required to copy the object from its base object. 
      protected.type = "Child"; 
     })); 

     //Method 
     public.setName = function (value) { 
      return protected.name = value; 
     }; 
    } 
    return Child; 
})(Person); 

Và đây là các bài kiểm tra:

var testBase = new BaseClass(); 
testBase.getType(); //"BaseClass" 
testBase.saySomething; //undefined 

var testPerson = new Person("Nic"); 
testPerson.getType(); //"Person" 
testPerson.saySomething(); //"Hello World" 
testPerson.name; //undefined 
testPerson.getName() //"Nic" 
testPerson.setName; //undefined 

var testChild = new Child("Bob"); 
testChild.getType(); //"Child" 
testChild.saySomething(); //"Hello World" 
testChild.name; //undefined 
testChild.getName(); //"Bob" 
testChild.setName("George"); 
testChild.getName(); //"George" 
1

Có một mô hình mà tôi đã trở nên thích đó không làm việc cùng một cách như truy cập được bảo vệ trong hầu hết các ngôn ngữ, nhưng cung cấp một lợi ích tương tự. Về cơ bản, sử dụng một phương pháp xây dựng để tạo ra một đóng cửa cho các thuộc tính, và sau đó có phương pháp tạo ra một đối tượng "đầy đủ" với quyền truy cập tự do cũng như một đối tượng "tiếp xúc" với truy cập hạn chế hơn. Đặt đối tượng tiếp xúc vào một thuộc tính của đối tượng đầy đủ và trả lại đối tượng đầy đủ đó cho người gọi.

Người gọi sau đó có thể sử dụng đối tượng đầy đủ (và chuyển đối tượng đó cho các cộng tác viên thích hợp khác), nhưng chỉ cung cấp đối tượng tiếp xúc với cộng tác viên có quyền truy cập hạn chế hơn.

Một ví dụ giả tạo ...

// Ring employs a typical private/public pattern while 
// RingEntry employs a private/exposed/full access pattern. 

function buildRing(size) { 
    var i 
    , head = buildRingEntry(0) 
    , newEntry; 
    ; 
    head.setNext(head); 
    for(i = size - 1; i ; i--) { 
    newEntry = buildRingEntry(i); 
    newEntry.setNext(head.getNext()); 
    head.setNext(newEntry); 
    } 
    function getHead() { return head.exposed; } 
    return { 
     getHead : getHead 
    } 
} 

function buildRingEntry(index) { 
    var next 
    , exposed 
    ; 
    function getIndex() { return index; } 
    function setNext(newNext) { next = newNext; } 
    function getNextFullEntry() { return next; } 
    function getNextExposedEntry() { return next.exposed; } 
    exposed = { 
     getIndex : getIndex 
    , getNext : getNextExposedEntry 
    }; 
    return { 
     getIndex : getIndex 
    , setNext : setNext 
    , getNext : getNextFullEntry 
    , exposed : exposed 
    }; 
} 

Nếu chúng ta sử dụng để xây dựng một vòng 4 mục ring = buildRing(4);, sau đó cho chúng ta ring.getHead().getIndex() 0, ring.getHead().getNext().getIndex() cho chúng ta 1, ring.getHead().getNext().getNext().getIndex() cho chúng ta 2, vv

Tuy nhiên, nếu chúng tôi cố gắng thực thi ring.getHead().setNext({}) hoặc ring.getHead().getNext().setNext({}), chúng tôi sẽ gặp lỗi vì setNext không phải là tài sản của đối tượng được tiếp xúc.

Nên biết trước:

Do đây là trong gia đình mẫu mà xây dựng các phương pháp một lần nữa trong một kết thúc mới cho mỗi đối tượng mới, nó không phải là thích hợp cho các tình huống trong đó một khối lượng rất cao của instantiation có thể cần thiết.

+0

Lưu ý rằng mẫu này cũng có thể được sử dụng với hàm xây dựng cho đối tượng đầy đủ. Đơn giản chỉ cần tạo và gán thuộc tính tiếp xúc của 'this' từ bên trong phần thân của hàm tạo. –

Các vấn đề liên quan