ecomfe / oo Goto Github PK
View Code? Open in Web Editor NEWBase library for OO style programming
License: MIT License
Base library for OO style programming
License: MIT License
如果我们写ES6:
import oo from 'eoo';
/**
* 用户信息面板类
*
* @class common.Account
*/
class Account {
/**
* 初始化
*
* @method common.Account#init
*/
init() {
// ...
}
}
oo.defineAccessor(Account.prototype, 'globalData');
oo.defineAccessor(Account.prototype, 'widgetContainer');
oo.defineAccessor(Account.prototype, 'templateEngine');
这个defineAccessor
就比较奇怪,是不是能有个defineAccessorFor
方法,直接给class?
之前只能在创建类的时候传入原型链对象,无法尽早看到继承关系,增加后的代码可以下面这样:
var A = Class();
var exports = { //xx };
Class.defineMembers(A, exports);
相当于Object.create
,以下是摘自MDN的代码:
if (typeof Object.create != 'function') {
(function () {
var F = function () {};
Object.create = function (o) {
if (arguments.length > 1) { throw Error('Second argument not supported');}
if (o === null) { throw Error('Cannot set a null [[Prototype]]');}
if (typeof o != 'object') { throw TypeError('Argument must be an object');}
F.prototype = o;
return new F();
};
})();
}
示例代码:
let Super = oo.create({});
let Sub = function () {};
Object.setPrototypeOf(Sub, Super);
Sub.toString(); // StackOverflow
原因分析:
kclass.toString
toString
的实现实际上是this.prototype.constructor.toString()
Object.setPrototypeOf
会让Sub.toString
与Super.toString
相同Sub.prototype.constructor
其实就是Sub
自身toString()
会导致死循环更进一步:
这个问题不仅仅存在于setPrototypeOf
上,当一个“继承”函数同时满足以下条件:
prototype.constructor
为自身的情况下,这个toString()
就会导致死循环
即给类对象增加快捷继承出一个新类的方法:
var Super = Class(superExports);
var Sub = Super.extend(SubExports);
等价:
var Super = Class(superExports);
var Sub = Class(Super, SubExports);
RT
有群众普遍反映,在console中看通过eoo.create
创建出来的类,是一堆klass
,完全看不出具体是哪个类
我是这么想的,像在java之类的语言中,有一个重要的特性叫反射,即可以将类、方法、参数的元信息提取出来,用于动态地操作这个类,而eoo
可以借鉴一下这一点
我设想的思路是,变成eoo.create({Function} parent, {Object} exports, {Object} meta)
,其中meta
我们暂定包含一个name
属性,后续可以扩充
当有meta
参数时,取里面的name
属性来动态生成类名(用new Function
生成就行),在之后也能再加accessibility: 'public | internal | private'
之类的其它数据
然后eoo
提供一个getMetaOf(someClass)
的方法来获取这些元信息,方法名是参考Object.getPrototypeOf
和Object.getOwnPropertyDescriptor
来的
以前觉得为了调试来加一个参数是不好的,现在想想从元数据的角度来看,似乎能合理解释
有时候setter
和getter
是有逻辑的,但是又希望可以利用oo
隐藏掉具体的属性强制只能使用getter
访问,是否有可能实现类似的功能。
有2个想法,第一种是静态方法:
exports.setFoo = function (value) {
value.bar = true;
oo.set(this, 'foo', value);
};
exports.getFoo = function () {
var value = oo.get(this, 'foo');
value.bar = false;
return value;
};
第二种是hook模式:
oo.defineAccessor(
exports,
'foo',
{
getHook: function (value) {
// value是oo拿到的
value.bar = false;
return value; // 返回给外面
},
setHook: function (value) {
// value是传进来的
value.bar = true;
return value; // 随后会被真正set
}
}
);
https://github.com/ecomfe/oo/blob/master/src/oo.js#L138
这里会无限递归,因为默认constructor
指向自己
var exports = {};
exports.$privae = {};
exports.$private.privateMethod = function () {};
exports.$private.privateMember = 'private';
exports.publicMethod = function () {
this.privateMethod();
};
var MyClass = oo.Class(exports);
var instance = new MyClass();
instance.publishMethod();
instance.privateMethod() // throw error;
instance.privateMember() // throw error
实现上:
会借助Object.defineProperty的 getter/setter 和 caller__owner__ 来做限制,ie8下不做支持,毕竟我们的开发调试流程是在支持es5的环境下下进行的,仅仅是定义了开发模型,不会对 ie8造成功能影响。
我们的开源项目应该都是基于 BSD 的,现在 oo
的 package.json
里用了 GPL,改掉吧不然不好搞了……
用于给类定义静态成员:
var A = Class();
var statics = { staticA: 1 };
Class.defineStatics(A, statics);
A.staticA; // 1
实现见: https://github.com/ecomfe/oo/tree/feature/private-weakmap-like
使用方式如下:
// User.js
var $private = oo.createPrivate({
privateMethod: function () {
// 获取私有属性
return $private(this).privateProp;
},
privateProp: 'private'
});
var exports = {
constructor: function () {
this.$super(arguments);
// 设置实例上的私有属性
$private(this).instancePrivateProp = 'instance';
},
publicMethod: function () {
// 调用私有方法
var result = $private(this).privateMethod.call(this);
return result + $private(this).instancePrivateProp;
}
};
var User = oo.create(exports);
优点在于:
不足在于:
@otakustay @Justineo 我个人倾向于用类 weakmap 的实现方案
在我们放弃IE8后,我的视野好像确实大了些- -
希望提供一个definePropertyAccessor
的功能,使用defineProeprty
来定义一个getter/setter的属性,功能和现在的defineAccessor
是一样的就行
这里不使用普通的属性,而是要一个没有逻辑的getter/setter,目的是让uioc能更好地发现需要注入的属性而实现自动注入功能
当传入非object/function
类型参数时,Object.create
返回的类的实例调用this.$super报错。因此,对非object/function
型参数需要进行处理。
如:
var A = Class.create(1, {
constructor: function () {
this.$super(arguments);
}
});
new A(); // TypeError: Cannot read property 'constructor' of undefined
类似require('eoo').defineSimpleGetterAndSetter(exports, 'globalData')
使用者无法直接通过 this.globalData访问到属性,需要通过 set/getGlobalData方式获取
大概这样的代码:
class Foo {
}
let Bar = require('eoo').create(Foo);
new Bar();
如果不做任何编译,直接在支持class的环境下跑,会有这样的错:
TypeError: Class constructor Foo cannot be invoked without 'new'
Object.create
可以接收null
作为参数,Class.static
的实现接收null
时会抛异常。
RT,有时候基类来自其它库,其它库没有使用oo
,则会让$super(arguments)
不能用
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.