backbone.Collection源码笔记
Backbone.Collection
backbone的Collection(集合),用来存储多个model,并且可以多这些model进行数组一样的操作,比如添加,修改,删除,排序,插入,根据索引取值,等等,数组有的方法,他基本上都有
源码注释
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
<title>backbone</title>
<style type="text/css">
*{padding:0;margin:0;}
.wrap{width:960px; margin: 100px auto; padding: 20px 0;}
ul{ list-style: none;}
</style>
</head>
<body>
<div class="wrap">
<div id="a1"></div>
<div id="a2"></div>
<div id="a3"></div>
</div>
<script src="http://files.cnblogs.com/wtcsy/jquery.js"></script>
<script src="http://files.cnblogs.com/wtcsy/underscore.js"></script>
<script src="http://files.cnblogs.com/wtcsy/events.js"></script>
<script src="http://files.cnblogs.com/wtcsy/model.js"></script>
<script>
(function(){
// Backbone.Collection
// -------------------
var array = [];
var slice = array.slice;
// If models tend to represent a single row of data, a Backbone Collection is
// more analogous to a table full of data ... or a small slice or page of that
// table, or a collection of rows that belong together for a particular reason
// -- all of the messages in this particular folder, all of the documents
// belonging to this particular author, and so on. Collections maintain
// indexes of their models, both in order, and for lookup by `id`. // Create a new **Collection**, perhaps to contain a specific type of `model`.
// If a `comparator` is specified, the Collection will maintain
// its models in sort order, as they're added and removed.
var Collection = Backbone.Collection = function(models, options) {
options || (options = {});
//默认的model
if (options.model) this.model = options.model;
if (options.comparator !== void 0) this.comparator = options.comparator;
//重置collection里面的的一些属性
this._reset();
this.initialize.apply(this, arguments);
//如果传入的models有数据,可以进行设置
if (models)
this.reset(models, _.extend({silent: true}, options));
}; // Default options for `Collection#set`.
// 设置的参数 添加的参数 add
var setOptions = {add: true, remove: true, merge: true};
var addOptions = {add: true, remove: false}; _.extend(Collection.prototype, Backbone.Events, {
// The default model for a collection is just a **Backbone.Model**.
// This should be overridden in most cases.
model: Backbone.Model, // Initialize is an empty function by default. Override it with your own
// initialization logic.
initialize: function(){}, // The JSON representation of a Collection is an array of the
// models' attributes.
toJSON: function(options) {
return this.map(function(model){ return model.toJSON(options); });
}, // Proxy `Backbone.sync` by default.
/*
sync: function() {
return Backbone.sync.apply(this, arguments);
},
*/ // **parse** converts a response into a list of models to be added to the
// collection. The default implementation is just to pass it through.
parse: function(resp, options) {
return resp;
}, // Add a model, or list of models to the set.
add: function(models, options) {
//其实就是调用set方法 只有add设置成true remove设置成false merge设置成false
return this.set(models, _.extend({merge: false}, options, addOptions));
}, // Update a collection by `set`-ing a new list of models, adding new ones,
// removing models that are no longer present, and merging models that
// already exist in the collection, as necessary. Similar to **Model#set**,
// the core operation for updating the data contained by the collection.
set: function(models, options) {
options = _.defaults({}, options, setOptions);
//parse 必须是一个函数 传入的后将models进行一次转换
if (options.parse) models = this.parse(models, options);
var singular = !_.isArray(models);
models = singular ? (models ? [models] : []) : models.slice();
var id, model, attrs, existing, sort;
var at = options.at;
// this.comparator 是排序的东西 如果是函数 sotrAttr为null 否则sotrAttr为true
var sortable = this.comparator && (at == null) && options.sort !== false;
var sortAttr = _.isString(this.comparator) ? this.comparator : null;
var toAdd = [], toRemove = [], modelMap = {};
var add = options.add, merge = options.merge, remove = options.remove;
var order = !sortable && add && remove ? [] : false;
var targetProto = this.model.prototype; // Turn bare objects into model references, and prevent invalid models
// from being added.
//对models进行一次遍历 找出要add的 要remove的
for (var i = 0, length = models.length; i < length; i++) {
attrs = models[i] || {};
//通过查找model的属性找出id 可以是方便后面用 id可以是model本身 也可以是model的cid 或者是model的id
if (this._isModel(attrs)) {
id = model = attrs;
} else if (targetProto.generateId) {
id = targetProto.generateId(attrs);
} else {
id = attrs[targetProto.idAttribute || Model.prototype.idAttribute];
} // If a duplicate is found, prevent it from being added and
// optionally merge it into the existing model.
// return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid];
// 看model是否在this.models里面存在 如果存在,并且设置了remove吧model放到modelMap中
// 如果设置了merge model重新设置他的属性 如果设置了排序 排序标识sotr设置成true,数据改变了 肯定要排序一次的
if (existing = this.get(id)) {
if (remove) modelMap[existing.cid] = true;
if (merge) {
attrs = attrs === model ? model.attributes : attrs;
if (options.parse) attrs = existing.parse(attrs, options);
existing.set(attrs, options);
if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
}
models[i] = existing; // If this is a new, valid model, push it to the `toAdd` list.
} else if (add) {
// 如果遍历的model不存在 变并且设置了add
//对这个model做一些操作_prepareModel 如果传入的attrs是backbone实例化的model则只设置model.collection指向this
//如果attrs只是数据 则实例化model并且model.collection指向this
// 然后把model放到 toAdd中 方便后面使用
//最后 以model的cid为key 存入this._byId中
model = models[i] = this._prepareModel(attrs, options);
if (!model) continue;
toAdd.push(model);
this._addReference(model, options);
} // Do not add multiple models with the same `id`.
model = existing || model;
if (!model) continue;
//order 如果是add或者是remove并且没有设置排序 并且model是新实例化的 添加到order里面去 后面会用到
if (order && (model.isNew() || !modelMap[model.id])) order.push(model);
modelMap[model.id] = true;
} // Remove nonexistent models if appropriate.
if (remove) {
// 做删除 先做一些准备 然后添加到toRemove里面去
for (var i = 0, length = this.length; i < length; i++) {
if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
}
if (toRemove.length) this.remove(toRemove, options);
} // See if sorting is needed, update `length` and splice in new models.
if (toAdd.length || (order && order.length)) {
//符合添加条件就记性添加
if (sortable) sort = true;
this.length += toAdd.length;
if (at != null) {
for (var i = 0, length = toAdd.length; i < length; i++) {
this.models.splice(at + i, 0, toAdd[i]);
}
} else {
if (order) this.models.length = 0;
var orderedModels = order || toAdd;
for (var i = 0, length = orderedModels.length; i < length; i++) {
this.models.push(orderedModels[i]);
}
}
} // Silently sort the collection if appropriate.
//符合排序条件 进行排序
if (sort) this.sort({silent: true}); // Unless silenced, it's time to fire all appropriate add/sort events.
if (!options.silent) {
//如果没有设置silent 触发每个model的add的回调
for (var i = 0, length = toAdd.length; i < length; i++) {
(model = toAdd[i]).trigger('add', model, this, options);
}
if (sort || (order && order.length)) this.trigger('sort', this, options);
} // Return the added (or merged) model (or models).
return singular ? models[0] : models;
}, // Remove a model, or a list of models from the set.
remove: function(models, options) {
// 删除model 删除this._byId对model的引用
//触发model本身的remove绑定的回调
var singular = !_.isArray(models);
models = singular ? [models] : _.clone(models);
options || (options = {});
for (var i = 0, length = models.length; i < length; i++) {
var model = models[i] = this.get(models[i]);
if (!model) continue;
delete this._byId[model.id];
delete this._byId[model.cid];
var index = this.indexOf(model);
this.models.splice(index, 1);
this.length--;
if (!options.silent) {
options.index = index;
model.trigger('remove', model, this, options);
}
this._removeReference(model, options);
}
return singular ? models[0] : models;
}, // Force the collection to re-sort itself. You don't need to call this under
// normal circumstances, as the set will maintain sort order as each item
// is added.
sort: function(options) {
if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
options || (options = {}); // Run sort based on type of `comparator`.
if (_.isString(this.comparator) || this.comparator.length === 1) {
this.models = this.sortBy(this.comparator, this);
} else {
this.models.sort(_.bind(this.comparator, this));
} if (options.reverse) this.models = this.models.reverse(); if (!options.silent) this.trigger('sort', this, options);
return this;
},
// Get a model from the set by id.
get: function(obj) {
if (obj == null) return void 0;
return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid];
}, // Private method to reset all internal state. Called when the collection
// is first initialized or reset.
_reset: function() {
this.length = 0;
this.models = [];
this._byId = {};
}, // When you have more items than you want to add or remove individually,
// you can reset the entire set with a new list of models, without firing
// any granular `add` or `remove` events. Fires `reset` when finished.
// Useful for bulk operations and optimizations.
reset: function(models, options) {
options || (options = {});
for (var i = 0, length = this.models.length; i < length; i++) {
this._removeReference(this.models[i], options);
}
options.previousModels = this.models;
this._reset();
models = this.add(models, _.extend({silent: true}, options));
if (!options.silent) this.trigger('reset', this, options);
return models;
}, // Prepare a hash of attributes (or other model) to be added to this
// collection.
_prepareModel: function(attrs, options) {
if (this._isModel(attrs)) {
if (!attrs.collection) attrs.collection = this;
return attrs;
}
options = options ? _.clone(options) : {};
options.collection = this;
var model = new this.model(attrs, options);
if (!model.validationError) return model;
this.trigger('invalid', this, model.validationError, options);
return false;
},
// Method for checking whether an object should be considered a model for
// the purposes of adding to the collection.
_isModel: function (model) {
return model instanceof Backbone.Model;
}, // Internal method to create a model's ties to a collection.
_addReference: function(model, options) {
this._byId[model.cid] = model;
if (model.id != null) this._byId[model.id] = model;
model.on('all', this._onModelEvent, this);
}, // Internal method called every time a model in the set fires an event.
// Sets need to update their indexes when models change ids. All other
// events simply proxy through. "add" and "remove" events that originate
// in other collections are ignored.
_onModelEvent: function(event, model, collection, options) {
if ((event === 'add' || event === 'remove') && collection !== this) return;
if (event === 'destroy') this.remove(model, options);
if (event === 'change-id') {
if (collection != null) delete this._byId[collection];
if (model.id != null) this._byId[model.id] = model;
}
this.trigger.apply(this, arguments);
},
// Internal method to sever a model's ties to a collection.
_removeReference: function(model, options) {
if (this === model.collection) delete model.collection;
model.off('all', this._onModelEvent, this);
},
}); // Underscore methods that we want to implement on the Collection.
// 90% of the core usefulness of Backbone Collections is actually implemented
// right here:
var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
'lastIndexOf', 'isEmpty', 'chain', 'sample', 'partition']; // Mix in each Underscore method as a proxy to `Collection#models`.
_.each(methods, function(method) {
if (!_[method]) return;
Collection.prototype[method] = function() {
var args = slice.call(arguments);
args.unshift(this.models);
return _[method].apply(_, args);
};
}); // Underscore methods that take a property name as an argument.
var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy']; // Use attributes instead of properties.
_.each(attributeMethods, function(method) {
if (!_[method]) return;
Collection.prototype[method] = function(value, context) {
var iterator = _.isFunction(value) ? value : function(model) {
return model.get(value);
};
return _[method](this.models, iterator, context);
};
}); // Helper function to correctly set up the prototype chain, for subclasses.
// Similar to `goog.inherits`, but uses a hash of prototype properties and
// class properties to be extended.
//第一个参数是要扩展到原型上的对象, 第2个参数是静态方法扩展到构造函数上去的
var extend = function(protoProps, staticProps) {
var parent = this;
var child; // The constructor function for the new subclass is either defined by you
// (the "constructor" property in your `extend` definition), or defaulted
// by us to simply call the parent's constructor.
if (protoProps && _.has(protoProps, 'constructor')) {
child = protoProps.constructor;
} else {
child = function(){ return parent.apply(this, arguments); };
} // Add static properties to the constructor function, if supplied.
//将静态方法和 parent上的静态方法一起扩展到child上面去
_.extend(child, parent, staticProps); // Set the prototype chain to inherit from `parent`, without calling
// `parent`'s constructor function.
//创建一个新的构造含糊Surrogate ;
//this.constructor = child的意思是 Surrogate实例化后的对象 让对象的构造函数指向child
// Surrogate的原型就是parent的原型
// 然后实例化给child的原型,
// 这里不是直接从new parent给child.prototype 而是创建一个新的构造函数,我也不知道为啥要这样
var Surrogate = function(){ this.constructor = child; };
Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate; // Add prototype properties (instance properties) to the subclass,
// if supplied.
// 把第一个参数上的属性扩展到child.prototype
if (protoProps) _.extend(child.prototype, protoProps); // Set a convenience property in case the parent's prototype is needed
// later.
// 拿一个属性引用父的原型, 以免以后要用到.
child.__super__ = parent.prototype; return child;
}; Backbone.Collection.extend = extend;
})(); </script>
</body>
</html>
Collection的一些基本属性
length collection里面包含moldel的个数
models 该属性引用一个数组,数组里面就是model了
_byId 该属性引用一个对象,value就是model,key是该model的cid(或者是id,如果给model设置了id,就取id当key,否则用cid当key),
model 默认是Backbone.Model,可以被覆盖,如果传入的参数是这样的{name:"xx",age:"oo"}的对象,被实例化的对象就是用model这个基类来实例化的
Collection被实例化的过程以及 _reset,reset的方法
实例化的过程就是设置默认model,默认的model的作用是如果实例化后的colletion添加model的时候,如果传入的参数是object,则会用默认model实例化
设置comparator,
重置属性,
调用初始化方法initialize,
如果传入了值,重置值
_reset
this.length = 0;
this.models = [];
this._byId = {};
就是将一些属性设置成初始化的值
reset collection.reset([models], [options])
reset: function(models, options) {
options || (options = {});
for (var i = 0, length = this.models.length; i < length; i++) {
this._removeReference(this.models[i], options);
}
options.previousModels = this.models;
this._reset();
models = this.add(models, _.extend({silent: true}, options));
if (!options.silent) this.trigger('reset', this, options);
return models;
},
_removeReference: function(model, options) {
if (this === model.collection) delete model.collection;
model.off('all', this._onModelEvent, this);
},
它会遍历this.models里面的东西,然后执行this._removeReference,this._removeReference会把model对象的属性collection给删除掉(model在加入this.models里面的时候会加上collection这个属性,所以删除的时候要这个属性也干掉),然后触发model的all监听的回调(如果model绑定了all)
用previousModels保存之前的this.models
如果传入的参数中有对象,要添加到this.models里面去,所以在调用this.add方法
silent表示是否触发事件,没有设置就触发reset监听的回调
一些例子
var c = new Backbone.Collection
c.add({a:1})
var m = c.models[0];
alert(m.constructor === Backbone.Model) //true
//可以看到默认的model是Backbone.Model var newModel = Backbone.Model.extend({});
var newC = new Backbone.Collection(null,{model:newModel});
newC.add({a:1})
var m = newC.models[0];
alert(m.constructor === newModel) //true
alert(m.constructor === Backbone.Model)//false
//可以看到默认的Backbone.Model变成了新的newModel了
var c = new Backbone.Collection({a:1})
console.log(c.models)
//如果初始化的时候传一些数据进去,会自动变成model存在models里面的 var cc = new Backbone.Collection([{a:1},{b:1},{c:1}])
console.log(cc.models.length)
//传入的数据也可以是一个数组
Collection的set ,add,remove,sort方法(set算是里面最重要的东西了)
set
首先会对传入的models进行一次转换,变成数组,方便进行下面的遍历
然后遍历传入的models,第一步对每个单独的model查看它是否由Backbone.Model实例化而来,如果是直接把id=model,然后通过该Collection上的modle的原型上的方法查看,看能否找到id
当查找完id后,判断该id是否已经存在了,如果存在,则看参数中是否传入options.remove,如果存在放入modelMap中,在看参数中是否有options.merge,如果有则直接molde.set来改变model的值
如果id不存在,而且传入的参数中有options.add,先对遍历的model做一些操作操作如下,如果attrs是真实的model,则把attrs.collection设置成当前的这个Collection,如果attrs不是model,则用当前的Collection.model实例化一个model,把attrs当参数传进去,然后将完成的model放入toAdd数组里面,然后看该model是否设置id属性,设置了id属性则this._byId通过model.id来引用model,没有设置id属性,则通过model.cid来引用model,然后给model绑定一个"on"的监听回调事件
然后看此次操作不是排序并且是添加或者删除,则吧model加到order数组中
操作完对models的遍历后,我们可能拿到这样几个东西modelMap,toAdd,order
如果参数传入的参数中options.remove为真,则遍历modelMap,进行删除,这个modelMap是通过已存在的model来得到的
如果toAdd,order里面有数据则进行添加..
然后再options里面是否设置了排序属性sort,如果设置了,则进行排序
set是给collection重新设置models,是重新设置,之前的models会全部清掉
var c = new Backbone.Collection();
c.set([{a:1},{b:1},{c:1}]);
console.log(c.models) //有3个
c.set({d:1});
console.log(c.models) //只有1个了
add
add 很简单的就是设置set方法 把options参数里面的remove,merge设置成false,add设置成true
var c = new Backbone.Collection();
c.add([{a:1},new Backbone.Model(),new (Backbone.Model.extend({name:"newModel"}))()])
console.log(c.models)
//存入moldes里面的model可以由不同的Model构建出来,
remove collection.remove(models, [options])
首先将传入的models进行遍历,删除collection里面的_byId对象的属性,然后从collection的models里面删除对应的项,触发model的remove事件
var c = new Backbone.Collection;
var m = new Backbone.Model;
m.on("remove",function(){
alert("你删除我了")
})
c.add(m);
alert(c.models.length);
c.remove(m);
alert(c.models.length);
comparator sort
comparator如果是一个function,则是规定models按什么样子的规则排序的函数
如果是一个字符窜,则按models里面有的有的属性进行排序
sort就是调用排序了,除了用comparator,还可以用reverse直接对models进行倒叙
comparator是函数
var c = new Backbone.Collection([
{name:"a1",age:18,level:"一般"},
{name:"a2",age:16,level:"很差"},
{name:"a3",age:28,level:"很好"},
{name:"a4",age:11,level:"较好"},
],{
comparator : function(a,b){
return a.attributes.age-b.attributes.age
}
})
c.sort();
console.log(c.models);
//这个可以按age排序
//用法和数组的sort一模一样的
//修改comparator可以自定义排序 很好 较好 一般 很差
c.comparator = function(a,b){
var obj = {
"很好" : 5,
"较好" : 4,
"一般" : 3,
"很差" : 2
}
return obj[b.attributes.level] - obj[a.attributes.level]
}
c.sort();
console.log(c.models);
comparator是字符串
var c = new Backbone.Collection([
{name:"a1",age:18,level:"一般"},
{name:"a2",age:16,level:"很差"},
{name:"a3",age:28,level:"很好"},
{name:"a4",age:11,level:"较好"},
],{
comparator : "age"
})
c.sort();
console.log(c.models);
//按age来排序
c.sort({reverse:true});
console.log(c.models);
//进行倒序
Backbone.Collection扩展了很多数据的方法
['forEach', 'each', 'map', 'collect', 'reduce', 'foldl','inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select','reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke','max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest','tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle','lastIndexOf', 'isEmpty', 'chain', 'sample', 'partition'];
还扩展了一些underscore的方法
['groupBy', 'countBy', 'sortBy', 'indexBy']
backbone.Collection源码笔记的更多相关文章
- Backbone Events 源码笔记
用了backbone一段时间了,做一些笔记和总结,看的源码是1.12 backbone有events,model,collection,histoty,router,view这些模块,其中events ...
- Backbone Collection 源码简谈
一切由一个例子引发: var Man=Backbone.Model.extend({ initilize:function(){ this.bind('change:name',function(){ ...
- backbone.Model 源码笔记
backbone.Model backbone的model(模型),用来存储数据,交互数据,数据验证,在view里面可以直接监听model来达到model一改变,就通知视图. 这个里面的代码是从bac ...
- springmvc源码笔记-RequestMappingHandlerMapping
下图是springmvc的执行流程 图片来源:https://www.jianshu.com/p/8a20c547e245 DispatcherServlet根据url定位到Controller和方法 ...
- Zepto源码笔记(一)
最近在研究Zepto的源码,这是第一篇分析,欢迎大家继续关注,第一次写源码笔记,希望大家多指点指点,第一篇文章由于首次分析原因不会有太多干货,希望后面的文章能成为各位大大心目中的干货. Zepto是一 ...
- redis源码笔记(一) —— 从redis的启动到command的分发
本作品采用知识共享署名 4.0 国际许可协议进行许可.转载联系作者并保留声明头部与原文链接https://luzeshu.com/blog/redis1 本博客同步在http://www.cnblog ...
- AsyncTask源码笔记
AsyncTask源码笔记 AsyncTask在注释中建议只用来做短时间的异步操作,也就是只有几秒的操作:如果是长时间的操作,建议还是使用java.util.concurrent包中的工具类,例如Ex ...
- Java Arrays 源码 笔记
Arrays.java是Java中用来操作数组的类.使用这个工具类可以减少平常很多的工作量.了解其实现,可以避免一些错误的用法. 它提供的操作包括: 排序 sort 查找 binarySearch() ...
- Tomcat8源码笔记(八)明白Tomcat怎么部署webapps下项目
以前没想过这么个问题:Tomcat怎么处理webapps下项目,并且我访问浏览器ip: port/项目名/请求路径,以SSM为例,Tomcat怎么就能将请求找到项目呢,项目还是个文件夹类型的? Tom ...
随机推荐
- Linux环境下oracle创建和删除表空间及用户
#su - oracle $ sqlplus /nolog SQL> connect / as sysdba --//创建临时表空间 create temporary tablespace te ...
- PPAS上运行pg_dump经过
目前我有两台机器, 分别已经安装了PPAS9.1,安装后建立了OS系统用户enterprisedb和数据库用户enterprisedb. 机器1:master 192.168.10.88 机器2: ...
- Codeforces Round #180 (Div. 2) B. Sail 贪心
B. Sail 题目连接: http://www.codeforces.com/contest/298/problem/B Description The polar bears are going ...
- WinForm特效:桌面上的遮罩层
一个窗体特效,帮你了解几个windows api函数.效果:windows桌面上增加一个简单的遮罩层,其中WS_EX_TRANSPARENT 比较重要,它实现了鼠标穿透的功能. using Syste ...
- C# 图片裁剪代码
/// <summary> /// 缩小裁剪图片 /// </summary> /// <param name="int_Width">要缩小裁 ...
- oracle 迁移到 mysql(结构和数据)
1下载MySQL Migration Toolkit 2安装:jdk-6u38-ea-bin-b04-windows-amd64-31_oct_2012.exe 3下载ojdbc14.jar 具体地址 ...
- 【JavsScript】XMLHttpRequest Level 2 使用指南
XMLHttpRequest是一个浏览器接口,使得Javascript可以进行HTTP(S)通信. 最早,微软在IE 5引进了这个接口.因为它太有用,其他浏览器也模仿部署了,ajax操作因此得以诞生. ...
- Cocos2d html5 笔记 1: overview
昨天接触到了cocos2d-html5的的东东了, 第一次看其源代码一头雾水,幸好samples目录下面有几个例子,可以从这个入手. MoonWarriors是一个射击类的游戏, 有点像以前玩的雷电, ...
- cpio备份命令
cpio是一个比较古老的备份命令,也是用于磁带机备份的工具.虽然如此,现在许多时候仍然需要使用这个命令.例如定制系统内存映像盘时等. 小知识:系统内存映像盘通常位于引导分区/root中,文件名以ini ...
- php手册总结《安装与配置》
一:web服务器与php解释器的连接方式 有两个方法将 PHP 连接到服务器上. 1>通过SAPI模块来连接 对于很多服务器,PHP 均有一个直接的模块接口(也叫做 SAPI).这些服务器包括 ...