function Obj() { this.property = 'Hello!' this.show = function () { alert(this.property) } } var obj = new Obj setTimeout(obj.show, 100) // alert('undefined')
show
property of the Obj
object, and passed it to setTimeout
, which simply called it — apart from Obj
, in the context of the window
. Here obj
for us is like a faceless array.bind()
was added to the Function
, fixing this in one position. function Base() { // . } Base.prototype.property = 'Hello!' Base.prototype.show = function () { alert(this.property) } function Child() { // . } // "". for (var prop in Base.prototype) { Child.prototype[prop] = Base.prototype[prop] } // (. ). Child.__super__ = Base.prototype Child.prototype.show = function () { // ? Child.__super__.show.call(this) }
setTimeout((new Child).show, 100)
.Foo.__super__.bar.apply(this, arguments)
is at least tedious and unaesthetic. And debugging of forgotten, untranslated links can be compared only with the study of black magic ... Child.reopen({ show: function (msg) { this._super(msg + '123') }, })
var Base = Sqimitive.Sqimitive.extend({ property: 'Hello', show: function (right) { alert(this.property + right) }, }) var Child = Base.extend({ property: 'Bye', events: { '=show': function (sup, right) { sup(this, [' World' + right]) }, }, }) ;(new Base).show('123') // alert('Hello123') ;(new Child).show('123') // alert('Bye World123')
var Base = Sqimitive.Sqimitive.extend({ // . }) var Child = Base.extend({ property: 'Bye', show: function (right) { Child.__super__.show.call(this, ' World' + right) }, })
sup(context, argArray)
. var Child = Base.extend({ events: { show: function (msg) { // - -, , // - . this.render() }, '-show': function (msg) { // - , - // , . if (msg.length < 3) { throw ' show() 3 .' } }, '+show': function (res) { // , . return '(' + res + ')' }, '=show': function (sup, msg) { // , . // . return '(' + sup(this, [msg + ' foo!']) + ')' }, }, })
var Child = Base.extend({ events: { // render() , show. . show: 'render', }, })
var Base = Sqimitive.Sqimitive.extend({ property: 'Hello', show: function (right) { alert(this.property + right) }, }) var base = new Base base.on('=show', function (sup) { sup(this, [' - I alert']) })
base.off('show')
var handlerID = base.on('=show', function (sup) { sup(this, [' - I alert']) }) base.off(handlerID)
var Bindable = Sqimitive.Sqimitive.extend({ // opt (option) Sqimitive attribute Backbone: // - . _opt: { // , . wasBound: false, }, events: { // postInit , . // owned - , . postInit: 'bindAll', // unnest . '-unnest': 'unbindAll', }, bindAll: function () { // ifSet true, . this.ifSet('wasBound', true) && this.bind(this) // sink , . return this.sink('bindALl') }, unbindAll: function () { if (this._parent && this.ifSet('wasBound', false)) { this.unbind(this) } return this.sink('unbindAll') }, // - // , . // , unbind. bind: function () { }, // bind - . , // bind. unbind: function (self) { // autoOff - stopListening. // , autoOff('event') - . . this.autoOff() }, })
var MyObject = Bindable.extend({ _opt: { someObject: null, // Sqimitive, "". }, events: { bind: function () { this.autoOff(this.get('someObject'), { event1: ..., event2: ..., }) }, }, }) new MyObject({someObject: new X})
MyObject
is created with the option (parameter) someObject
, to which two event handlers are then added: event1
and event2
. This is done via autoOff , which is similar to on , but adds this object to the list of dependencies and then, when unbind is called , autoOff () without parameters removes all the handlers of its object ( MyObject
) from all objects for which it was previously called ( someObject
).Sqimitive
base class for your application. this.autoOff(someObject, { // render() this change someObject. change: 'render', nest: 'render', }) // : someObject.on('change', function () { this.render.apply(this, arguments) }, this) someObject.on('nest', function () { this.nest.apply(this, arguments) }, this)
Sqimitive.Core
and Sqimitive.Sqimitive
. Core - event core, everything that I have already described above. Sqimitive is his successor, adding options and nesting.normalize_OPT
, responding to change_OPT
and change
- this will be change_OPT
below. var MyItem = Sqimitive.Sqimitive.extend({ // - . _opt: { complete: false, something: 'bar', }, }) var MyCollection = Sqimitive.Sqimitive.extend({ _childClass: MyItem, _childEvents: ['change', 'foobar'], _opt: { // , !complete. allowIncomplete: false, }, events: { // - , . change_allowIncomplete: function (newValue) { newValue || this.each(this._checkComplete, this) }, // - . '.change': '_checkComplete', // - , . '+nest': '_checkComplete', }, _checkComplete: function (sqim) { if (!this.get('allowIncomplete') && !sqim.get('complete')) { throw 'This collection only allows complete items!' } }, })
MyItem
, as indicated by the _childClass propertyfalse
if allowIncomplete
not set)false
, all attached objects are automatically scanned. var col = new MyCollection var item1 = new MyItem col.nest(item1) // exception var item2 = new MyItem({complete: true}) col.nest(item2) // okay item2.set('complete', false) // exception
var col = new MyCollection({allowIncomplete: true}) var item1 = new MyItem col.nest(item1) // okay col.set('allowIncomplete', false) // exception
change_allowIncomplete
). var col = new MyCollection col.nest( new MyItem({complete: true}) ) col.nest( new MyItem({something: 'item2'}) ) col.nest( new MyItem({complete: true, something: 'item3'}) ) var completeCounts = col.countBy(function (sqim) { return sqim.get('complete') ? 'done' : 'undone' }) // completeCounts = {done: 2, undone: 1} var isEveryComplete = col.every(function (sqim) { return sqim.get('complete') }) // isEveryComplete = false, complete == true. var allComplete = col.filter( Sqimitive.Sqimitive.picker('get', 'complete') ) // , picker() - , . // allComplete = [MyItem item1, MyItem item3] - complete == true. var firstComplete = col.find( Sqimitive.Sqimitive.picker('get', 'complete') ) // firstComplete = MyItem item1 ( complete == true). undefined, var doneUndone = col.partition( Sqimitive.Sqimitive.picker('get', 'complete') ) // doneUndone = [[item1, item3], [item2]] - , // , - . var firstChild = col.first() var lastChild = col.last() var parentKeys = col.keys() var three = col.length var item2 = col.at(1) var item2_3 = col.slice(1, 1) var somethings = col.invoke('get', 'something') // somethings = ['bar', 'item2', 'item3'] - // , col. var sorted = col.sortBy( Sqimitive.Sqimitive.picker('get', 'something') ) // sorted = [item1, item2, item3] - , // , . var serialized = col.invoke('get') // Backbone.Collection.toJSON(), shallow copy. col.invoke('render') // render() . . var cids = col.map(function (sqim) { return sqim._cid }) // cids = ['p11', 'p12', 'p13'] - invoke(), // . _cid - . col.each(function (sqim, key) { alert(key + ': ' + sqim._cid) }, col) // 3 col (this).
_updateSize
_checkInput
). var MyView = Sqimitive.Sqimitive.extend({ _opt: { name: '', surname: '', age: 900, }, events: { change: function (opt, value) { this.$('.' + opt).text(value) }, render: function () { this.el.empty() .append( $('<p class=name>').text(this.get('name')) ) .append( $('<p class=surname>').text(this.get('surname')) ) .append( $('<p class=age>').text(this.get('age')) ) }, }, })
var MyModel = Sqimitive.Sqimitive.extend({ _opt: { name: '', surname: '', age: 900, }, }) var MyView = Sqimitive.Sqimitive.extend({ _opt: { model: null, }, // , // <script id="MyView" type="text/template"> <template>. // , Sqimitive , , // . _template: _.template( '<p class="name"><%- name %></p>' + '<p class="surname"><%- surname %></p>' + '<p class="age"><%- age %></p>'), events: { // , change // , ( Backbone). change_model: function (newModel, oldModel) { // , . oldModel && oldModel.off(this) newModel.on('change', '_modelChanged', this) }, render: function () { // get() toJSON() Backbone, // (shallow copy). this.el.html( this._template(this.get('model').get()) ) }, }, _modelChanged: function (opt, value) { if (/^(name|surname|age)$/.test(opt)) { this.$('.' + opt).text(value) } }, })
var view = new MyView({ el: $('#foo'), model: new MyModel, }) // . , // . postInit, . view.render() view.get('model').set('name', '') // _modelChanged('name', '', '')
var MyList = Sqimitive.Sqimitive.extend({ // . _owning: false, _childClass: MyItem, _childEvents: ['change'], }) var item = new MyItem var list1 = new MyList list1.nest(item) var list2 = new MyList list2.nest(item) alert(list1.length + ' ' + list2.length) // alert('1 1')
var MyList = Sqimitive.Sqimitive.extend({ // true - . _owning: true, _childClass: MyItem, _childEvents: ['change'], }) var item = new MyItem var list1 = new MyList list1.nest(item) var list2 = new MyList list2.nest(item) alert(list1.length + ' ' + list2.length) // alert('0 1') alert(item._parent === list2) // alert('TRUE')
var MyView = Sqimitive.Sqimitive.extend({ el: {tag: 'aside', className: 'info'}, _opt: { // - . loaded: false, }, elEvents: { 'click .something': '_somethingClicked', }, events: { // render. . change_loaded: function (value) { this.el.toggleClass('loaded', value) }, render: function () { this.el.html('Click <u class="something">here</u>?') }, }, _somethingClicked: function (e) { alert(e.target.tagName + ' clicked!') }, }) var view = new MyView({el: $('body')}) view .render() // .attach() // DOM (elEvents) .set('loaded', true) // <aside class="info loaded">
var MyList = Sqimitive.Sqimitive.extend({ // el , <div>. // , DOM , , , // . el: false, // , . _childClass: MyItem, }) var MyViewItem = Sqimitive.Sqimitive.extend({ el: {tag: 'li'}, _opt: { model: null, // MyItem. // this.el . . attachPath: '.', }, events: { change_model: function (newModel, oldModel) { oldModel && oldModel.off(this) // , - // . MyList . // - unnested. newModel.on({ change: 'render', // remove - , // el (unnest , el ). // on this (3- ), remove // -unnest MyViewItem. '-unnest': 'remove', }, this) }, unnest: function () { // - MyViewItem // ( ). // , , . this.get('model') && this.get('model').off(this) }, render: function () { this.el.html(...) }, }, }) var MyViewList = Sqimitive.Sqimitive.extend({ el: {tag: 'ul'}, _childClass: MyViewItem, _opt: { list: null, // MyList. }, events: { change_list: function (newList, oldList) { oldList && oldList.off(this) newList.on('+nest', '_modelAdded', this) // newList. this.invoke('remove') newList.each(this._modelAdded, this) }, }, _modelAdded: function (sqim) { this.nest( new MyViewItem({model: sqim}) ) .render() }, })
el.appendTo(...)
— elEvents attach()
item.attach($('...'))
, el , elEvents var list = new MyList list.nest(new MyItem) // list.length == 1 var view = new MyViewList({list: list}) // view.length == 1 list.nest(new MyItem) // list.length == view.length == 2 list.at(1).remove() // list.length == view.length == 1 var list2 = new MyList view.set('list', list2) // list.length == 1 // list2.length == view.length == 0
Backbone.sync
, .$.ajax()
5 .Local Storage
, location.hash
. : assignChildren
assignResp
.normalize_OPT
, change_OPT
change
, set , . { 'thisID': 123, 'date': '2014-10-03T10:26:22+03:00', 'parents': '1 2 3', 'junk': 'ONk49Xo3SxEps8uCV9je8dhez', 'caption': '', }
var MyModel = Sqimitive.Sqimitive.extend({ // -. defaults Backbone. _opt: { id: 0, date: new Date, parents: [], caption: '', }, })
var MyModel = Sqimitive.Sqimitive.extend({ _opt: { id: 0, date: new Date, parents: [], caption: '', }, // assignResp , // . _respToOpt: { // . thisID: 'id', // . , // - , - . date: function (str) { return ['date', new Date(str)] }, // . junk: false, parents: function (str) { return ['parents', str.split(/\s+/)] }, // / . caption: 'caption'. caption: true, }, // , - , . normalize_id: function (value) { var id = parseInt(value) if (isNaN(id)) { throw 'What kind of ID is that?' } return id }, normalize_parents: function (value) { return _.map([].concat(value), this.normalize_id, this) }, normalize_caption: function (value) { return value.replace(/^\s+|\s+$/g, '') }, })
var model = new MyModel $.getJSON('api/route', _.bind(model.assignResp, model)) // POST: $.ajax({ url: 'api/route', type: 'POST', data: {...}, context: model, success: model.assignResp, })
class SomeObject: list = [] def push(self, value): self.list.append(value) return self print SomeObject().push('123').list #=> ['123'] print SomeObject().push('345').list #=> ['123', '456']
var SomeObject = Backbone.View.extend({ list: [], push: function (value) { this.list.push(value) return this }, }) console.dir( (new SomeObject).push('123').list ) //=> ['123'] console.dir( (new SomeObject).push('456').list ) //=> ['123', '456']
var MySqimitive = Sqimitive.Sqimitive.extend({ ... }) MySqimitive._shareProps.push('notToCloneSomething')
var MyView = Backbone.View.extend({ events: { 'click .me': function () { alert(' !') }, }, }) var MyOtherView = MyView.extend({ events: { 'keypress .me': function () { alert(' :(') }, }, })
events: _.extend(MyView.prototype.events, {...})
, events . ( ), . events , .base.concat(child)
, — _.extend(base, child)
( ). , , null
/ undefined
, .elEvents
, events
_opt
( _shareProps
) — Backbone Sqimitive : MyOtherView
. var MyBase = Sqimitive.Sqimitive.extend({ _opt: { base: 123, base2: 'kept', complex: {a: 1}, }, }) var MyChild = MyBase.extend({ _opt: { // 123. base: 'replaced', // {a: 1} - . complex: {b: 2}, // _opt. child: 'new', // base2 - . //base2: 'kept', }, })
nest(key, object)
ID var list = {11: obj1, 22: obj2, 33: obj3}
.$.each(list, _.bind(this.nest, this))
— , jQuery_.each(list, function (o, k) { this.nest(k, o) }, this)
_.each(Sqimitive.Sqimitive.masker('21'), this.nest, this)
$.ajax
. jQuery success , assignResp
, . , — jQuery . : $.getJSON('api/route', masker(model.assignResp, '.', model))
[]
(. expandFunc ). — , ( JSFiddle ): var MyView = Sqimitive.Sqimitive.extend({ // / . // . toggle: function (state) { arguments.length || (state = !this.$('.contents').is(':visible')) this.$('.contents').toggle(!!state) return this }, elEvents: { // . - . // , . 'click .toggle': 'toggle-', // jQuery event object, == true. 'click .show': 'toggle', // 9 jQuery , != true. // - toggle9. 'click .hide': 'toggle-9', }, })
elEvents: { 'click .toggle': function () { this.toggle() }, 'click .show': function () { this.toggle(true) }, 'click .hide': function () { this.toggle(false) }, },
Source: https://habr.com/ru/post/239149/
All Articles