ECMAScript是基于原型实现的面向对象编程语言。
C = Class {a, b, c} // 类C, 包括特性a, b, c
C = Class {a, b, c, method1, method2}
c1 = {a: 10, b: 20, c: 30} // 类C是实例:对象с1
c2 = {a: 50, b: 60, c: 70} // 类C是实例:对象с2,拥有自己的状态(也就是属性值)
D = Class extends C = {d, e} // {a, b, c, d, e}
d1 = {a: 10, b: 20, c: 30, d: 40, e: 50}
d1.method1() // D.method1 (no) -> C.method1 (yes)
d1.method5() // D.method5 (no) -> C.method5 (no) -> no result
object = {a: 10, b: 20, c: 30, method: fn};
object.a; // 10
object.c; // 30
object.method();
object.method5 = function () {...}; // 添加新方法
object.d = 40; // 添加新属性 "d"
delete object.c; // 删除属性 "с"
object.a = 100; // 修改属性 "а"
// 结果是: object: {a: 100, b: 20, d: 40, method: fn, method5: fn};
原型是一个对象,它是用来作为其他对象的原始copy,或者如果一些对象没有自己的必要特性,原型可以作为这些对象的一个委托而当成辅助对象。
x = {a: 10, b: 20};
y = {a: 40, c: 50};
y.[[Prototype]] = x; // x是y的原型
y.a; // 40, 自身特性
y.c; // 50, 也是自身特性
y.b; // 20 – 从原型中获取: y.b (no) -> y.[[Prototype]].b (yes): 20
delete y.a; // 删除自身的"а"
y.a; // 10 – 从原型中获取
z = {a: 100, e: 50}
y.[[Prototype]] = z; // 将y的原型修改为z
y.a; // 100 – 从原型z中获取
y.e // 50, 也是从从原型z中获取
z.q = 200 // 添加新属性到原型上
y.q // 修改也适用于y
x = {a: 10}
y = {b: 20}
y.[[Prototype]] = x
z = {c: 30}
z.[[Prototype]] = y
z.a // 10
// z.a 在原型链里查到:
// z.a (no) ->
// z.[[Prototype]].a (no) ->
// z.[[Prototype]].[[Prototype]].a (yes): 10
var object = {
// catch住不能响应消息的系统信号
__noSuchMethod__: function (name, args) {
alert([name, args]);
if (name == 'test') {
return '.test() method is handled';
}
return delegate[name].apply(this, args);
}
};
var delegate = {
square: function (a) {
return a * a;
}
};
alert(object.square(10)); // 100
alert(object.test()); // .test() method is handled
// 在基于静态来的模型里
if (object instanceof SomeClass) {
// 一些行为是运行的
}
// 在动态实现里
// 对象在此时是什么类型并不重要
// 因为突变、类型、特性可以自由重复的转变。
// 重要的对象是否可以响应test消息
if (isFunction(object.test)) // ECMAScript
if object.respond_to?(:test) // Ruby
if hasattr(object, 'test'): // Python
# Python
class A(object):
def __init__(self, a):
self.a = a
def square(self):
return self.a * self.a
a = A(10) # 创建实例
print(a.a) # 10
A.b = 20 # 为类提供一个新属性
print(a.b) # 20 – 可以在"a"实例里访问到
a.b = 30 # 创建a自身的属性
print(a.b) # 30
del a.b # 删除自身的属性
print(a.b) # 20 - 再次从类里获取(原型)
# 就像基于原型的模型
# 可以在运行时改变对象的原型
class B(object): # 空类B
pass
b = B() # B的实例
b.__class__ = A # 动态改变类(原型)
b.a = 10 # 创建新属性
print(b.square()) # 100 - A类的方法这时候可用
# 可以显示删除类上的引用
del A
del B
# 但对象依然有隐式的引用,并且这些方法依然可用
print(b.square()) # 100
# 但这时候不能再改变类了
# 这是实现的特性
b.__class__ = dict # error
function test() {
alert([this.a, this.b]);
}
test.call({a: 10, b: 20}); // 10, 20
test.call({a: 100, b: 200}); // 100, 200
var a = 1;
var b = 2;
test(); // 1, 2
alert(Date.prototype.getTime.call(new Date())); // time
alert(Date.prototype.getTime.call(new String(''))); // TypeError
class A(object):
def __init__(self):
self.public = 10
self.__private = 20
def get_private(self):
return self.__private
# outside:
a = A() # A的实例
print(a.public) # OK, 30
print(a.get_private()) # OK, 20
print(a.__private) # 失败,因为只能在A里可用
# 但在Python里,可以通过特殊规则来访问
print(a._A__private) # OK, 20
class A
def initialize
@a = 10
end
def public_method
private_method(20)
end
private
def private_method(b)
return @a + b
end
end
a = A.new # 新实例
a.public_method # OK, 30
a.a # 失败, @a - 是私有的实例变量
# "private_method"是私有的,只能在A类里访问
a.private_method # 错误
# 但是有特殊的元数据方法名,可以获取到数据
a.send(:private_method, 20) # OK, 30
a.instance_variable_get(:@a) # OK, 10
function A() {
var _a; // "private" a
this.getA = function _getA() {
return _a;
};
this.setA = function _setA(a) {
_a = a;
};
}
var a = new A();
a.setA(10);
alert(a._a); // undefined, "private"
alert(a.getA()); // 10
eval('_a = 100', a.getA); // 或者a.setA,因为"_a"两个方法的[[Scope]]上
a.getA(); // 100
// Rhino
var foo = (function () {
var x = 10; // "private"
return function () {
print(x);
};
})();
foo(); // 10
foo.__parent__.x = 20;
foo(); // 20
var _myPrivateData = 'testString';
(function () {
// 初始化上下文
})();
// helper for augmentation
Object.extend = function (destination, source) {
for (property in source) if (source.hasOwnProperty(property)) {
destination[property] = source[property];
}
return destination;
};
var X = {a: 10, b: 20};
var Y = {c: 30, d: 40};
Object.extend(X, Y); // mix Y into X
alert([X.a, X.b, X.c, X.d]); 10, 20, 30, 40
var _delegate = {
foo: function () {
alert('_delegate.foo');
}
};
var agregate = {
delegate: _delegate,
foo: function () {
return this.delegate.foo.call(this);
}
};
agregate.foo(); // delegate.foo
agregate.delegate = {
foo: function () {
alert('foo from new delegate');
}
};
agregate.foo(); // foo from new delegate
function checkDecorator(originalFunction) {
return function () {
if (fooBar != 'test') {
alert('wrong parameter');
return false;
}
return originalFunction();
};
}
function test() {
alert('test function');
}
var testWithCheck = checkDecorator(test);
var fooBar = false;
test(); // 'test function'
testWithCheck(); // 'wrong parameter'
fooBar = 'test';
test(); // 'test function'
testWithCheck(); // 'test function'