Skip to content

Instantly share code, notes, and snippets.

@zhiyelee
Last active December 23, 2015 03:08
Show Gist options
  • Save zhiyelee/6571049 to your computer and use it in GitHub Desktop.
Save zhiyelee/6571049 to your computer and use it in GitHub Desktop.
yui oop demos

yui oop demo gist

  • merge mix

  • OOP

    • extend
    • augment
    • aggregate
  • bind rbind

var foo = {
0: 'foo',
1: 'name',
2: 'meituan'
};
var bar = {
0: 'bar',
1: 'name',
4: 'meituan',
length: 3
};
console.log(Array.prototype.slice.call(foo,0));
foo.length = 3;
console.log(Array.prototype.slice.call(foo,0));
console.log(Array.prototype.slice.call(bar,0));
// Object.keys which works well in both browser
// @source http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
// @discussion http://stackoverflow.com/questions/208016/how-to-list-the-properties-of-a-javascript-object/3937321
Object.keys = Object.keys || (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !{toString:null}.propertyIsEnumerable("toString"),
DontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
DontEnumsLength = DontEnums.length;
return function (o) {
if (typeof o != "object" && typeof o != "function" || o === null)
throw new TypeError("Object.keys called on a non-object");
var result = [];
for (var name in o) {
if (hasOwnProperty.call(o, name))
result.push(name);
}
if (hasDontEnumBug) {
for (var i = 0; i < DontEnumsLength; i++) {
if (hasOwnProperty.call(o, DontEnums[i]))
result.push(DontEnums[i]);
}
}
return result;
};
})();
// false in node
// console.log(this === global);
// true in browser
// console.log(this === window);
// undefined
console.log(a);
// will throw error
// ReferenceError: b is not defined
// 去掉下面一行的注释试试
// console.log(b);
var a = 10;
b = 20;
// delete 成功时返回值为true
// false
console.log(delete a);
// here 20
console.log(b);
// true, can delete
console.log(delete b);
// after delete ,still 10
console.log(a);
// here error
console.log(b);
/**
Augments the _receiver_ with prototype properties from the _supplier_. The
receiver may be a constructor function or an object. The supplier must be a
constructor function.
If the _receiver_ is an object, then the _supplier_ constructor will be called
immediately after _receiver_ is augmented, with _receiver_ as the `this` object.
If the _receiver_ is a constructor function, then all prototype methods of
_supplier_ that are copied to _receiver_ will be sequestered, and the
_supplier_ constructor will not be called immediately. The first time any
sequestered method is called on the _receiver_'s prototype, all sequestered
methods will be immediately copied to the _receiver_'s prototype, the
_supplier_'s constructor will be executed, and finally the newly unsequestered
method that was called will be executed.
This sequestering logic sounds like a bunch of complicated voodoo, but it makes
it cheap to perform frequent augmentation by ensuring that suppliers'
constructors are only called if a supplied method is actually used. If none of
the supplied methods is ever used, then there's no need to take the performance
hit of calling the _supplier_'s constructor.
@method augment
@param {Function|Object} receiver Object or function to be augmented.
@param {Function} supplier Function that supplies the prototype properties with
which to augment the _receiver_.
@param {Boolean} [overwrite=false] If `true`, properties already on the receiver
will be overwritten if found on the supplier's prototype.
@param {String[]} [whitelist] An array of property names. If specified,
only the whitelisted prototype properties will be applied to the receiver, and
all others will be ignored.
@param {Array|any} [args] Argument or array of arguments to pass to the
supplier's constructor when initializing.
@return {Function} Augmented object.
@for YUI
**/
Y.augment = function (receiver, supplier, overwrite, whitelist, args) {
var rProto = receiver.prototype,
sequester = rProto && supplier,
sProto = supplier.prototype,
to = rProto || receiver,
copy,
newPrototype,
replacements,
sequestered,
unsequester;
args = args ? Y.Array(args) : [];
if (sequester) {
newPrototype = {};
replacements = {};
sequestered = {};
copy = function (value, key) {
if (overwrite || !(key in rProto)) {
if (toString.call(value) === '[object Function]') {
sequestered[key] = value;
newPrototype[key] = replacements[key] = function () {
return unsequester(this, value, arguments);
};
} else {
newPrototype[key] = value;
}
}
};
unsequester = function (instance, fn, fnArgs) {
// Unsequester all sequestered functions.
for (var key in sequestered) {
if (hasOwn.call(sequestered, key)
&& instance[key] === replacements[key]) {
instance[key] = sequestered[key];
}
}
// Execute the supplier constructor.
supplier.apply(instance, args);
// Finally, execute the original sequestered function.
return fn.apply(instance, fnArgs);
};
if (whitelist) {
Y.Array.each(whitelist, function (name) {
if (name in sProto) {
copy(sProto[name], name);
}
});
} else {
Y.Object.each(sProto, copy, null, true);
}
}
Y.mix(to, newPrototype || sProto, overwrite, whitelist);
if (!sequester) {
supplier.apply(to, args);
}
return receiver;
};
// use debug version yui
var YUI = require('yui/debug').YUI;
YUI().use('oop', 'event-custom-base', function(Y) {
// EventTarget in `event-custom-base`
var Foo = function() {
/* code specific to Foo */
this.publish('interestingMoment');
};
Foo.prototype.doSomething = function() {
var eventData = {};
// -- do something interesting, add results to eventData --
eventData.statusText = 'bar';
// notify the subscribers, passing the event data
this.fire('interestingMoment', eventData);
}
Y.augment(Foo, Y.EventTarget);
var foo = new Foo();
// add some event listeners
foo.on('interestingMoment', function (data) {
console.log('I was notified of an interesting moment: ' + data.statusText);
});
foo.on('interestingMoment', function (data) {
console.log('I was also notified of an interesting moment: ' + data.statusText);
});
foo.doSomething();
});
var YUI = require('yui').YUI,
Y = YUI();
// if no var
var maxim = 'Talk is cheap,show me the code';
function foo(f) {
this.maxim = 'Code is poetry';
f();
}
function bar() {
console.log(this.maxim);
console.log(this === global);
}
//maxim = 'Talk is cheap,show me the code';
//bar(1,2,3,4);
var obj = {
maxim: 'the foolish wait'
};
Y.use('oop', function(Y) {
foo(bar);
foo(Y.bind(bar, obj));
});
/**
* Utility to set up the prototype, constructor and superclass properties to
* support an inheritance strategy that can chain constructors and methods.
* Static members will not be inherited.
*
* @method extend
* @param {function} r the object to modify.
* @param {function} s the object to inherit.
* @param {object} px prototype properties to add/override.
* @param {object} sx static properties to add/override.
* @return {object} the extended object.
*/
Y.extend = function(r, s, px, sx) {
if (!s || !r) {
Y.error('extend failed, verify dependencies');
}
var sp = s.prototype, rp = Y.Object(sp);
r.prototype = rp;
rp.constructor = r;
r.superclass = sp;
// assign constructor property
if (s != Object && sp.constructor == OP.constructor) {
sp.constructor = s;
}
// add prototype overrides
if (px) {
Y.mix(rp, px, true);
}
// add object overrides
if (sx) {
Y.mix(r, sx, true);
}
return r;
};
// use debug version yui
var YUI = require('yui').YUI;
YUI().use('oop', function(Y) {
function People(name) {
this.name = name || 'anonymous';
this.canEat = true;
}
People.prototype.getName = function () {
console.log('I am ' + this.name);
};
function Teacher() {
// can use superclass property to reference parent class
Teacher.superclass.constructor.apply(this, arguments);
}
Y.extend(Teacher, People, {
punish: function () {
console.log('As a teach, I usually punish students');
}
});
var teach = new Teacher();
teach.punish()
teach.getName();
console.log('teach.canEat ' + teach.canEat);
});
Y.merge = function () {
var i = 0,
len = arguments.length,
hasOwn = Object.prototype.hasOwnProperty,
result = {},
key,
obj;
for (; i < len; ++i) {
obj = arguments[i];
for (key in obj) {
// why not obj.hasOwnProperty(key)
if (hasOwn.call(obj, key)) {
result[key] = obj[key];
}
}
}
return result;
};
var YUI = require('yui').YUI,
Y,
defaultConfig,
result;
Y = YUI();
defaultConfig = {
canDisappear: false,
hideWhenNarrow: true
};
// 可以merge多个obj,后边的obj的属性会覆盖前边的,未提供配置项
result = Y.merge(defaultConfig,
{ canDisappear: true },
{ staticBottomEdge: true });
/*
info:
{ canDisappear: true,
hideWhenNarrow: true,
staticBottomEdge: true }
*/
Y.log(result);
// another demo
var foo = {
obj: {}
};
var copy = Y.merge(foo);
//copy.obj.addedToCopy = true;
console.log(copy === foo);
console.log(copy.obj === foo.obj);
/**
Mixes _supplier_'s properties into _receiver_.
Properties on _receiver_ or _receiver_'s prototype will not be overwritten or
shadowed unless the _overwrite_ parameter is `true`, and will not be merged
unless the _merge_ parameter is `true`.
In the default mode (0), only properties the supplier owns are copied (prototype
properties are not copied). The following copying modes are available:
* `0`: _Default_. Object to object.
* `1`: Prototype to prototype.
* `2`: Prototype to prototype and object to object.
* `3`: Prototype to object.
* `4`: Object to prototype.
@method mix
@param {Function|Object} receiver The object or function to receive the mixed
properties.
@param {Function|Object} supplier The object or function supplying the
properties to be mixed.
@param {Boolean} [overwrite=false] If `true`, properties that already exist
on the receiver will be overwritten with properties from the supplier.
@param {String[]} [whitelist] An array of property names to copy. If
specified, only the whitelisted properties will be copied, and all others
will be ignored.
@param {Number} [mode=0] Mix mode to use. See above for available modes.
@param {Boolean} [merge=false] If `true`, objects and arrays that already
exist on the receiver will have the corresponding object/array from the
supplier merged into them, rather than being skipped or overwritten. When
both _overwrite_ and _merge_ are `true`, _merge_ takes precedence.
@return {Function|Object|YUI} The receiver, or the YUI instance if the
specified receiver is falsy.
**/
Y.mix = function(receiver, supplier, overwrite, whitelist, mode, merge) {
var alwaysOverwrite, exists, from, i, key, len, to;
if (!receiver || !supplier) {
return receiver || Y;
}
if (mode) {
if (mode === 2) {
Y.mix(receiver.prototype, supplier.prototype, overwrite,
whitelist, 0, merge);
}
from = mode === 1 || mode === 3 ? supplier.prototype : supplier;
to = mode === 1 || mode === 4 ? receiver.prototype : receiver;
if (!from || !to) {
return receiver;
}
} else {
from = supplier;
to = receiver;
}
alwaysOverwrite = overwrite && !merge;
if (whitelist) {
for (i = 0, len = whitelist.length; i < len; ++i) {
key = whitelist[i];
if (!hasOwn.call(from, key)) {
continue;
}
exists = alwaysOverwrite ? false : key in to;
if (merge && exists && isObject(to[key], true)
&& isObject(from[key], true)) {
Y.mix(to[key], from[key], overwrite, null, 0, merge);
} else if (overwrite || !exists) {
to[key] = from[key];
}
}
} else {
for (key in from) {
// duplication,same as above,for performance tradeoff
}
if (Y.Object._hasEnumBug) {
Y.mix(to, from, overwrite, Y.Object._forceEnum, mode, merge);
}
}
return receiver;
};
var YUI = require('yui').YUI,
Y = YUI();
function Person(name) {
this.name = 'init person';
this.eat = function() {
console.log(this.name + "is eating.");
};
}
Person.prototype.sleep = function() {
console.log(this.name + "is sleeping.");
};
function Manong(name) {
this.name = name;
}
Manong.prototype.coding = function () {
console.log(this.name + "is coding.");
};
// mode 1
Y.mix(Manong, Person, true, null, 1);
// [Function: Manong]
console.log(Manong);
// { coding: [Function], sleep: [Function] }
console.log(Manong.prototype);
// // mod2
// Person.pattr1 = "person attr1";
// Manong.mattr1 = "manong attr1";
// Y.mix(Manong, Person, true, null, 2);
// // { [Function: Manong] mattr1: 'manong attr1', pattr1: 'person attr1' }
// console.log(Manong);
// // { coding: [Function], sleep: [Function] }
// console.log(Manong.prototype);
// // mod3
// Y.mix(Manong, Person, true, null, 3);
// // { [Function: Manong] sleep: [Function] }
// console.log(Manong);
// // { coding: [Function] }
// console.log(Manong.prototype);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment