backbonejs
Web前端框架技术综述
58软件开发与应用Software Development And Application电子技术与软件工程Electronic Technology & Software Engineering●社科项目:武汉职业技术学院2020年社科项目(2020YJ010)。
1 引言1995年,网景公司发布第一款商业浏览器Netscape Navigator ,为了提高网页互动性,网景公司设计出第一个能够在浏览器端运行的脚本语言,命名为LiveScript 。
为了借助Java 语言的营销效应,遂改名为JavaScript 。
1996年,微软发布VBScript 和Jscript 两个脚本语言,内置于其IE 浏览器中。
为了确保JavaScript 占有市场领导地位,网景公司将JavaScript 提交到欧洲计算机制造商协会(ECMA )以便将其进行国际标准化,产生了ECMAScript 。
为了取得浏览器市场,网景公司在1998年成立了Mozilla 开源项目,准备开发下一代浏览器。
2003年,苹果公司发布了Safari 。
随着浏览器产品越来越多,即使有了ECMAScript 标准,但是由于标准制定较晚,所以每个浏览器都有各自的标准。
网页开发人员需要对同一个功能编写出多份代码,以适应不同浏览器。
直到2006年,John Resig 编写出jQuery ,封装实现浏览器兼容的JavaScript 细节代码,从此解决了网页开发人员处理网页兼容性问题的痛点,极大简化了前端编程。
直到今天jQuery 仍旧是使用最广泛的框架之一。
随着MVC 设计模式广泛应用于前端开发当中,Angular JS, Backbone JS, React JS, Vue JS 依次诞生并为大家所广泛使用。
本文将详细介绍五种框架的原理及优缺点,为立志于与做前端开发的学生普及框架知识,同时给出学习和实践中选择框架的建议和启示。
2 五大主流框架介绍下面按照前端框架诞生的时间线,依次讲解jQuery 、Angular JS 、BackBone JS 、React JS 、Vue JS 这五种广泛流行的框架。
Backbone源码解析
// Backbone.js 0.9.2// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.// Backbone may be freely distributed under the MIT license.// For all details and documentation:// (function() {// 创建一个全局对象, 在浏览器中表示为window对象, 在Node.js中表示global对象var root = this;// 保存"Backbone"变量被覆盖之前的值// 如果出现命名冲突或考虑到规范, 可通过Backbone.noConflict()方法恢复该变量被Backbone占用之前的值, 并返回Backbone对象以便重新命名var previousBackbone = root.Backbone;// 将Array.prototype中的slice和splice方法缓存到局部变量以供调用var slice = Array.prototype.slice;var splice = Array.prototype.splice;var Backbone;if ( typeof exports !== 'undefined') {Backbone = exports;} else {Backbone = root.Backbone = {};}// 定义Backbone版本Backbone.VERSION = '0.9.2';// 在服务器环境下自动导入Underscore, 在Backbone中部分方法依赖或继承自Underscorevar _ = root._;if (!_ && ( typeof require !== 'undefined'))_ = require('underscore');// 定义第三方库为统一的变量"$", 用于在视图(View), 事件处理和与服务器数据同步(sync)时调用库中的方法// 支持的库包括jQuery, Zepto等, 它们语法相同, 但Zepto更适用移动开发, 它主要针对Webkit内核浏览器// 也可以通过自定义一个与jQuery语法相似的自定义库, 供Backbone使用(有时我们可能需要一个比jQuery, Zepto更轻巧的自定义版本)// 这里定义的"$"是局部变量, 因此不会影响在Backbone框架之外第三方库的正常使用var $ = root.jQuery || root.Zepto || root.ender;// 手动设置第三方库// 如果在导入了Backbone之前并没有导入第三方库, 可以通过setDomLibrary方法设置"$"局部变量// setDomLibrary方法也常用于在Backbone中动态导入自定义库Backbone.setDomLibrary = function(lib) {$ = lib;};// 放弃以"Backbone"命名框架, 并返回Backbone对象, 一般用于避免命名冲突或规范命名方式// 例如:// var bk = Backbone.noConflict(); // 取消"Backbone"命名, 并将Backbone对象存放于bk变量中// console.log(Backbone); // 该变量已经无法再访问Backbone对象, 而恢复为Backbone定义前的值// var MyBackbone = bk; // 而bk存储了Backbone对象, 我们将它重命名为MyBackboneBackbone.noConflict = function() {root.Backbone = previousBackbone;return this;};// 对于不支持REST方式的浏览器, 可以设置Backbone.emulateHTTP = true// 与服务器请求将以POST方式发送, 并在数据中加入_method参数标识操作名称, 同时也将发送X-HTTP-Method-Override头信息Backbone.emulateHTTP = false;// 对于不支持application/json编码的浏览器, 可以设置Backbone.emulateJSON = true;// 将请求类型设置为application/x-www-form-urlencoded, 并将数据放置在model参数中实现兼容Backbone.emulateJSON = false;// Backbone.Events 自定义事件相关// -----------------// eventSplitter指定处理多个事件时, 事件名称的解析规则var eventSplitter = /\s+/;// 自定义事件管理器// 通过在对象中绑定Events相关方法, 允许向对象添加, 删除和触发自定义事件var Events = Backbone.Events = {// 将自定义事件(events)和回调函数(callback)绑定到当前对象// 回调函数中的上下文对象为指定的context, 如果没有设置context则上下文对象默认为当前绑定事件的对象// 该方法类似与DOM Level2中的addEventListener方法// events允许指定多个事件名称, 通过空白字符进行分隔(如空格, 制表符等)// 当事件名称为"all"时, 在调用trigger方法触发任何事件时, 均会调用"all"事件中绑定的所有回调函数on : function(events, callback, context) {// 定义一些函数中使用到的局部变量var calls, event, node, tail, list;// 必须设置callback回调函数if (!callback)return this;// 通过eventSplitter对事件名称进行解析, 使用split将多个事件名拆分为一个数组// 一般使用空白字符指定多个事件名称events = events.split(eventSplitter);// calls记录了当前对象中已绑定的事件与回调函数列表calls = this._callbacks || (this._callbacks = {});// 循环事件名列表, 从头至尾依次将事件名存放至event变量while ( event = events.shift()) {// 获取已经绑定event事件的回调函数// list存储单个事件名中绑定的callback回调函数列表// 函数列表并没有通过数组方式存储, 而是通过多个对象的next属性进行依次关联/** 数据格式如:* {* tail: {Object},* next: {* callback: {Function},* context: {Object},* next: {* callback: {Function},* context: {Object},* next: {Object}* }* }* }*/// 列表每一层next对象存储了一次回调事件相关信息(函数体, 上下文和下一次回调事件)// 事件列表最顶层存储了一个tail对象, 它存储了最后一次绑定回调事件的标识(与最后一次回调事件的next指向同一个对象)// 通过tail标识, 可以在遍历回调列表时得知已经到达最后一个回调函数list = calls[event];// node变量用于记录本次回调函数的相关信息// tail只存储最后一次绑定回调函数的标识// 因此如果之前已经绑定过回调函数, 则将之前的tail指定给node作为一个对象使用, 然后创建一个新的对象标识给tail// 这里之所以要将本次回调事件添加到上一次回调的tail对象, 是为了让回调函数列表的对象层次关系按照绑定顺序排列(最新绑定的事件将被放到最底层)node = list ? list.tail : {};node.next = tail = {};// 记录本次回调的函数体及上下文信息node.context = context;node.callback = callback;// 重新组装当前事件的回调列表, 列表中已经加入了本次回调事件calls[event] = {tail : tail,next : list ? list.next : node};}// 返回当前对象, 方便进行方法链调用return this;},// 移除对象中已绑定的事件或回调函数, 可以通过events, callback和context对需要删除的事件或回调函数进行过滤// - 如果context为空, 则移除所有的callback指定的函数// - 如果callback为空, 则移除事件中所有的回调函数// - 如果events为空, 但指定了callback或context, 则移除callback或context指定的回调函数(不区分事件名称)// - 如果没有传递任何参数, 则移除对象中绑定的所有事件和回调函数off : function(events, callback, context) {var event, calls, node, tail, cb, ctx;// No events, or removing *all* events.// 当前对象没有绑定任何事件if (!( calls = this._callbacks))return;// 如果没有指定任何参数, 则移除所有事件和回调函数(删除_callbacks属性)if (!(events || callback || context)) {delete this._callbacks;return this;}// 解析需要移除的事件列表// - 如果指定了events, 则按照eventSplitter对事件名进行解析// - 如果没有指定events, 则解析已绑定所有事件的名称列表events = events ? events.split(eventSplitter) : _.keys(calls);// 循环事件名列表while ( event = events.shift()) {// 将当前事件对象从列表中移除, 并缓存到node变量中node = calls[event];delete calls[event];// 如果不存在当前事件对象(或没有指定移除过滤条件, 则认为将移除当前事件及所有回调函数), 则终止此次操作(事件对象在上一步已经移除)if (!node || !(callback || context))continue;// Create a new list, omitting the indicated callbacks.// 根据回调函数或上下文过滤条件, 组装一个新的事件对象并重新绑定tail = node.tail;// 遍历事件中的所有回调对象while (( node = node.next) !== tail) {cb = node.callback;ctx = node.context;// 根据参数中的回调函数和上下文, 对回调函数进行过滤, 将不符合过滤条件的回调函数重新绑定到事件中(因为事件中的所有回调函数在上面已经被移除)if ((callback && cb !== callback) || (context && ctx !== context)) {this.on(event, cb, ctx);}}}return this;},// 触发已经定义的一个或多个事件, 依次执行绑定的回调函数列表trigger : function(events) {var event, node, calls, tail, args, all, rest;// 当前对象没有绑定任何事件if (!( calls = this._callbacks))return this;// 获取回调函数列表中绑定的"all"事件列表all = calls.all;// 将需要触发的事件名称, 按照eventSplitter规则解析为一个数组events = events.split(eventSplitter);// 将trigger从第2个之后的参数, 记录到rest变量, 将依次传递给回调函数rest = slice.call(arguments, 1);// 循环需要触发的事件列表while ( event = events.shift()) {// 此处的node变量记录了当前事件的所有回调函数列表if ( node = calls[event]) {// tail变量记录最后一次绑定事件的对象标识tail = node.tail;// node变量的值, 按照事件的绑定顺序, 被依次赋值为绑定的单个回调事件对象// 最后一次绑定的事件next属性, 与tail引用同一个对象, 以此作为是否到达列表末尾的判断依据while (( node = node.next) !== tail) {// 执行所有绑定的事件, 并将调用trigger时的参数传递给回调函数node.callback.apply(node.context || this, rest);}}// 变量all记录了绑定时的"all"事件, 即在调用任何事件时, "all"事件中的回调函数均会被执行// - "all"事件中的回调函数无论绑定顺序如何, 都会在当前事件的回调函数列表全部执行完毕后再依次执行// - "all"事件应该在触发普通事件时被自动调用, 如果强制触发"all"事件, 事件中的回调函数将被执行两次if ( node = all) {tail = node.tail;// 与调用普通事件的回调函数不同之处在于, all事件会将当前调用的事件名作为第一个参数传递给回调函数args = [event].concat(rest);// 遍历并执行"all"事件中的回调函数列表while (( node = node.next) !== tail) {node.callback.apply(node.context || this, args);}}}return this;}};// 绑定事件与释放事件的别名, 也为了同时兼容Backbone以前的版本Events.bind = Events.on;Events.unbind = Events.off;// Backbone.Model 数据对象模型// --------------// Model是Backbone中所有数据对象模型的基类, 用于创建一个数据模型// @param {Object} attributes 指定创建模型时的初始化数据// @param {Object} options* @format options* {* parse: {Boolean},* collection: {Collection}* }*/var Model = Backbone.Model = function(attributes, options) {// defaults变量用于存储模型的默认数据var defaults;// 如果没有指定attributes参数, 则设置attributes为空对象attributes || ( attributes = {});// 设置attributes默认数据的解析方法, 例如默认数据是从服务器获取(或原始数据是XML格式), 为了兼容set方法所需的数据格式, 可使用parse方法进行解析if (options && options.parse)attributes = this.parse(attributes);if ( defaults = getValue(this, 'defaults')) {// 如果Model在定义时设置了defaults默认数据, 则初始化数据使用defaults与attributes参数合并后的数据(attributes中的数据会覆盖defaults中的同名数据)attributes = _.extend({}, defaults, attributes);}// 显式指定模型所属的Collection对象(在调用Collection的add, push等将模型添加到集合中的方法时, 会自动设置模型所属的Collection对象)if (options && options.collection)this.collection = options.collection;// attributes属性存储了当前模型的JSON对象化数据, 创建模型时默认为空this.attributes = {};// 定义_escapedAttributes缓存对象, 它将缓存通过escape方法处理过的数据this._escapedAttributes = {};// 为每一个模型配置一个唯一标识this.cid = _.uniqueId('c');// 定义一系列用于记录数据状态的对象, 具体含义请参考对象定义时的注释this.changed = {};this._silent = {};this._pending = {};// 创建实例时设置初始化数据, 首次设置使用silent参数, 不会触发change事件this.set(attributes, {silent : true});// 上面已经设置了初始化数据, changed, _silent, _pending对象的状态可能已经发生变化, 这里重新进行初始化this.changed = {};this._silent = {};this._pending = {};// _previousAttributes变量存储模型数据的一个副本// 用于在change事件中获取模型数据被改变之前的状态, 可通过previous或previousAttributes方法获取上一个状态的数据this._previousAttributes = _.clone(this.attributes);// 调用initialize初始化方法this.initialize.apply(this, arguments);// 使用extend方法为Model原型定义一系列属性和方法_.extend(Model.prototype, Events, {// changed属性记录了每次调用set方法时, 被改变数据的key集合changed : null,// // 当指定silent属性时, 不会触发change事件, 被改变的数据会记录下来, 直到下一次触发change事件// _silent属性用来记录使用silent时的被改变的数据_silent : null,_pending : null,// 每个模型的唯一标识属性(默认为"id", 通过修改idAttribute可自定义id属性名)// 如果在设置数据时包含了id属性, 则id将会覆盖模型的id// id用于在Collection集合中查找和标识模型, 与后台接口通信时也会以id作为一条记录的标识idAttribute : 'id',// 模型初始化方法, 在模型被构造结束后自动调用initialize : function() {},// 返回当前模型中数据的一个副本(JSON对象格式)toJSON : function(options) {return _.clone(this.attributes);},// 根据attr属性名, 获取模型中的数据值get : function(attr) {return this.attributes[attr];},// 根据attr属性名, 获取模型中的数据值, 数据值包含的HTML特殊字符将被转换为HTML实体, 包含 & < > " ' \// 通过 _.escape方法实现escape : function(attr) {var html;// 从_escapedAttributes缓存对象中查找数据, 如果数据已经被缓存则直接返回if ( html = this._escapedAttributes[attr])return html;// _escapedAttributes缓存对象中没有找到数据// 则先从模型中获取数据var val = this.get(attr);// 将数据中的HTML使用 _.escape方法转换为实体, 并缓存到_escapedAttributes对象, 便于下次直接获取return this._escapedAttributes[attr] = _.escape(val == null ? '' : ''+ val);},// 检查模型中是否存在某个属性, 当该属性的值被转换为Boolean类型后值为false, 则认为不存在// 如果值为false, null, undefined, 0, NaN, 或空字符串时, 均会被转换为falsehas : function(attr) {return this.get(attr) != null;},// 设置模型中的数据, 如果key值不存在, 则作为新的属性添加到模型, 如果key值已经存在, 则修改为新的值set : function(key, value, options) {// attrs变量中记录需要设置的数据对象var attrs, attr, val;// 参数形式允许key-value对象形式, 或通过key, value两个参数进行单独设置// 如果key是一个对象, 则认定为使用对象形式设置, 第二个参数将被视为options参数if (_.isObject(key) || key == null) {attrs = key;options = value;} else {// 通过key, value两个参数单独设置, 将数据放到attrs对象中方便统一处理attrs = {};attrs[key] = value;}// options配置项必须是一个对象, 如果没有设置options则默认值为一个空对象options || ( options = {});// 没有设置参数时不执行任何动作if (!attrs)return this;// 如果被设置的数据对象属于Model类的一个实例, 则将Model对象的attributes数据对象赋给attrs// 一般在复制一个Model对象的数据到另一个Model对象时, 会执行该动作if ( attrs instanceof Model)attrs = attrs.attributes;// 如果options配置对象中设置了unset属性, 则将attrs数据对象中的所有属性重置为undefined// 一般在复制一个Model对象的数据到另一个Model对象时, 但仅仅需要复制Model中的数据而不需要复制值时执行该操作if (options.unset)for (attr in attrs)attrs[attr] =void 0;// 对当前数据进行验证, 如果验证未通过则停止执行if (!this._validate(attrs, options))return false;// 如果设置的id属性名被包含在数据集合中, 则将id覆盖到模型的id属性// 这是为了确保在自定义id属性名后, 访问模型的id属性时, 也能正确访问到idif (this.idAttribute in attrs)this.id = attrs[this.idAttribute];var changes = options.changes = {};// now记录当前模型中的数据对象var now = this.attributes;// escaped记录当前模型中通过escape缓存过的数据var escaped = this._escapedAttributes;// prev记录模型中数据被改变之前的值var prev = this._previousAttributes || {};// 遍历需要设置的数据对象for (attr in attrs) {// attr存储当前属性名称, val存储当前属性的值val = attrs[attr];// 如果当前数据在模型中不存在, 或已经发生变化, 或在options中指定了unset属性删除, 则删除该数据被换存在_escapedAttributes中的数据if (!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) {// 仅删除通过escape缓存过的数据, 这是为了保证缓存中的数据与模型中的真实数据保持同步delete escaped[attr];// 如果指定了silent属性, 则此次set方法调用不会触发change事件, 因此将被改变的数据记录到_silent属性中, 便于下一次触发change事件时, 通知事件监听函数此数据已经改变// 如果没有指定silent属性, 则直接设置changes属性中当前数据为已改变状态(options.silent ? this._silent : changes)[attr] = true;}// 如果在options中设置了unset, 则从模型中删除该数据(包括key)// 如果没有指定unset属性, 则认为将新增或修改数据, 向模型的数据对象中加入新的数据options.unset ?delete now[attr] : now[attr] = val;// 如果模型中的数据与新的数据不一致, 则表示该数据已发生变化if (!_.isEqual(prev[attr], val) || (_.has(now, attr) != _.has(prev, attr))) { // 在changed属性中记录当前属性已经发生变化的状态this.changed[attr] = val;if (!options.silent)this._pending[attr] = true;} else {// 如果数据没有发生变化, 则从changed属性中移除已变化状态delete this.changed[attr];delete this._pending[attr];}}// 调用change方法, 将触发change事件绑定的函数if (!options.silent)this.change(options);return this;},// 从当前模型中删除指定的数据(属性也将被同时删除)unset : function(attr, options) {(options || ( options = {})).unset = true;// 通过options.unset配置项告知set方法进行删除操作return this.set(attr, null, options);},// 清除当前模型中的所有数据和属性clear : function(options) {(options || ( options = {})).unset = true;// 克隆一个当前模型的属性副本, 并通过options.unset配置项告知set方法执行删除操作return this.set(_.clone(this.attributes), options);},// 从服务器获取默认的模型数据, 获取数据后使用set方法将数据填充到模型, 因此如果获取到的数据与当前模型中的数据不一致, 将会触发change事件fetch : function(options) {// 确保options是一个新的对象, 随后将改变options中的属性options = options ? _.clone(options) : {};var model = this;// 在options中可以指定获取数据成功后的自定义回调函数var success = options.success;// 当获取数据成功后填充数据并调用自定义成功回调函数options.success = function(resp, status, xhr) {// 通过parse方法将服务器返回的数据进行转换// 通过set方法将转换后的数据填充到模型中, 因此可能会触发change事件(当数据发生变化时)// 如果填充数据时验证失败, 则不会调用自定义success回调函数if (!model.set(model.parse(resp, xhr), options))return false;// 调用自定义的success回调函数if (success)success(model, resp);};// 请求发生错误时通过wrapError处理error事件options.error = Backbone.wrapError(options.error, model, options);// 调用sync方法从服务器获取数据return (this.sync || Backbone.sync).call(this, 'read', this, options);},// 保存模型中的数据到服务器save : function(key, value, options) {// attrs存储需要保存到服务器的数据对象var attrs, current;// 支持设置单个属性的方式 key: value// 支持对象形式的批量设置方式 {key: value}if (_.isObject(key) || key == null) {// 如果key是一个对象, 则认为是通过对象方式设置// 此时第二个参数被认为是optionsattrs = key;options = value;} else {// 如果是通过key: value形式设置单个属性, 则直接设置attrsattrs = {};attrs[key] = value;}// 配置对象必须是一个新的对象options = options ? _.clone(options) : {};// 如果在options中设置了wait选项, 则被改变的数据将会被提前验证, 且服务器没有响应新数据(或响应失败)时, 本地数据会被还原为修改前的状态// 如果没有设置wait选项, 则无论服务器是否设置成功, 本地数据均会被修改为最新状态if (options.wait) {// 对需要保存的数据提前进行验证if (!this._validate(attrs, options))return false;// 记录当前模型中的数据, 用于在将数据发送到服务器后, 将数据进行还原// 如果服务器响应失败或没有返回数据, 则可以保持修改前的状态current = _.clone(this.attributes);}// silentOptions在options对象中加入了silent(不对数据进行验证)// 当使用wait参数时使用silentOptions配置项, 因为在上面已经对数据进行过验证// 如果没有设置wait参数, 则仍然使用原始的options配置项var silentOptions = _.extend({}, options, {silent : true});// 将修改过最新的数据保存到模型中, 便于在sync方法中获取模型数据保存到服务器if (attrs && !this.set(attrs, options.wait ? silentOptions : options)) {return false;}var model = this;// 在options中可以指定保存数据成功后的自定义回调函数var success = options.success;// 服务器响应成功后执行successoptions.success = function(resp, status, xhr) {// 获取服务器响应最新状态的数据var serverAttrs = model.parse(resp, xhr);// 如果使用了wait参数, 则优先将修改后的数据状态直接设置到模型if (options.wait) {delete options.wait;serverAttrs = _.extend(attrs || {}, serverAttrs);}// 将最新的数据状态设置到模型中// 如果调用set方法时验证失败, 则不会调用自定义的success回调函数if (!model.set(serverAttrs, options))return false;if (success) {// 调用响应成功后自定义的success回调函数success(model, resp);} else {// 如果没有指定自定义回调, 则默认触发sync事件model.trigger('sync', model, resp, options);}};// 请求发生错误时通过wrapError处理error事件options.error = Backbone.wrapError(options.error, model, options);// 将模型中的数据保存到服务器// 如果当前模型是一个新建的模型(没有id), 则使用create方法(新增), 否则认为是update方法(修改)var method = this.isNew() ? 'create' : 'update';var xhr = (this.sync || Backbone.sync).call(this, method, this, options);// 如果设置了options.wait, 则将数据还原为修改前的状态// 此时保存的请求还没有得到响应, 因此如果响应失败, 模型中将保持修改前的状态, 如果服务器响应成功, 则会在success中设置模型中的数据为最新状态if (options.wait)this.set(current, silentOptions);return xhr;},// 删除模型, 模型将同时从所属的Collection集合中被删除// 如果模型是在客户端新建的, 则直接从客户端删除// 如果模型数据同时存在服务器, 则同时会删除服务器端的数据destroy : function(options) {// 配置项必须是一个新的对象options = options ? _.clone(options) : {};var model = this;// 在options中可以指定删除数据成功后的自定义回调函数var success = options.success;// 删除数据成功调用, 触发destroy事件, 如果模型存在于Collection集合中, 集合将监听destroy 事件并在触发时从集合中移除该模型// 删除模型时, 模型中的数据并没有被清空, 但模型已经从集合中移除, 因此当没有任何地方引用该模型时, 会被自动从内存中释放// 建议在删除模型时, 将模型对象的引用变量设置为nullvar triggerDestroy = function() {model.trigger('destroy', model, model.collection, options);};// 如果该模型是一个客户端新建的模型, 则直接调用triggerDestroy从集合中将模型移除if (this.isNew()) {triggerDestroy();return false;}// 当从服务器删除数据成功时options.success = function(resp) {// 如果在options对象中配置wait项, 则表示本地内存中的模型数据, 会在服务器数据被删除成功后再删除// 如果服务器响应失败, 则本地数据不会被删除if (options.wait)triggerDestroy();if (success) {// 调用自定义的成功回调函数success(model, resp);} else {// 如果没有自定义回调, 则默认触发sync事件model.trigger('sync', model, resp, options);}};// 请求发生错误时通过wrapError处理error事件options.error = Backbone.wrapError(options.error, model, options);// 通过sync方法发送删除数据的请求var xhr = (this.sync || Backbone.sync).call(this, 'delete', this, options);// 如果没有在options对象中配置wait项, 则会先删除本地数据, 再发送请求删除服务器数据// 此时无论服务器删除是否成功, 本地模型数据已被删除if (!options.wait)triggerDestroy();return xhr;},// 获取模型在服务器接口中对应的url, 在调用save, fetch, destroy等与服务器交互的方法时, 将使用该方法获取url// 生成的url类似于"PATHINFO"模式, 服务器对模型的操作只有一个url, 对于修改和删除操作会在url后追加模型id便于标识// 如果在模型中定义了urlRoot, 服务器接口应为[urlRoot/id]形式// 如果模型所属的Collection集合定义了url方法或属性, 则使用集合中的url形式: [collection.url/id]// 在访问服务器url时会在url后面追加上模型的id, 便于服务器标识一条记录, 因此模型中的id需要与服务器记录对应// 如果无法获取模型或集合的url, 将调用urlError方法抛出一个异常// 如果服务器接口并没有按照"PATHINFO"方式进行组织, 可以通过重载url方法实现与服务器的无缝交互url : function() {// 定义服务器对应的url路径var base = getValue(this, 'urlRoot') || getValue(this.collection, 'url') || urlError();// 如果当前模型是客户端新建的模型, 则不存在id属性, 服务器url直接使用baseif (this.isNew())return base;// 如果当前模型具有id属性, 可能是调用了save或destroy方法, 将在base后面追加模型的id// 下面将判断base最后一个字符是否是"/", 生成的url格式为[base/id]return base + (base.charAt(base.length - 1) == '/'? '': '/') + encodeURIComponent(this.id);},// parse方法用于解析从服务器获取的数据, 返回一个能够被set方法解析的模型数据// 一般parse方法会根据服务器返回的数据进行重载, 以便构建与服务器的无缝连接// 当服务器返回的数据结构与set方法所需的数据结构不一致(例如服务器返回XML格式数据时), 可使用parse方法进行转换parse : function(resp, xhr) {return resp;},// 创建一个新的模型, 它具有和当前模型相同的数据clone : function() {return new this.constructor(this.attributes);},// 检查当前模型是否是客户端创建的新模型// 检查方式是根据模型是否存在id标识, 客户端创建的新模型没有id标识// 因此服务器响应的模型数据中必须包含id标识, 标识的属性名默认为"id", 也可以通过修改idAttribute属性自定义标识isNew : function() {return this.id == null;},// 数据被更新时触发change事件绑定的函数// 当set方法被调用, 会自动调用change方法, 如果在set方法被调用时指定了silent配置, 则需要手动调用change方法change : function(options) {// options必须是一个对象options || ( options = {});// this._changing相关的逻辑有些问题// this._changing在方法最后被设置为false, 因此方法上面changing变量的值始终为false(第一次为undefined)// 作者的初衷应该是想用该变量标示change方法是否执行完毕, 对于浏览器端单线程的脚本来说没有意义, 因为该方法被执行时会阻塞其它脚本// changing获取上一次执行的状态, 如果上一次脚本没有执行完毕, 则值为truevar changing = this._changing;// 开始执行标识, 执行过程中值始终为true, 执行完毕后this._changing被修改为falsethis._changing = true;// 将非本次改变的数据状态添加到_pending对象中for (var attr in this._silent)this._pending[attr] = true;// changes对象包含了当前数据上一次执行change事件至今, 已被改变的所有数据// 如果之前使用silent未触发change事件, 则本次会被放到changes对象中var changes = _.extend({}, options.changes, this._silent);// 重置_silent对象this._silent = {};// 遍历changes对象, 分别针对每一个属性触发单独的change事件for (var attr in changes) {// 将Model对象, 属性值, 配置项作为参数以此传递给事件的监听函数this.trigger('change:'+ attr, this, this.get(attr), options);}// 如果方法处于执行中, 则停止执行if (changing)return this;// 触发change事件, 任意数据被改变后, 都会依次触发"change:属性"事件和"change"事件while (!_.isEmpty(this._pending)) {this._pending = {};// 触发change事件, 并将Model实例和配置项作为参数传递给监听函数this.trigger('change', this, options);// 遍历changed对象中的数据, 并依次将已改变数据的状态从changed中移除// 在此之后如果调用hasChanged检查数据状态, 将得到false(未改变)for (var attr in this.changed) {if (this._pending[attr] || this._silent[attr])continue;// 移除changed中数据的状态delete this.changed[attr];}// change事件执行完毕, _previousAttributes属性将记录当前模型最新的数据副本// 因此如果需要获取数据的上一个状态, 一般只通过在触发的change事件中通过previous或previousAttributes方法获取this._previousAttributes = _.clone(this.attributes);}// 执行完毕标识this._changing = false;return this;},// 检查某个数据是否在上一次执行change事件后被改变过/*** 一般在change事件中配合previous或previousAttributes方法使用, 如:* if(model.hasChanged('attr')) {* var attrPrev = model.previous('attr');* }*/hasChanged : function(attr) {if (!arguments.length)return !_.isEmpty(this.changed);return _.has(this.changed, attr);},// 获取当前模型中的数据与上一次数据中已经发生变化的数据集合// (一般在使用silent属性时没有调用change方法, 因此数据会被临时抱存在changed属性中, 上一次的数据可通过previousAttributes方法获取)// 如果传递了diff集合, 将使用上一次模型数据与diff集合中的数据进行比较, 返回不一致的数据集合// 如果比较结果中没有差异, 则返回falsechangedAttributes : function(diff) {// 如果没有指定diff, 将返回当前模型较上一次状态已改变的数据集合, 这些数据已经被存在changed属性中, 因此返回changed集合的一个副本if (!diff)return this.hasChanged() ? _.clone(this.changed) : false;// 指定了需要进行比较的diff集合, 将返回上一次的数据与diff集合的比较结果// old变量存储了上一个状态的模型数据var val, changed = false, old = this._previousAttributes;// 遍历diff集合, 并将每一项与上一个状态的集合进行比较for (var attr in diff) {// 将比较结果不一致的数据临时存储到changed变量if (_.isEqual(old[attr], ( val = diff[attr])))continue;(changed || (changed = {}))[attr] = val;}// 返回比较结果return changed;},// 在模型触发的change事件中, 获取某个属性被改变前上一个状态的数据, 一般用于进行数据比较或回滚// 该方法一般在change事件中调用, change事件被触发后, _previousAttributes属性存放最新的数据previous : function(attr) {// attr指定需要获取上一个状态的属性名称if (!arguments.length || !this._previousAttributes)return null;return this._previousAttributes[attr];},// 在模型触发change事件中, 获取所有属性上一个状态的数据集合。
前端面试题目大全(2)
前端面试题目(2)对前端模块化的认识AMD 是RequireJS在推广过程中对模块定义的规范化产出。
CMD 是SeaJS 在推广过程中对模块定义的规范化产出。
AMD是提前执行,CMD是延迟执行。
AMD 推荐的风格通过返回一个对象做为模块对象,CommonJS的风格通过对module.exports或exports的属性赋值来达到暴露模块对象的目的。
CMD模块方式<code class=""> define(<span class=""><span class="">function</span>(<span class="">require, exports, module</span>) </span>{ <span class="">// 模块代码</span> });</code> Javascript垃圾回收方法标记清除(mark and sweep)这是JavaScript最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”。
垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了。
引用计数(reference counting)在低版本IE中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。
引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加1,如果该变量的值变成了另外一个,则这个值得引用次数减1,当这个值的引用次数变为0的时候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为0的值占用的空间。
backbone教程
中文帮助文档/tools/backbone/backbone.js.htmlbackbone.js 初探什么是backbonebackbone不是脊椎骨,而是帮助开发重量级的javascript应用的框架。
主要提供了3个东西:1、models(模型) 2、collections(集合) 3、views(视图)backbone.js文件本身很小,压缩后只有5.3KB,作为一个框架级别的核心JS文件,这个数字很可怕。
除此之外,这个JS还必须依赖于另一个JS文件:underscore.js(包含许多工具方法,集合操作,js模板等等)。
简介用Backbone.Model表示应用中所有数据,models中的数据可以创建、校验、销毁和保存到服务端。
当models中值被改变时自动触发一个"change"事件、所有用于展示models数据的views都会侦听到这个事件,然后进行重新渲染。
Backbone.Collection和我们平时接触的JAVA集合类相似,具有增加元素,删除元素,获取长度,排序,比较等一系列工具方法,说白了就是一个保存models 的集合类。
Backbone.View中可以绑定dom el和客户端事件。
页面中的html就是通过views 的render方法渲染出来的,当新建一个view的时候通过要传进一个model作为数据,例如:Js代码1.var view = new EmployeeView({model:employee});也就是说model就是以这种方式和view进行关联的。
特点创建models或者views的语法:extends,相当于类继承models的创建,销毁,校验等一系列改变都会触发相应的事件示例需求:用backbone.js和jquery实现一个可编辑的员工信息表格。
功能:1、录入员工信息。
2、删除员工信息。
3、双击表格可对员工信息进行修改。
4、能对员工信息进行有效性校验。
Backbone js 中文API文档
promptColor: function() { var cssColor = prompt("请输入一个 CSS 颜色值:"); this.set({color: cssColor}); } });
window.sidebar = new Sidebar;
sidebar.bind('change:color', function(model, color) { $('#sidebar').css({background: color});
object.bind("alert", function(msg) { alert("Triggered " + msg);
});
object.trigger("alert", "");
bindobject.bind(event, callback, [context])
Backbone 将数据呈现为 模型, 你可以创建模型、对模型进行验证和销毁,甚至将它保存到服务 器。当 UI 的变化引起模型属性改变时,模型会触发"change"事件;所有显示模型数据的 视图 会 接收到该事件的通知,继而视图重新渲染。 你无需查找 DOM 来搜索指定 id 的元素去手动更新 HTML。 — 当模型改变了,视图便会自动变化。
从 object 对象移除先前绑定的 callback 函数。如果不指定第二个参数,所有 event 事件绑定 的回调函数都被移除。 如果第一个参数也不指定,对象所绑定的所有回调函数都将被移除。
BackBone_js之Router=
BackBone.js之Routerjavascript首先我们先看下面几个路径:http://localhost:2746/Home/Home#helphttp://localhost:2746/Home/Home#single/test1http://localhost:2746/Home/Home#multip/test1/test2某些人可能会认为是用来定位锚点的,但是在BackBone.js的路由中这些都是一个事件,并且还带有参数。
下面我们先定义一个路由:1 var CustRoute = Backbone.Router.extend({2 });如果是没有javascript基础的人看到这串代码可能仅仅只是认为是执行一个函数而已,但是实际的功能却不是你想的那样简单。
实际的功能是新建一个类,并且这个类继承自Backbone.Router。
(javascript并不存在实际意义上的类,仅仅只是通过某些技巧达到类的效果)。
然后我们继续往下,开始在这个类重写父类的方法:1 var CustRoute = Backbone.Router.extend({2 initialize: function () {3 console.log("Route initialize");4 }5 });在上面我们重写了父类中的initialize方法,这个方法会在实例化这个对象的时候被调用。
下面我们写一段代码去实例化它:1 $(function () {2 new CustRoute();3 Backbone.history.start();4 });这里我们还调用了Backbone.history.start 方法,这个方法可以让我们在点击后退或者前进的时候同样会触发路由的事件。
这个时候你可以按F12看看console中是不是输出上面的字符串。
下面我们开始在其中添加路由的路径,添加的路由路径要求重写父类的routes这个对象,那么我们将上面的第一个路由路径实现:var CustRoute = Backbone.Router.extend({initialize: function () {console.log("Route initialize");},routes: {"help":"helpex"},helpex: function () {console.log("helpex");}});这个时候我们访问这个页面,然后在后面加上#help 之后重新打开,然后查看console就可以看到输出的字符串了。
backbone案例
使用Backbone.js构建案例应用程序Backbone.js是一个轻量级的JavaScript框架,用于构建客户端Web应用程序。
它提供了一种结构化的方法来管理和组织前端代码,并提供了数据绑定和事件处理等功能。
以下是一个使用Backbone.js构建的案例应用程序的详细介绍。
案例应用程序:在线书店该应用程序是一个简单的在线书店,允许用户浏览书籍、添加到购物车、查看购物车和下订单。
1.模型(Models)模型是应用程序中数据结构的定义。
在在线书店应用程序中,我们有两个模型:Book和CartItem。
Book模型包含书的基本信息,如书名、作者、页数和描述。
它还包含一个名为"category"的关联,该关联将书与类别相关联。
CartItem模型表示购物车中的项。
它包含书的基本信息和一个数量属性,用于跟踪购物车中该书的数量。
它还包含一个名为"cart"的关联,该关联将购物车项与购物车相关联。
1.集合(Collections)集合是模型对象的集合。
在在线书店应用程序中,我们有两个集合:Books和CartItems。
Books集合包含应用程序中所有书籍的模型对象。
它使用Backbone的fetch方法从服务器获取数据,并在接收到数据时触发add事件,以便将新书籍添加到视图中。
CartItems集合包含购物车中所有项的模型对象。
当用户将书籍添加到购物车时,将创建一个新的CartItem模型对象并将其添加到集合中。
1.视图(Views)视图是应用程序中用户界面的组件。
在在线书店应用程序中,我们有四个视图:BookListView、CartView、CheckoutView和OrderView。
BookListView是一个表格,显示所有可用书籍的列表。
它使用Backbone的listenTo方法监听Books集合的add事件,以便在添加新书籍时更新视图。
当用户单击书籍时,将触发一个事件,并将所选书籍添加到购物车中。
backbonejs技术应用实例
backbonejs技术应用实例English Answer:Backbone.js is a lightweight JavaScript framework that provides an MVC architecture for creating single-page applications. It is designed to make it easy to manage data, define models, and create views that respond to changes in data. Backbone.js is also highly extensible, making it a great choice for complex applications.One of the most popular uses of Backbone.js is for creating to-do list applications. A to-do list application typically involves managing a list of tasks, each of which has a title, description, and status. Using Backbone.js,you can create a model to represent each task, and a collection to represent the list of tasks. You can then create views to display the tasks in a user interface, andto allow the user to add, edit, and delete tasks.Another popular use of Backbone.js is for creating chatapplications. A chat application typically involves managing a list of messages, each of which has a sender, a recipient, and a message body. Using Backbone.js, you can create a model to represent each message, and a collection to represent the list of messages. You can then create views to display the messages in a user interface, and to allow the user to send and receive messages.Backbone.js can also be used to create more complex applications, such as e-commerce applications, social networking applications, and even games. It is a versatile framework that can be used to create a wide variety of applications.Here are some specific examples of Backbone.js applications:Trello: Trello is a popular project management application that uses Backbone.js to manage its data.Asana: Asana is another popular project management application that uses Backbone.js to manage its data.HipChat: HipChat is a popular chat application that uses Backbone.js to manage its data.Slack: Slack is another popular chat application that uses Backbone.js to manage its data.GitHub: GitHub is a popular code hosting platform that uses Backbone.js to manage its data.These are just a few examples of the many applications that use Backbone.js. It is a powerful framework that can be used to create a wide variety of applications.中文回答:什么是 Backbone.js?Backbone.js 是一款轻量级 JavaScript 框架,它提供了一种MVC 架构,用于创建单页面应用程序。
backbone用法
backbone用法Backbone是一个轻量级的JavaScript框架,用于构建单页应用程序和管理前端数据。
它提供了一组简单而强大的工具,帮助开发人员组织和维护大规模的前端代码。
下面将介绍Backbone的一些常用用法。
1. 模型(Model):Backbone的核心是模型,它用于管理应用程序中的数据。
通过定义模型类,可以创建数据对象,并为其添加属性和方法。
模型还可以绑定事件,以便在数据变化时触发相应的回调函数。
2. 视图(View):视图负责将模型中的数据展示给用户,并响应用户的操作。
可以通过视图来创建HTML元素并将其渲染到DOM中。
视图也可以监听模型的变化,并在数据更新时自动更新对应的视图。
3. 集合(Collection):集合是一组模型的容器,用于管理多个模型对象。
它提供了丰富的方法,用于增加、删除、遍历和过滤模型。
集合还能和后端服务器进行数据交互,通过RESTful接口获取和保存数据。
4. 路由(Router):路由用于管理应用程序的URL,并根据URL的变化加载不同的视图。
通过定义路由规则,可以将不同的URL映射到对应的视图和操作。
当URL发生变化时,路由会自动触发相应的回调函数。
5. 事件(Events):Backbone提供了强大的事件系统,用于模块之间的通信和解耦。
可以在模型、视图和集合上绑定自定义事件,并触发相应的回调函数。
事件可以传递参数,以便在不同模块之间共享数据。
总结:Backbone是一个简洁、灵活的框架,可以帮助开发人员更好地组织和管理前端代码。
它的模型、视图、集合和路由等组件提供了丰富的功能,使得构建复杂的单页应用程序变得更加容易。
通过合理运用Backbone的各种用法,可以提高开发效率并改善代码质量。
backbone的作用
backbone的作用Backbone是一个适用于Web应用程序的JavaScript库。
它为开发者提供了一组通用的工具和方法,可以用来管理复杂的应用程序中的数据,事件,模块等。
Backbone的核心目的是为了帮助开发者更高效和有效地构建Web应用程序。
以下是Backbone的主要作用:1. 数据管理:Backbone提供了一些有用的API来管理和组织应用程序中的数据。
开发者可以使用模型(model)和集合(collection)来格式化和同步应用程序中不同的数据源,如服务器、后端数据库等。
模型和集合的使用使得开发人员可以更方便的处理数据,并能够更轻松地将数据传输到视图中。
2. 视图控制:通过视图(view)的使用,开发人员可以轻松地根据应用程序中不同的事件来管理页面的呈现和界面元素的状态。
Backbone中的视图也可以处理与应用程序功能相关的UI事件,比如点击、输入、鼠标移动事件等。
3. 路由控制:Backbone提供了一种可以对应用程序路由进行控制的方法,可帮助开发人员和用户更轻松地在应用程序内部和不同页面之间导航。
这种路由控制方法可以帮助开发者构建更像单页应用程序形式的应用,而且可以避免页面刷新和跳转造成的流畅性下降。
4. 事件管理:Backbone利用事件机制(event)来使开发者能够更容易地应对复杂的应用程序中的事件处理。
在Backbone中,事件可以被发射和捕获,使开发者有更大的控制权来处理应用程序的各种事件。
5. 模块化开发:Backbone提供了模块化开发的支持,这意味着开发人员可以将应用程序分成多个不同的模块,然后以这种方式进行组织和管理。
在模块化开发中,每个模块都可以由单独的JavaScript文件和CSS样式表所定义,这样可以更轻松地维护和管理代码。
前端框架Backbone基础知识
前端框架Backbone基础知识Backbone是现代Web应用开发领域中广泛使用的一种轻量级的前端框架。
由于其易于学习和支持高效开发复杂应用的方式,它在前端应用框架的竞争中处于重要地位。
本文旨在介绍Backbone的基础知识,包括其设计原则、核心组件以及优缺点。
设计原则Backbone框架的核心设计思想是“轻量级”,它的目标是避免被过多的复杂功能所淹没。
同时,它也遵循了MVC(模型-视图-控制器)的模式,将应用程序的业务逻辑,数据以及用户界面分离。
这种设计思想使得应用程序具有更大的灵活性和可维护性。
Backbone主要关注以下三个核心部分:模型、视图和路由器。
模型用于表示应用程序中的数据,视图用于呈现数据并与用户交互,而路由器则用于控制浏览器地址栏的变化并将其映射到应用程序的不同状态。
核心组件Backbone的核心组件包括以下几个部分:1.模型(Model)Backbone的模型是其最基本的组件之一,它类似于传统MVC模式中的模型。
模型是数据的抽象表示,它通常映射到应用程序的服务器端数据。
在模型中,可以定义模型属性(例如名称、描述、价格等)以及与属性相关的操作(例如获取属性值、设置属性值等)。
通过监听来自其他组件的事件,模型可以自动更新其属性以反映应用程序中的状态变化。
模型还可以将其属性保存到服务器上,或从服务器上加载数据。
在这种情况下,模型充当了与服务器通信的代理。
2.视图(View)Backbone的视图是另一个核心组件,用于呈现模型数据并与用户进行交互。
视图提供了一种将HTML和CSS样式与Javascript逻辑绑定在一起的方式,用于呈现数据并处理用户的操作。
在视图中,可以定义事件监听器,当用户执行特定操作(例如点击按钮、输入文本等)时,将调用监听器并执行相关的Javscript代码。
视图还允许将模型数据直接绑定到HTML元素,以便在数据更新时自动更新视图。
3.集合(Collection)集合是一组模型的集合,它们彼此相关并在应用程序中以某种方式进行组合。
JavaScript的Backbone.js框架入门学习指引_
JavaScript的Backbone.js框架入门学习指引_这篇文章主要介绍了JavaScript的Backbone.js框架入门学习指引, 其中格外讲到了Backbone中的关键部分Router路由器,需要的伴侣可以参考下1.简介最近在做一个大型网上银行项目前端的优化,需要用法一个胖客户端的优化,也许思路就是前端通过Ajax 恳求去后端猎取数据,以Jason的格式返回,然后显示在页面上。
由于这个系统特别浩大,胖客户端方案难免需要在客户端写大量的JS代码。
我想对于任何团队来说,大量的,非结构化的代码维护起来都特别的不便利。
所以BackBone进入了我的视线。
它供应了一种途径可以让你结构化你的JS代码,让你以面对对象的方式来组织你的前端JS代码。
这就好比我们在前端应用Domain Driven Design. 我们可以把一个特别大的项目按模块切分。
每个模块里面又可以根据BackBone的要求切分成View, Model, Router。
通过backbone,你可以把你的数据当作Models,通过Models你可以创建数据,进行数据验证,销毁或者保存到服务器上。
当界面上的操作引起model中属性的改变时,model 会触发change的大事;那些用来显示model状态的views会接受到model触发change的消息,进而发出对应的响应,并且重新渲染新的数据到界面。
在一个完整的backbone应用中,你不需要写那些胶水代码来从DOM中通过特别的id 来猎取节点,或者手工的更新HTML页面,由于在model发生改变时,views会很简洁的进行自我更新。
2.特点Backbone是一个轻量级的前端框架,用于结构化管理页面中的大量JS,建立与服务器、视图间的无缝连接,为构建简单的应用供应基础框架。
下面我先简洁地阐述下Backbone的主要特点及特性:2.1 轻量级Backbone的源码只有1000行左右(去说明和空行后),文件大小只有16KB,加上依靠库Underscore,也仅有29KB。
[转]Backbone.js简单入门范例
[转]Backbone.js 简单⼊门范例11年刚开始⽤前端MVC 框架时写过,当时Knockout 和Backbone 都在⽤,但之后的项⽬全是在⽤Backbone ,主要因为它简单、灵活,⽆论是富JS 应⽤还是企业⽹站都⽤得上。
写这篇⽂章的动机,是最近跟做在线教育的朋友聊,谈到⽐较好的中⽂⼊门教程不多,于是想针对⾃⼰⽤得最多的框架写⼀篇,说明如下:1. 结构上分4节,介绍Model/View/Collection ,实现从远程获取数据显⽰到表格且修改删除;2. 名为“范例”,所以代码为主,每节的第1段代码都是完整代码,复制粘贴就能⽤,每段代码都是基于前⼀段代码来写的,因此每段代码的新内容不会超过20⾏(⼤括号计算在内);3. 每⾏代码没有注释,但重要内容之后有写具体的说明;4. 开发环境是Chrome ,使⽤,这样⽤Chrome 即使在本地路径(形如file://的路径)也能获取数据。
0. Introduction⼏乎所有的框架都是在做两件事:⼀是帮你把代码写在正确的地⽅;⼆是帮你做⼀些脏活累活。
Backbone 实现⼀种清晰的MVC 代码结构,解决了数据模型和视图映射的问题。
虽然所有JS 相关的项⽬都可以⽤,但Backbone 最适合的还是这样⼀种场景:需要⽤JS ⽣成⼤量的页⾯内容(HTML 为主),⽤户跟页⾯元素有很多的交互⾏为。
Backbone 对象有5个重要的函数,Model/Collection/View/Router/History 。
Router 和History 是针对Web 应⽤程序的优化,建议先熟悉的相关知识。
⼊门阶段可以只了解Model/Collection/View 。
将Model 视为核⼼,Collection 是Model 的集合,View 是为了实现Model 的改动在前端的反映。
1. ModelModel 是所有JS 应⽤的核⼼,很多Backbone 教程喜欢从View 开始讲,其实View 的内容不多,⽽且理解了View 意义不⼤,理解Model 更重要。
Backbone.js中的集合详解
Backbone.js中的集合详解Backbone.js的集合只是⼀个简单的有序集的模型。
通过适应模型和集合,我们可以避免数据处理逻辑放到了我们的视图层。
此外,模型和集合还提供了便利的与后端⼀起⼯作的⽅法,当数据发⽣变化时,可以⾃动化地标记Backbone.js视图。
这样,它可以⽤于如下的情况:复制代码代码如下:Model: Animal, Collection: Zoo通常情况下你的集合只适应⼀种模型,但模型本⾝并不局限于集合的类型。
复制代码代码如下:Model: person, Collection: OfficeModel: person, Collection: Home下⾯是常见的模型/集合的例⼦:复制代码代码如下:var Music = Backbone.Model.extend({initialize: function(){console.log("Welcome to the music world");}});var Album = Backbone.Collection.extend({model: Music});上⾯的代码告诉我们如何创建集合。
但是它没有告诉我们⽤数据操纵集合的过程。
因此,让我们探索这个过程:复制代码代码如下:var Music = Backbone.Model.extend({defaults: {name: "Not specified",artist: "Not specified"},initialize: function(){console.log("Welcome to the music world "); }});var Album = Backbone.Collection.extend({model: Music});var music1 = new Music ({ id: 1 ,name: "How Bizarre", artist: "OMC" });var music 2 = new Music ({id: 2, name: "What Hurts the Most", artist: “Rascal Flatts" });var myAlbum = new Album([music 1, music 2]);console.log( myAlbum.models );下⾯我们来看看Backbone.js的集合和其它组件的关系:⼀、添加模型到集合正如我们所知的那样,集合是模型的集合。
backbone在模型中的作用 -回复
backbone在模型中的作用-回复Backbone.js是一个轻量级的JavaScript库,它提供了一种结构化的方法来构建Web应用程序。
它主要用于在前端应用程序中管理和组织数据模型,视图和事件。
在Backbone中,模型是数据的核心,它负责封装和处理与数据相关的逻辑。
模型代表应用程序中的实体,例如用户,文章,商品等。
它包含数据属性和与数据相关的方法。
Backbone的模型提供了一种机制来管理和维护模型的状态,以及在模型发生变化时通知视图。
一种常见的用法是将模型与服务器上的RESTful API进行交互。
Backbone 提供了一组内置的方法,例如`fetch`, `save`, `destroy`等来处理与服务器的数据交互。
这使得开发人员能够很容易地实现与后端的数据同步。
除了与服务器的交互,Backbone模型还提供了一些便利的功能来处理模型的验证和处理复杂的数据逻辑。
通过定义自定义验证规则,开发人员可以确保仅有效的数据被保存到模型中。
模型还可以定义计算属性,这些属性根据其他模型属性的值进行计算,并在值发生变化时自动更新。
另一个重要的功能是模型之间的关联和嵌套。
通过在模型中定义关系,例如一对多,多对多等,开发人员可以轻松地将模型连接在一起,以构建更复杂的数据结构。
这样的关联还允许在父模型发生更改时自动更新相关子模型,从而保持数据的一致性。
除了模型,Backbone还提供了视图的概念。
视图是用户界面的表现,它负责显示和交互用户操作。
视图在模型的基础上构建,并通过观察模型的改变来实时更新。
通过定义事件处理程序,视图可以捕获和响应用户交互,例如点击,拖动等。
视图还可以与其他视图进行嵌套和组合,以构建复杂的用户界面。
这种嵌套和组合的能力使开发人员能够设计可重用和可扩展的组件,从而提高代码的可维护性和可测试性。
除了模型和视图,Backbone还提供了一种事件处理机制。
通过使用事件,模型和视图之间可以进行通信和协调。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
主要组成:
1.model:创建数据,进行数据验证,销毁或者保存到服务器上 2.collection:可以增加元素,删除元素,获取长度,排序,比较等一系列工具方法,说白了就是一个保存 models的集合 类
3.view:绑定html模板,绑定界面元素的事件,初始的渲染,模型值改变后的重新渲染和界面元素的销毁等
殊的id来获取节点,或者手工的更新HTML页面,因为在model发生变化时,views会很 简单的进行自我更新。
Model(模型) “数据模型”(Model)用于封装与应用程序的业务逻辑相 关的数据以及对数据的处理方法。“模型”有对数据直接访问的权利, 例如对数据库的访问。
View(视图) 视图层能够实现数据有目的的显示(理论上,这不是必需 的)。在视图中一般没有程序上的逻辑。为了实现视图上的刷新功能, 视图需要访问它监视的数据模型(Model),因此应该事先在被它监视 的数据那里注册。
backbone.js提供了一套web开发的框架,通过Models进行key-value绑定及custom事件处理,通过Collections提供一套丰富的 API用于枚举功能,通过Views来进行事件处理及与现有的Application通过RESTful JSON接口进行交互.它是基于jquery和 underscore的一个js框架。(应该是唯一强制依赖underscore,非强制依赖jquery或者zepto、 ender )
--前端学习专题
初识backbonejs MVC简介 Backbonejs模块分析 实例 Q&A
Backbone是 DocumentCloud 的一个开源组件 . 项目托管在Github。可以通过官网http://documentcloud.github.io/backbone/ 获得代码。
Controller(控制器) 控制器起到不同层面间的组织作用,用于控制应用 程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据 模型上的改变。
Model负责保存view需要的数据以及数据处理逻辑(读写,更 新,删除,验证,转换等),以及和后端服务器和View的数 据交互 View负责接收显示Model提供的数据以及接收用户输入,响 应事件,Model更新后及时将更新反馈给用户
通过Models你可以创建数据,进行数据验证,销毁或者保存到服务器上。当界面上的操
作引起model中属性的变化时,model会触发change的事件;那些用来显示model状态的 views会接受到model触发change的消息,进而发出对应的响应,并且重新渲染新的数据
到界面。在一个完整的backbone应用中,你不需要写那些胶水代码来从DOM中通过特
不利之处:
对Javascript 开发技术要求高 纯AJAX的网站,不利于SEO
应用场景:
最适合的应用场景是单页面应用,并且页面上有大量数据模型,模型之间
需要进行、事件逻辑(包括用户触发的事件和 model数据发生改变的事件)和管理history hash
优势:
将数据和界面很好的分离开来。 将事件的绑定很好的剥离出来,便于管理和迭代 使得Javascript程序的模块化更加清晰明了 共用一套API,整个项目架构整洁优雅,容易维护 AJAX可.js是一个web端javascript的mvc框架,算得上是重量级的框架。 它能让你像写java代码一些写js代码,定义类,类的属性以及方法。更重要的是它能够 优雅的把原本无逻辑的javascript代码进行组织,并且提供数据和逻辑相互分离的方法, 减少代码开发过程中的数据和逻辑混乱。通过backbone,你可以把你的数据当作Models,