-
Summary
概要
I tried to achieve inheritance and encapsulation properly in javascript like it was in a class-based language such as c#.
我尝试在javascript中正确地实现继承和封装,就像在基于类的语言(如c#)中一样。
The ugly part is the protected members have multiple copies in the private instances which are only accessible via closure, and I don't have an idea except refreshing those members to the private instances.
丑陋的部分是受保护的成员在私有实例中有多个副本,只能通过闭包访问,除了将这些成员刷新到私有实例之外,我没有任何想法。
If it is possible, I want to get rid of both
transmit
andtransfer
in my code ofFunction.extend
.如果有可能,我想在我的Function.extend代码中摆脱传输和传输。
-
Update For people who are interested in citing or research, here's the source code repository:
更新对于对引用或研究感兴趣的人,这里是源代码库:
https://github.com/kenkins/Function.extend
https://github.com/kenkins/Function.extend
-
The story
故事
Since assemblies may be a concept which is out of range of javascript, I don't take the
internal
modifier into account, butpublic
,protected
andprivate
.由于程序集可能是一个超出javascript范围的概念,我不考虑内部修饰符,而是公共,受保护和私有。
public
andprivate
modifiers are not that difficult to achieve; but with inheritance,protected
is significantly tricky. Yet it's not a recommended thing to do with javascript, most of articles I've read says prefix with a special character and document it.公共和私人修饰符并不难实现;但是对于继承,受保护是非常棘手的。然而,使用javascript并不是一个推荐的事情,我读过的大多数文章都说带有特殊字符的前缀并记录它。
But it seems I'm persisted to make javascript to simulate class-based languages .. I stole this idea and implemented in my way, the code is at rear of this post.
但似乎我坚持使用javascript来模拟基于类的语言..我偷了这个想法并以我的方式实现,代码在这篇文章的后面。
The idea behind the scene is to put higher accessibility with a higher prototype and access the highest one with a closure.
场景背后的想法是使用更高的原型来提高可访问性,并使用闭包访问最高的原型。
Say we have three prototypes
A
,D
andG
, it looks like假设我们有三个原型A,D和G,它看起来像
As it is not possible that an object is an instance of a type also of another type which is not in the prototype chain; the way I chosen is to chain the
protected
level horizontally and copy the members from the prototype of the declaring type. This makes nesting class possible, because the members declared on a less-derived type can be propagated to more-derived types; thetransmit
method in my code is to do this. IfA
,D
andG
have their own protected members, it would look like:因为对象不可能是另一种不属于原型链的类型的实例;我选择的方式是水平链接受保护的级别,并从声明类型的原型中复制成员。这使得嵌套类成为可能,因为在较少派生类型上声明的成员可以传播到更多派生类型;我的代码中的传输方法是这样做的。如果A,D和G有自己的受保护成员,它看起来像:
The closure for accessing the private instance, is
this['']
. It takes an argument which is for identifying a class. The modifiers holder is just the class identifier, namedy
inFunction.extend
and_
in the test code, it should not be exposed outside the class declaration. It is also used as a shortcut ofthis['']
.用于访问私有实例的闭包是['']。它需要一个用于识别类的参数。修饰符持有者只是类标识符,在Function.extend中命名为y,在测试代码中命名为_,它不应该暴露在类声明之外。它也用作此['']的快捷方式。
_['base']
is in fact not only the base constructor invoker, but also the private instances creator. It creates the private instances and updatesthis['']
for each constructor with the inheritance, so it should always be called in the constructors._ ['base']实际上不仅是基础构造函数调用者,也是私有实例创建者。它创建私有实例并使用继承为每个构造函数更新此[''],因此应始终在构造函数中调用它。
Although a private instance would have the access of the public members, it should not be used to alter them, since
this['']
is not guaranteed to be invoked when accessing public members. But the accessing of private instance is;recent
remembers the most recently accessed private instance, and update the protected members if there're changes.虽然私有实例可以访问公共成员,但不应该使用它来更改它们,因为在访问公共成员时不保证调用['']。但访问私有实例是;最近记得最近访问过的私有实例,如果有更改,则更新受保护的成员。
My question is, how can I get rid of this kind of refreshing the protected members? Are there better ideas to achieve the encapsulation more of the realistic?
我的问题是,我怎样才能摆脱受保护成员的这种清新?是否有更好的想法来实现更真实的封装?
p.s.: I actually do not want a solution which uses non-standard methods/properties .. and it would be better there're polyfills if the used methods/properties are too fashion to the old browsers.
p.s。:我实际上不想要一个使用非标准方法/属性的解决方案..如果使用的方法/属性对于旧浏览器来说过于时尚,那么填充更好。
-
Function.extend
Function.extend
Function.extend=function (base, factory) { factory.call(initializeClass); updateStaticMembersOfDerivedInnerClasses(y['public'].constructor); transfer(y['protected'], y['public']); return y['public'].constructor; function y($this) { return $this[''](y); } function updateStaticMembersOfDerivedInnerClasses(outer) { var member, inner; for (var key in outer) { if (Object.prototype.hasOwnProperty.call(outer, key)? (member=outer[key]) instanceof outer? outer!==(inner=member.constructor): false:false) { transfer(inner, outer); } } } function initializeInstance() { var $this=Object.create(y['private']); var derivedGet=this['']; var recent=$this; this['']=function (x) { var value=y!==x?derivedGet.call(this, x):$this; if (value!==recent) { transfer(value, recent, x['protected']); recent=value; } return value; }; base.apply(this, arguments); $this['']=this['']; } function initializeClass(derived) { y['public']=Object.create(base.prototype); y['public'].constructor=derived; if (Object.prototype.hasOwnProperty.call(base, 'transmit')) { base.transmit(y); } else { y['protected']=Object.create(y['public']); } y['private']=Object.create(y['protected']); y['base']=initializeInstance; transfer(derived, base); derived.transmit=function (x) { if (x['public'] instanceof derived) { x['protected']=Object.create(y['protected']); x['protected'].constructor=x['public'].constructor; } }; derived.prototype=y['public']; return y; } };
-
transfer
转让
function transfer(target, source, descriptor) { if (target!==source? 'undefined'!==typeof target? 'undefined'!==typeof source: false:false) { var keys='undefined'!==typeof descriptor?descriptor:source; for (var key in keys) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key]=source[key]; } } } }
-
test code
测试代码
'use strict'; var BaseClass=Function.extend(Object, function () { var _=this(BaseClass); var NestedClass=Function.extend(BaseClass, function () { var _=this(NestedClass); function NestedClass(x, y, z) { _['base'].apply(this, arguments); _(this).Y=y; _(this).Z=z; } _['public'].SetX=function (x) { _(this).InternalSetX(x); }; _['public'].GetX=function () { return _(this).InternalGetX(); }; _['public'].GetY=function () { return _(this).Y; }; _['public'].SetZ=function (z) { _(this).Z=z; }; _['public'].GetZ=function () { return _(this).Z; }; _['private'].Y=0; }); function BaseClass(x) { _['base'].apply(this, arguments); _(this).X=x; } _['protected'].InternalSetX=function (x) { _(this).X=x; }; _['protected'].InternalGetX=function () { return _(this).X; }; _['private'].X=0; _['protected'].Z=0; BaseClass.Sample=new NestedClass(1, 2, 3); }); var DerivedClass=Function.extend(BaseClass, function () { var _=this(DerivedClass); function DerivedClass(x, y, z) { _['base'].apply(this, arguments); } }); var o=DerivedClass.Sample; alert(o.GetX()); alert(o.GetY()); alert(o.GetZ()); o.SetX(3); o.SetZ(1); alert(o.GetX()); alert(o.GetY()); alert(o.GetZ());
5 个解决方案
#1
4
I also had a similar thought and decided to try write something. A vanilla js solution. Still early but I like what came out of it. You might find it interesting also.
我也有类似的想法,并决定尝试写点东西。一个香草js解决方案。还是早,但我喜欢它的结果。您可能也觉得它很有趣。
It's not exactly c# but provides a more strict ecosystem. And some other advanced js features in a lightweight solution.
它不完全是c#,但提供了更严格的生态系统。轻量级解决方案中还有一些其他高级js功能。
https://github.com/iamlothian/rucksack.js
https://github.com/iamlothian/rucksack.js
This is not a solution to your code, but solution to your concept. If your goal was the get your idea to work then by all means continue as I am interested by the result.
这不是您的代码的解决方案,而是您的概念的解决方案。如果你的目标是让你的想法发挥作用,那么一定要继续,因为我对结果感兴趣。
If you like me just want a more structured js environment, then here is one I wrote with similar ambition to your questions concepts.
如果你喜欢我只是想要一个更有条理的js环境,那么这里就是我写的一个与你的问题概念类似的抱负。
Part 2:
第2部分:
The idea here is to use closure and access restriction to create a pattern that restricts the way code can be used and changed after is has been defined. For the most part a lot of the hard work has been done. But the pattern is left for you to define.
这里的想法是使用闭包和访问限制来创建一个模式,该模式限制了在定义代码之后使用和更改代码的方式。在大多数情况下,已经完成了很多艰苦的工作。但是模式留给你定义。
Here is a quick mock example demonstrating how you might implement a public|protect|private inheritance. I am trying to decide weather i implement some of this as a built in feature or leave it up to users to implement their own object extension like i have in the example.
这是一个快速模拟示例,演示如何实现public | protect | private继承。我试图决定天气我实现其中的一些作为内置功能或留给用户实现他们自己的对象扩展,就像我在示例中。
http://plnkr.co/edit/ao2hTyBV1b3nYIwr7ZS5
http://plnkr.co/edit/ao2hTyBV1b3nYIwr7ZS5
The implementation is in scripts.js. view you console to see what is going on.
实现在scripts.js中。查看您的控制台以查看发生了什么。
What rucksack provides is a framework for creating detached modules of code. These modules are grouped into namespaces and can depend on each other. These dependencies are resolved lazily as defined, so that definition order is not really important. The resolution process provides some other useful features such as interfaces matching and sealed module.
rucksack提供的是用于创建分离的代码模块的框架。这些模块分为命名空间,可以相互依赖。这些依赖项按定义延迟解析,因此定义顺序并不重要。解析过程提供了一些其他有用的功能,如接口匹配和密封模块。
current features:
目前的特点:
- Modular
- 模块化
- Dependency Injection
- 依赖注入
- Factory constructor (Instances Object)
- 工厂构造函数(Instances Object)
- Service constructor (Static Objects)
- 服务构造函数(静态对象)
- Lazy loading
- 延迟加载
- Easy error logging (All error within modules are captured and can be passed on)
- 简单的错误记录(模块中的所有错误都被捕获并可以传递)
- Namespaces
- 命名空间
- Sealable modules and namespaces (modules that can't be accessed from outside the namespace)
- 可密封的模块和命名空间(无法从命名空间外部访问的模块)
- Global await event for module
- Global等待模块事件
- Interface for optional config object
- 可选配置对象的接口
- Optional strict interface checks for injection
- 注射的可选严格接口检查
#2
3
While the code with closure might solve what you want, I would go with the simpler Privileged methods as Crockford called them here.
虽然带闭包的代码可以解决你想要的问题,但我会选择更简单的Privileged方法,就像Crockford在这里调用它们一样。
Usage idea is simple:
使用方法很简单:
- Define privileged method on the base object (with limit 1 - allows to be called only once).
- 在基础对象上定义特权方法(限制为1 - 允许仅调用一次)。
- Privileged method returns a protected interface of itself (of a base object) which contains protected functions in it (probably those functions are privately defined in the base, and then get copied over to the protected interface object... or maybe the protected interface exists privately).
- 特权方法返回自身(基础对象)的受保护接口,其中包含受保护的函数(可能这些函数在基础中私有定义,然后被复制到受保护的接口对象...或者受保护的接口可能存在私下)。
- Each object extends its protected interface with its base object's protected interface and still exposes it through the privileged method.
- 每个对象都使用其基础对象的受保护接口扩展其受保护接口,并仍然通过特权方法公开它。
You will end up with something like this:
你最终会得到这样的东西:
function A() {
var protected = {
protectedA: function() { }
};
this.getProtected = (function() {
var allow = true;
//privileged function.
return function() {
if (allow) {
allow = false;
return protected;
}
};
});
}
//B - derives from (extends) A
function B() {
var base = {}; //acquiring a base omitted - depends on your implementation.
var protected = {
protectedB: function() { }
};
//"extend" simply copies new members into protected:
protected = $.extend(protected, base.getProtected());
this.getProtected = function() {
/* privileged function - similar to A.getProtected */
};
}
JavaScript has limited abilities in this extent, so the protected
sugar comes with some cost anyway.
JavaScript在这种程度上的能力有限,所以受保护的糖无论如何都会带来一些成本。
#3
1
Javascript is a wide language, because you can do almost all the things do you want in a webpage, just by creating functions and finding ways to do it.
Javascript是一种广泛的语言,因为您可以在网页中完成几乎所有您想要的操作,只需创建函数并找到方法即可。
I can tell you that JavaScript are not a secure language, because you can easily access the most part of variables and functions, read them, and know how it works, just by acessing the .js file, included on the page.
我可以告诉你,JavaScript不是一种安全的语言,因为只需访问页面中包含的.js文件,就可以轻松访问大部分变量和函数,读取它们并了解它是如何工作的。
My Tought: Some access modifiers was not created to use in javascript due to developers already know that maybe it can be useless, because JavaScript does not "Travel" into another places(pages), unless you use a session variable.
我的尝试:由于开发人员已经知道它可能没用,因此JavaScript中没有创建一些访问修饰符,因为JavaScript不会“移动”到其他地方(页面),除非您使用会话变量。
And about that modifiers:
关于修饰符:
-
Private
私人的
-
Protected
受保护
- Public
- 上市
I can tell you that i know some javascript modifiers that have some similarity to them, that are:
我可以告诉你,我知道一些与它们有一些相似性的javascript修饰符,它们是:
Local:
本地:
var Variable = 0;
var Variable = 0;
Automatically, this is converted into a Integer variable, because it is receiving a Integer value, and too, this is a LOCAL variable because of the var
modifier that declare this variable in a way that you cannot access the value of it, unless if you are inside the same function that this variable was declared.
自动地,这被转换为Integer变量,因为它正在接收一个Integer值,并且这也是一个LOCAL变量,因为var修饰符以一种你无法访问它的值的方式声明这个变量,除非你在声明此变量的函数内部。
Example:
例:
If you declare these functions this way, with default modifiers:
如果以这种方式声明这些函数,使用默认修饰符:
function conflict(){
i = 2;
changeI();
alert(i);
}
function changeI(){
i = 0;
}
In this case the i
is the same variable for the two functions.
在这种情况下,i是两个函数的相同变量。
So if you execute conflict();
you will get a alert resulting 0
.
所以如果你执行conflict();你会得到一个警告0。
BUT, if you declare i
using the var
modifier:
但是,如果你声明我使用var修饰符:
function conflict(){
var i = 2;
changeI();
alert(i);
}
function changeI(){
var i = 0;
}
In this case, you have two i
variables, because they are restricted to use only inside their function, so if you execute conflict();
now, you will get a alert with value of 2
.
在这种情况下,您有两个i变量,因为它们仅限于在其函数内使用,因此如果执行conflict();现在,您将收到值为2的警报。
Class Variable:
类变量:
this.Variable = "a";
this.Variable =“a”;
This variable is automatically a String, because it is receiving a String value, Probably you already know what the this
modifier does, but, i'll try to explain with my point of view, that is this variable is coming from the SuperClass or in javascript a "SuperFunction" that can be called a Class, or in other words, the "father" class.
这个变量自动是一个String,因为它正在接收一个String值,可能你已经知道这个修饰符的作用了,但是,我会尝试用我的观点来解释,就是这个变量来自SuperClass或者javascript一个“SuperFunction”,可以称为Class,或者换句话说,就是“父”类。
A example:
一个例子:
function TClass()
{
this.getVar = function()
{
try
{
return "test";
}
catch(err)
{
return false;
}
}
this.alertVar = function()
{
try
{
alert(this.getVar());
}
catch(err)
{
alert('error');
}
}
}
var $Class = new TClass();
As you see above, i created a Class TClass
and some variables containing functions into it (javascript closure) and added the modifier this.
to them, to make them bound to the TClass
and as you see on the alertVar()
function, i access on the alert(this.getVar());
the function that are from the TClass
that is equal to this
in this context.
如上所示,我创建了一个Class TClass和一些包含函数的变量(javascript closure)并添加了修饰符this。对他们来说,为了让他们绑定到TClass,正如你在alertVar()函数中看到的那样,我可以访问警报(this.getVar());来自TClass的函数在此上下文中等于this。
And this part: var $Class = new TClass();
i am creating the class as you probably knew that, to have access to its methods, doing this i am possible to execute, to test:
这一部分:var $ Class = new TClass();我正在创建类,因为您可能知道,要访问其方法,执行此操作我可以执行,以测试:
$Class.alertVar();
And getting as result, an alertbox containing "test", as you can see:
得到结果,一个包含“test”的警告框,如您所见:
Note that you can't access the TClass
methods in another ways, you only can access it creating the class and accessing by it.
请注意,您无法以其他方式访问TClass方法,您只能访问它创建类并通过它进行访问。
So i hope that you did understand the usability of the this
modifier.
所以我希望你确实理解了这个修饰符的可用性。
Global:
全球:
window.Variable = true;
window.Variable = true;
Automatically javascript declare this variable is a boolean, because it is receiving a Boolean value. The window
modifier as it says, you can access it whatever you are on the window that you are, because javascript variables when declared, they go to the DOM into the window, see what is DOM:
自动javascript声明此变量是一个布尔值,因为它接收一个布尔值。正如它所说的窗口修饰符,无论你在窗口上是什么都可以访问它,因为javascript变量在声明时,它们会进入窗口,看看DOM是什么:
DOM(Document Object Model): The DOM, is a multi-platform that represents how the html,xhtml, and xml markup's are organized and read by the browser that you are using. In other words, if you access the DOM you can see every propery, every variable, or such of thing that exists on the browser at the moment.
DOM(文档对象模型):DOM是一个多平台,表示您正在使用的浏览器如何组织和读取html,xhtml和xml标记。换句话说,如果您访问DOM,您可以看到浏览器上存在的每个属性,每个变量或其他内容。
Different from another variables, the window
variables can have assigned another value and access the actual value, from whatever you are, inside a function or not, inside a js file or not.
与其他变量不同,窗口变量可以分配另一个值,并且无论您是否在函数内部,都可以在js文件内部访问实际值。
Example of Global(window):
全局(窗口)示例:
Execute on the onLoad
event of a page a code that declares a window
variable, or declare it yourself using browser console:
在页面的onLoad事件上执行声明窗口变量的代码,或者使用浏览器控制台自己声明:
window.Variable = true;
Then, add a JS File containing this function, or create it yourself just by executing the code on the browser console:
然后,添加一个包含此函数的JS文件,或者只需在浏览器控制台上执行代码即可自行创建:
function testGlobalVar(){
if (Variable)
alert("it works!");
}
When you execute testGlobalVar()
you will get the alert, but it is only because you declared it as `window´ otherwise, you will get nothing.
当你执行testGlobalVar()时,你会得到警告,但这只是因为你把它声明为“窗口”,否则你什么也得不到。
Default Modifier:
默认修饰符:
Variable = 0.5
变量= 0.5
Automatically this Variable is declared as Float beacuse it is receiving a Float value. I dont know if you already know, but javascript variables declared as the usual way, have a default modifier that makes the variable similar to window
variables, but you cannot access it from whatever you are, but in most cases you can acess it, particulary, i dont know all the cases that you cannot access it, but i know that you cant when you loaded a js file and it was declared inside it. Only if you run a function that declares it, and after that try to acesss.
自动将此变量声明为Float,因为它正在接收Float值。我不知道你是否已经知道,但javascript变量被声明为通常的方式,有一个默认的修饰符,使变量类似于窗口变量,但你不能从任何你访问它,但在大多数情况下你可以访问它,特别是,我不知道你无法访问它的所有情况,但我知道你不能加载一个js文件,并在它内部声明。只有当你运行一个声明它的函数,然后尝试访问。
By the way, i see that you want to know modifiers that match the three that you said, but at my tought some of that modifiers that i told you can be used to do the same that your c# modifiers do.
顺便说一句,我看到你想知道与你所说的三个匹配的修饰符,但在我看来,我告诉你的一些修饰符可以用来做你的c#修饰符那样做。
I hope that you understand what i'm saying.
我希望你明白我在说什么。
Ah, and if you was confused when you saw a function inside a variable, study Javascript Closures, you will understand after that :).
啊,如果你在变量中看到一个函数时感到困惑,研究Javascript Closures,你就会明白了:)。
#4
1
How the parent and child classes interact with each other
父类和子类如何相互交互
-
An extending child class calls
super.call
, a function that constructs an instance of it's parent.扩展子类调用super.call,这是一个构造其父实例的函数。
-
A parent class shares it's protected members (both fields and functions) to it's extending subclass by using
this.share
in it's constructor.父类通过在其构造函数中使用this.share将它的受保护成员(字段和函数)共享到它的扩展子类。
-
A subclass can also call
super.fetch()
, which returns the object of fields/functions that the parent class passed tothis.share
子类也可以调用super.fetch(),它返回父类传递给this.share的字段/函数的对象。
To illustrate my technique, the following code demonstrates some essentials to OOP with a simple example of a class Dog extends Animal
为了说明我的技术,下面的代码演示了OOP的一些基本要素,其中包含一个类似于Dog extends Animal的简单示例
Some core functions for this object oriented model
这种面向对象模型的一些核心功能
// runs in both node.js and browser
var global_namespace = ('undefined'==typeof module)? window: global;
// put a no-operation function in the value for `share` in case nothing is extending a class
var not_extendable = {share:function(){}};
// when something is extending a class...
var extendable = function(constructor) {
// create a space for protected fields
var protected_space = {};
// the following is what will get passed as `this` to the parent constructor
var sharing = {
share: function(fields) {
protected_space = fields;
},
};
// the following is what will get passed as the first arg to the child constructor
return {
// enables child to call its parent's constructor
call: function(args) {
return constructor.apply(sharing, args);
},
// allows child to access protected fields shared by its parent
fetch: function() {
return protected_space;
},
};
};
Animal
class
动物类
// class definition for `Animal`
(function(namespace) {
// construct an instance of this class
var constructor = function(name, weight, info) {
// private fields
var color = (info && info.color) || 'unknown';
// for protected fields
var protect = {
weight: weight,
noise: function() {
return 'nothing';
},
};
// share the protected fields with any subclass that might be extending this
this.share(protect);
// public fields and methods
return {
speak: function() {
console.log(name+' says '+protect.noise());
},
feed: function() {
console.log(name+' is not hungry');
},
weigh: function() {
console.log(name+' weighs '+protect.weight+' lbs');
},
toString: function() {
return '{Animal}';
},
};
};
// handle calls to: `Animal()`
namespace.Animal = function() {
// called with new operator: `new Animal(...)`
if(this !== namespace) {
// construct simple instance of this class
return constructor.apply(not_extendable, arguments);
}
// static call: `Animal(...)`, means the caller wants to extend this class
else {
// reference child constructor
var child_constructor = arguments[0];
// return a wrapped constructor function
return function() {
// call child constructor and allow it to call the super constructor
return child_constructor.apply({}, [extendable(constructor), arguments]);
};
}
};
})(global_namespace);
Dog
class
狗班
// class definition for `Dog`
(function(namespace) {
// class `Dog` extends class `Animal`
var constructor = Animal(function(super_class, args) {
// private field
var been_fed = false;
// call super's constructor
var operator = super_class.call(args);
// inherit parent's protected members
var parent = super_class.fetch();
// override a protected method
parent.noise = function() {
return 'bark!';
};
// override a public method
operator.feed = function() {
been_fed = true;
parent.weight += 5;
};
// extend a public method
var super_weigh = operator.weigh;
operator.weigh = function() {
super_weigh();
if(been_fed) console.log('\t'+args[0]+' has been eating :)');
else console.log('\t'+args[0]+' has not been fed yet');
};
// override another public method
operator.toString = function() {
return '{Dog}';
},
// return the operator (interfacable instance object)
return operator;
});
// handle calls to: `Dog()`
namespace.Dog = function() {
// called with new operator: `new Dog()`
if(this !== namespace) {
return constructor.apply(this, arguments);
}
// static call: `Dog()`
else {
// we do no allow extending class `Dog`
return false;
}
};
})(global_namespace);
So now, we can do this:
所以现在,我们可以这样做:
var giraffe = new Animal('Mr. Giraffe', 720);
giraffe.speak(); // "Mr. Giraffe says nothing"
giraffe.weigh(); // "Mr. Giraffe weighs 720 lbs"
var buddy = new Dog('Buddy', 50);
buddy.speak(); // "Buddy says bark!"
buddy.weigh(); // "Buddy weighs 50 lbs"
// "Buddy has not been fed yet"
buddy.feed();
buddy.weigh(); // "Buddy weighs 55 lbs"
// "Buddy has been eating :)"
This allows private, protected and public fields/functions. Both protected and public field/functions may be overwritten and extended.
这允许私有,受保护和公共字段/功能。受保护和公共字段/功能都可以被覆盖和扩展。
console.log(giraffe); // "{Animal}"
console.log(buddy); // "{Dog}"
#5
1
I have been working on another interesting javascript project and implemented something that may be closer to what you are looking for.
我一直在研究另一个有趣的javascript项目,并实现了一些可能更接近你正在寻找的东西。
Implement.js
Interested in you thoughts.
对你的想法感兴趣。
#1
4
I also had a similar thought and decided to try write something. A vanilla js solution. Still early but I like what came out of it. You might find it interesting also.
我也有类似的想法,并决定尝试写点东西。一个香草js解决方案。还是早,但我喜欢它的结果。您可能也觉得它很有趣。
It's not exactly c# but provides a more strict ecosystem. And some other advanced js features in a lightweight solution.
它不完全是c#,但提供了更严格的生态系统。轻量级解决方案中还有一些其他高级js功能。
https://github.com/iamlothian/rucksack.js
https://github.com/iamlothian/rucksack.js
This is not a solution to your code, but solution to your concept. If your goal was the get your idea to work then by all means continue as I am interested by the result.
这不是您的代码的解决方案,而是您的概念的解决方案。如果你的目标是让你的想法发挥作用,那么一定要继续,因为我对结果感兴趣。
If you like me just want a more structured js environment, then here is one I wrote with similar ambition to your questions concepts.
如果你喜欢我只是想要一个更有条理的js环境,那么这里就是我写的一个与你的问题概念类似的抱负。
Part 2:
第2部分:
The idea here is to use closure and access restriction to create a pattern that restricts the way code can be used and changed after is has been defined. For the most part a lot of the hard work has been done. But the pattern is left for you to define.
这里的想法是使用闭包和访问限制来创建一个模式,该模式限制了在定义代码之后使用和更改代码的方式。在大多数情况下,已经完成了很多艰苦的工作。但是模式留给你定义。
Here is a quick mock example demonstrating how you might implement a public|protect|private inheritance. I am trying to decide weather i implement some of this as a built in feature or leave it up to users to implement their own object extension like i have in the example.
这是一个快速模拟示例,演示如何实现public | protect | private继承。我试图决定天气我实现其中的一些作为内置功能或留给用户实现他们自己的对象扩展,就像我在示例中。
http://plnkr.co/edit/ao2hTyBV1b3nYIwr7ZS5
http://plnkr.co/edit/ao2hTyBV1b3nYIwr7ZS5
The implementation is in scripts.js. view you console to see what is going on.
实现在scripts.js中。查看您的控制台以查看发生了什么。
What rucksack provides is a framework for creating detached modules of code. These modules are grouped into namespaces and can depend on each other. These dependencies are resolved lazily as defined, so that definition order is not really important. The resolution process provides some other useful features such as interfaces matching and sealed module.
rucksack提供的是用于创建分离的代码模块的框架。这些模块分为命名空间,可以相互依赖。这些依赖项按定义延迟解析,因此定义顺序并不重要。解析过程提供了一些其他有用的功能,如接口匹配和密封模块。
current features:
目前的特点:
- Modular
- 模块化
- Dependency Injection
- 依赖注入
- Factory constructor (Instances Object)
- 工厂构造函数(Instances Object)
- Service constructor (Static Objects)
- 服务构造函数(静态对象)
- Lazy loading
- 延迟加载
- Easy error logging (All error within modules are captured and can be passed on)
- 简单的错误记录(模块中的所有错误都被捕获并可以传递)
- Namespaces
- 命名空间
- Sealable modules and namespaces (modules that can't be accessed from outside the namespace)
- 可密封的模块和命名空间(无法从命名空间外部访问的模块)
- Global await event for module
- Global等待模块事件
- Interface for optional config object
- 可选配置对象的接口
- Optional strict interface checks for injection
- 注射的可选严格接口检查
#2
3
While the code with closure might solve what you want, I would go with the simpler Privileged methods as Crockford called them here.
虽然带闭包的代码可以解决你想要的问题,但我会选择更简单的Privileged方法,就像Crockford在这里调用它们一样。
Usage idea is simple:
使用方法很简单:
- Define privileged method on the base object (with limit 1 - allows to be called only once).
- 在基础对象上定义特权方法(限制为1 - 允许仅调用一次)。
- Privileged method returns a protected interface of itself (of a base object) which contains protected functions in it (probably those functions are privately defined in the base, and then get copied over to the protected interface object... or maybe the protected interface exists privately).
- 特权方法返回自身(基础对象)的受保护接口,其中包含受保护的函数(可能这些函数在基础中私有定义,然后被复制到受保护的接口对象...或者受保护的接口可能存在私下)。
- Each object extends its protected interface with its base object's protected interface and still exposes it through the privileged method.
- 每个对象都使用其基础对象的受保护接口扩展其受保护接口,并仍然通过特权方法公开它。
You will end up with something like this:
你最终会得到这样的东西:
function A() {
var protected = {
protectedA: function() { }
};
this.getProtected = (function() {
var allow = true;
//privileged function.
return function() {
if (allow) {
allow = false;
return protected;
}
};
});
}
//B - derives from (extends) A
function B() {
var base = {}; //acquiring a base omitted - depends on your implementation.
var protected = {
protectedB: function() { }
};
//"extend" simply copies new members into protected:
protected = $.extend(protected, base.getProtected());
this.getProtected = function() {
/* privileged function - similar to A.getProtected */
};
}
JavaScript has limited abilities in this extent, so the protected
sugar comes with some cost anyway.
JavaScript在这种程度上的能力有限,所以受保护的糖无论如何都会带来一些成本。
#3
1
Javascript is a wide language, because you can do almost all the things do you want in a webpage, just by creating functions and finding ways to do it.
Javascript是一种广泛的语言,因为您可以在网页中完成几乎所有您想要的操作,只需创建函数并找到方法即可。
I can tell you that JavaScript are not a secure language, because you can easily access the most part of variables and functions, read them, and know how it works, just by acessing the .js file, included on the page.
我可以告诉你,JavaScript不是一种安全的语言,因为只需访问页面中包含的.js文件,就可以轻松访问大部分变量和函数,读取它们并了解它是如何工作的。
My Tought: Some access modifiers was not created to use in javascript due to developers already know that maybe it can be useless, because JavaScript does not "Travel" into another places(pages), unless you use a session variable.
我的尝试:由于开发人员已经知道它可能没用,因此JavaScript中没有创建一些访问修饰符,因为JavaScript不会“移动”到其他地方(页面),除非您使用会话变量。
And about that modifiers:
关于修饰符:
-
Private
私人的
-
Protected
受保护
- Public
- 上市
I can tell you that i know some javascript modifiers that have some similarity to them, that are:
我可以告诉你,我知道一些与它们有一些相似性的javascript修饰符,它们是:
Local:
本地:
var Variable = 0;
var Variable = 0;
Automatically, this is converted into a Integer variable, because it is receiving a Integer value, and too, this is a LOCAL variable because of the var
modifier that declare this variable in a way that you cannot access the value of it, unless if you are inside the same function that this variable was declared.
自动地,这被转换为Integer变量,因为它正在接收一个Integer值,并且这也是一个LOCAL变量,因为var修饰符以一种你无法访问它的值的方式声明这个变量,除非你在声明此变量的函数内部。
Example:
例:
If you declare these functions this way, with default modifiers:
如果以这种方式声明这些函数,使用默认修饰符:
function conflict(){
i = 2;
changeI();
alert(i);
}
function changeI(){
i = 0;
}
In this case the i
is the same variable for the two functions.
在这种情况下,i是两个函数的相同变量。
So if you execute conflict();
you will get a alert resulting 0
.
所以如果你执行conflict();你会得到一个警告0。
BUT, if you declare i
using the var
modifier:
但是,如果你声明我使用var修饰符:
function conflict(){
var i = 2;
changeI();
alert(i);
}
function changeI(){
var i = 0;
}
In this case, you have two i
variables, because they are restricted to use only inside their function, so if you execute conflict();
now, you will get a alert with value of 2
.
在这种情况下,您有两个i变量,因为它们仅限于在其函数内使用,因此如果执行conflict();现在,您将收到值为2的警报。
Class Variable:
类变量:
this.Variable = "a";
this.Variable =“a”;
This variable is automatically a String, because it is receiving a String value, Probably you already know what the this
modifier does, but, i'll try to explain with my point of view, that is this variable is coming from the SuperClass or in javascript a "SuperFunction" that can be called a Class, or in other words, the "father" class.
这个变量自动是一个String,因为它正在接收一个String值,可能你已经知道这个修饰符的作用了,但是,我会尝试用我的观点来解释,就是这个变量来自SuperClass或者javascript一个“SuperFunction”,可以称为Class,或者换句话说,就是“父”类。
A example:
一个例子:
function TClass()
{
this.getVar = function()
{
try
{
return "test";
}
catch(err)
{
return false;
}
}
this.alertVar = function()
{
try
{
alert(this.getVar());
}
catch(err)
{
alert('error');
}
}
}
var $Class = new TClass();
As you see above, i created a Class TClass
and some variables containing functions into it (javascript closure) and added the modifier this.
to them, to make them bound to the TClass
and as you see on the alertVar()
function, i access on the alert(this.getVar());
the function that are from the TClass
that is equal to this
in this context.
如上所示,我创建了一个Class TClass和一些包含函数的变量(javascript closure)并添加了修饰符this。对他们来说,为了让他们绑定到TClass,正如你在alertVar()函数中看到的那样,我可以访问警报(this.getVar());来自TClass的函数在此上下文中等于this。
And this part: var $Class = new TClass();
i am creating the class as you probably knew that, to have access to its methods, doing this i am possible to execute, to test:
这一部分:var $ Class = new TClass();我正在创建类,因为您可能知道,要访问其方法,执行此操作我可以执行,以测试:
$Class.alertVar();
And getting as result, an alertbox containing "test", as you can see:
得到结果,一个包含“test”的警告框,如您所见:
Note that you can't access the TClass
methods in another ways, you only can access it creating the class and accessing by it.
请注意,您无法以其他方式访问TClass方法,您只能访问它创建类并通过它进行访问。
So i hope that you did understand the usability of the this
modifier.
所以我希望你确实理解了这个修饰符的可用性。
Global:
全球:
window.Variable = true;
window.Variable = true;
Automatically javascript declare this variable is a boolean, because it is receiving a Boolean value. The window
modifier as it says, you can access it whatever you are on the window that you are, because javascript variables when declared, they go to the DOM into the window, see what is DOM:
自动javascript声明此变量是一个布尔值,因为它接收一个布尔值。正如它所说的窗口修饰符,无论你在窗口上是什么都可以访问它,因为javascript变量在声明时,它们会进入窗口,看看DOM是什么:
DOM(Document Object Model): The DOM, is a multi-platform that represents how the html,xhtml, and xml markup's are organized and read by the browser that you are using. In other words, if you access the DOM you can see every propery, every variable, or such of thing that exists on the browser at the moment.
DOM(文档对象模型):DOM是一个多平台,表示您正在使用的浏览器如何组织和读取html,xhtml和xml标记。换句话说,如果您访问DOM,您可以看到浏览器上存在的每个属性,每个变量或其他内容。
Different from another variables, the window
variables can have assigned another value and access the actual value, from whatever you are, inside a function or not, inside a js file or not.
与其他变量不同,窗口变量可以分配另一个值,并且无论您是否在函数内部,都可以在js文件内部访问实际值。
Example of Global(window):
全局(窗口)示例:
Execute on the onLoad
event of a page a code that declares a window
variable, or declare it yourself using browser console:
在页面的onLoad事件上执行声明窗口变量的代码,或者使用浏览器控制台自己声明:
window.Variable = true;
Then, add a JS File containing this function, or create it yourself just by executing the code on the browser console:
然后,添加一个包含此函数的JS文件,或者只需在浏览器控制台上执行代码即可自行创建:
function testGlobalVar(){
if (Variable)
alert("it works!");
}
When you execute testGlobalVar()
you will get the alert, but it is only because you declared it as `window´ otherwise, you will get nothing.
当你执行testGlobalVar()时,你会得到警告,但这只是因为你把它声明为“窗口”,否则你什么也得不到。
Default Modifier:
默认修饰符:
Variable = 0.5
变量= 0.5
Automatically this Variable is declared as Float beacuse it is receiving a Float value. I dont know if you already know, but javascript variables declared as the usual way, have a default modifier that makes the variable similar to window
variables, but you cannot access it from whatever you are, but in most cases you can acess it, particulary, i dont know all the cases that you cannot access it, but i know that you cant when you loaded a js file and it was declared inside it. Only if you run a function that declares it, and after that try to acesss.
自动将此变量声明为Float,因为它正在接收Float值。我不知道你是否已经知道,但javascript变量被声明为通常的方式,有一个默认的修饰符,使变量类似于窗口变量,但你不能从任何你访问它,但在大多数情况下你可以访问它,特别是,我不知道你无法访问它的所有情况,但我知道你不能加载一个js文件,并在它内部声明。只有当你运行一个声明它的函数,然后尝试访问。
By the way, i see that you want to know modifiers that match the three that you said, but at my tought some of that modifiers that i told you can be used to do the same that your c# modifiers do.
顺便说一句,我看到你想知道与你所说的三个匹配的修饰符,但在我看来,我告诉你的一些修饰符可以用来做你的c#修饰符那样做。
I hope that you understand what i'm saying.
我希望你明白我在说什么。
Ah, and if you was confused when you saw a function inside a variable, study Javascript Closures, you will understand after that :).
啊,如果你在变量中看到一个函数时感到困惑,研究Javascript Closures,你就会明白了:)。
#4
1
How the parent and child classes interact with each other
父类和子类如何相互交互
-
An extending child class calls
super.call
, a function that constructs an instance of it's parent.扩展子类调用super.call,这是一个构造其父实例的函数。
-
A parent class shares it's protected members (both fields and functions) to it's extending subclass by using
this.share
in it's constructor.父类通过在其构造函数中使用this.share将它的受保护成员(字段和函数)共享到它的扩展子类。
-
A subclass can also call
super.fetch()
, which returns the object of fields/functions that the parent class passed tothis.share
子类也可以调用super.fetch(),它返回父类传递给this.share的字段/函数的对象。
To illustrate my technique, the following code demonstrates some essentials to OOP with a simple example of a class Dog extends Animal
为了说明我的技术,下面的代码演示了OOP的一些基本要素,其中包含一个类似于Dog extends Animal的简单示例
Some core functions for this object oriented model
这种面向对象模型的一些核心功能
// runs in both node.js and browser
var global_namespace = ('undefined'==typeof module)? window: global;
// put a no-operation function in the value for `share` in case nothing is extending a class
var not_extendable = {share:function(){}};
// when something is extending a class...
var extendable = function(constructor) {
// create a space for protected fields
var protected_space = {};
// the following is what will get passed as `this` to the parent constructor
var sharing = {
share: function(fields) {
protected_space = fields;
},
};
// the following is what will get passed as the first arg to the child constructor
return {
// enables child to call its parent's constructor
call: function(args) {
return constructor.apply(sharing, args);
},
// allows child to access protected fields shared by its parent
fetch: function() {
return protected_space;
},
};
};
Animal
class
动物类
// class definition for `Animal`
(function(namespace) {
// construct an instance of this class
var constructor = function(name, weight, info) {
// private fields
var color = (info && info.color) || 'unknown';
// for protected fields
var protect = {
weight: weight,
noise: function() {
return 'nothing';
},
};
// share the protected fields with any subclass that might be extending this
this.share(protect);
// public fields and methods
return {
speak: function() {
console.log(name+' says '+protect.noise());
},
feed: function() {
console.log(name+' is not hungry');
},
weigh: function() {
console.log(name+' weighs '+protect.weight+' lbs');
},
toString: function() {
return '{Animal}';
},
};
};
// handle calls to: `Animal()`
namespace.Animal = function() {
// called with new operator: `new Animal(...)`
if(this !== namespace) {
// construct simple instance of this class
return constructor.apply(not_extendable, arguments);
}
// static call: `Animal(...)`, means the caller wants to extend this class
else {
// reference child constructor
var child_constructor = arguments[0];
// return a wrapped constructor function
return function() {
// call child constructor and allow it to call the super constructor
return child_constructor.apply({}, [extendable(constructor), arguments]);
};
}
};
})(global_namespace);
Dog
class
狗班
// class definition for `Dog`
(function(namespace) {
// class `Dog` extends class `Animal`
var constructor = Animal(function(super_class, args) {
// private field
var been_fed = false;
// call super's constructor
var operator = super_class.call(args);
// inherit parent's protected members
var parent = super_class.fetch();
// override a protected method
parent.noise = function() {
return 'bark!';
};
// override a public method
operator.feed = function() {
been_fed = true;
parent.weight += 5;
};
// extend a public method
var super_weigh = operator.weigh;
operator.weigh = function() {
super_weigh();
if(been_fed) console.log('\t'+args[0]+' has been eating :)');
else console.log('\t'+args[0]+' has not been fed yet');
};
// override another public method
operator.toString = function() {
return '{Dog}';
},
// return the operator (interfacable instance object)
return operator;
});
// handle calls to: `Dog()`
namespace.Dog = function() {
// called with new operator: `new Dog()`
if(this !== namespace) {
return constructor.apply(this, arguments);
}
// static call: `Dog()`
else {
// we do no allow extending class `Dog`
return false;
}
};
})(global_namespace);
So now, we can do this:
所以现在,我们可以这样做:
var giraffe = new Animal('Mr. Giraffe', 720);
giraffe.speak(); // "Mr. Giraffe says nothing"
giraffe.weigh(); // "Mr. Giraffe weighs 720 lbs"
var buddy = new Dog('Buddy', 50);
buddy.speak(); // "Buddy says bark!"
buddy.weigh(); // "Buddy weighs 50 lbs"
// "Buddy has not been fed yet"
buddy.feed();
buddy.weigh(); // "Buddy weighs 55 lbs"
// "Buddy has been eating :)"
This allows private, protected and public fields/functions. Both protected and public field/functions may be overwritten and extended.
这允许私有,受保护和公共字段/功能。受保护和公共字段/功能都可以被覆盖和扩展。
console.log(giraffe); // "{Animal}"
console.log(buddy); // "{Dog}"
#5
1
I have been working on another interesting javascript project and implemented something that may be closer to what you are looking for.
我一直在研究另一个有趣的javascript项目,并实现了一些可能更接近你正在寻找的东西。
Implement.js
Interested in you thoughts.
对你的想法感兴趣。