Backbone.js模型基础 #

一、什么是Model #

Model(模型)是Backbone.js的核心组件之一,用于管理应用程序的数据和业务逻辑。

1.1 Model的作用 #

text
Model职责
├── 数据存储:存储和管理应用数据
├── 数据验证:验证数据的有效性
├── 数据同步:与服务器进行数据同步
├── 业务逻辑:处理数据相关的业务逻辑
└── 事件通知:数据变化时通知相关组件

1.2 Model的特点 #

特点 说明
属性管理 通过get/set方法管理属性
事件驱动 属性变化时触发事件
验证机制 内置数据验证支持
RESTful 自动与RESTful API交互
唯一标识 每个模型有唯一id

二、创建Model #

2.1 基本创建方式 #

javascript
var Todo = Backbone.Model.extend({
    defaults: {
        title: '',
        completed: false,
        createdAt: null
    }
});

var todo = new Todo();
console.log(todo.toJSON());

2.2 extend方法 #

Backbone.Model.extend 用于创建自定义模型类:

javascript
var User = Backbone.Model.extend({
    defaults: {
        name: '',
        email: '',
        age: 0
    },
    
    initialize: function() {
        console.log('User模型已创建');
    }
});

extend参数:

参数 类型 说明
properties Object 实例属性和方法
classProperties Object 类属性和静态方法

2.3 初始化时传入属性 #

javascript
var todo = new Todo({
    title: '学习Backbone.js',
    completed: false
});

console.log(todo.get('title'));

2.4 initialize方法 #

initialize 方法在模型创建时自动调用:

javascript
var User = Backbone.Model.extend({
    initialize: function(attributes, options) {
        console.log('初始化属性:', attributes);
        console.log('初始化选项:', options);
        
        this.on('change', function() {
            console.log('模型属性已变化');
        });
    }
});

var user = new User({ name: '张三' }, { silent: true });

三、属性操作 #

3.1 获取属性 #

javascript
var user = new User({ name: '张三', age: 25 });

// 获取单个属性
var name = user.get('name');
console.log(name);

// 获取所有属性(副本)
var attrs = user.toJSON();
console.log(attrs);

// 获取属性值(直接访问,不推荐)
var name = user.attributes.name;

3.2 设置属性 #

javascript
var user = new User();

// 设置单个属性
user.set('name', '李四');

// 设置多个属性
user.set({
    name: '王五',
    age: 30,
    email: 'wangwu@example.com'
});

// 设置属性并触发事件
user.set('name', '赵六', { silent: false });

// 静默设置(不触发事件)
user.set('name', '钱七', { silent: true });

3.3 set方法选项 #

javascript
user.set('name', '张三', {
    silent: false,      // 是否静默设置
    validate: true,     // 是否验证
    unset: false        // 是否删除属性
});

选项说明:

选项 默认值 说明
silent false 是否静默设置(不触发事件)
validate true 是否调用validate验证
unset false 是否删除属性

3.4 删除属性 #

javascript
var user = new User({ name: '张三', age: 25 });

// 删除单个属性
user.unset('age');

// 删除所有属性
user.clear();

// 静默删除
user.unset('name', { silent: true });

3.5 检查属性 #

javascript
var user = new User({ name: '张三' });

// 检查属性是否存在
if (user.has('name')) {
    console.log('name属性存在');
}

// 检查属性是否为空
if (!user.has('email')) {
    console.log('email属性不存在');
}

3.6 转义属性 #

javascript
var user = new User({ name: '<script>alert("XSS")</script>' });

// 安全获取(转义HTML)
var safeName = user.escape('name');
console.log(safeName);

四、默认值 #

4.1 设置默认值 #

javascript
var Todo = Backbone.Model.extend({
    defaults: {
        title: '未命名任务',
        completed: false,
        createdAt: null,
        priority: 'normal'
    }
});

var todo = new Todo();
console.log(todo.toJSON());

4.2 函数形式的默认值 #

javascript
var Todo = Backbone.Model.extend({
    defaults: function() {
        return {
            title: '未命名任务',
            completed: false,
            createdAt: new Date().toISOString(),
            priority: 'normal'
        };
    }
});

4.3 默认值与传入属性合并 #

javascript
var Todo = Backbone.Model.extend({
    defaults: {
        title: '默认标题',
        completed: false,
        priority: 'normal'
    }
});

var todo = new Todo({ title: '自定义标题' });
console.log(todo.toJSON());

五、模型标识 #

5.1 id属性 #

javascript
var user = new User({ id: 1, name: '张三' });

console.log(user.id);
console.log(user.get('id'));
console.log(user.isNew());

5.2 idAttribute #

javascript
var User = Backbone.Model.extend({
    idAttribute: '_id'
});

var user = new User({ _id: 123, name: '张三' });
console.log(user.id);
console.log(user.idAttribute);

5.3 cid #

cid 是客户端自动生成的唯一标识:

javascript
var user1 = new User();
var user2 = new User();

console.log(user1.cid);
console.log(user2.cid);

5.4 isNew方法 #

javascript
var user1 = new User();
console.log(user1.isNew());

var user2 = new User({ id: 1 });
console.log(user2.isNew());

六、模型克隆 #

6.1 clone方法 #

javascript
var user = new User({ id: 1, name: '张三' });
var cloned = user.clone();

console.log(cloned.toJSON());
console.log(cloned.id);
console.log(cloned.cid);

6.2 克隆特点 #

javascript
var user = new User({ id: 1, name: '张三' });
var cloned = user.clone();

cloned.set('name', '李四');

console.log(user.get('name'));
console.log(cloned.get('name'));

七、模型事件 #

7.1 change事件 #

javascript
var user = new User({ name: '张三' });

user.on('change', function(model, options) {
    console.log('模型已变化');
});

user.on('change:name', function(model, value, options) {
    console.log('name已变更为:', value);
});

user.set('name', '李四');

7.2 事件类型 #

事件 触发时机
change 任何属性变化时
change:attr 特定属性变化时
destroy 模型销毁时
sync 同步成功时
error 同步失败或验证失败时
invalid 验证失败时
request 开始请求时

7.3 previous方法 #

javascript
var user = new User({ name: '张三', age: 25 });

user.on('change:name', function(model, value) {
    var previous = model.previous('name');
    console.log('旧值:', previous);
    console.log('新值:', value);
});

user.set('name', '李四');

7.4 previousAttributes方法 #

javascript
var user = new User({ name: '张三', age: 25 });

user.on('change', function(model) {
    var previous = model.previousAttributes();
    console.log('所有旧值:', previous);
    console.log('当前值:', model.toJSON());
});

user.set({ name: '李四', age: 30 });

八、模型方法 #

8.1 自定义方法 #

javascript
var User = Backbone.Model.extend({
    defaults: {
        firstName: '',
        lastName: ''
    },
    
    getFullName: function() {
        return this.get('firstName') + ' ' + this.get('lastName');
    },
    
    setFullName: function(fullName) {
        var parts = fullName.split(' ');
        this.set({
            firstName: parts[0],
            lastName: parts[1]
        });
    }
});

var user = new User({ firstName: '张', lastName: '三' });
console.log(user.getFullName());
user.setFullName('李 四');

8.2 计算属性 #

javascript
var Product = Backbone.Model.extend({
    defaults: {
        price: 0,
        quantity: 1,
        discount: 0
    },
    
    getTotal: function() {
        var price = this.get('price');
        var quantity = this.get('quantity');
        var discount = this.get('discount');
        return price * quantity * (1 - discount / 100);
    },
    
    getFormattedPrice: function() {
        return '¥' + this.get('price').toFixed(2);
    }
});

var product = new Product({ price: 100, quantity: 2, discount: 10 });
console.log(product.getTotal());
console.log(product.getFormattedPrice());

九、URL配置 #

9.1 urlRoot #

javascript
var User = Backbone.Model.extend({
    urlRoot: '/api/users'
});

var user = new User({ id: 1 });
console.log(user.url());

9.2 url方法 #

javascript
var User = Backbone.Model.extend({
    urlRoot: '/api/users',
    
    url: function() {
        var base = this.urlRoot;
        if (this.isNew()) {
            return base;
        }
        return base + '/' + this.id + '.json';
    }
});

9.3 集合中的URL #

javascript
var User = Backbone.Model.extend({});
var Users = Backbone.Collection.extend({
    model: User,
    url: '/api/users'
});

var users = new Users();
var user = new User({ id: 1 }, { collection: users });
console.log(user.url());

十、实用示例 #

10.1 Todo模型 #

javascript
var Todo = Backbone.Model.extend({
    defaults: {
        title: '',
        completed: false,
        createdAt: null
    },
    
    initialize: function() {
        if (!this.get('createdAt')) {
            this.set('createdAt', new Date().toISOString());
        }
    },
    
    toggle: function() {
        this.set('completed', !this.get('completed'));
    },
    
    isExpired: function() {
        var created = new Date(this.get('createdAt'));
        var now = new Date();
        var days = (now - created) / (1000 * 60 * 60 * 24);
        return days > 7;
    }
});

var todo = new Todo({ title: '学习Backbone.js' });
todo.toggle();
console.log(todo.isExpired());

10.2 用户模型 #

javascript
var User = Backbone.Model.extend({
    urlRoot: '/api/users',
    
    defaults: {
        name: '',
        email: '',
        role: 'user',
        active: true
    },
    
    validate: function(attrs) {
        var errors = [];
        
        if (!attrs.name || attrs.name.trim() === '') {
            errors.push('姓名不能为空');
        }
        
        if (!attrs.email || !attrs.email.match(/^[\w-]+@[\w-]+\.[a-z]+$/i)) {
            errors.push('邮箱格式不正确');
        }
        
        if (errors.length > 0) {
            return errors;
        }
    },
    
    isAdmin: function() {
        return this.get('role') === 'admin';
    },
    
    activate: function() {
        this.set('active', true);
    },
    
    deactivate: function() {
        this.set('active', false);
    }
});

10.3 文章模型 #

javascript
var Article = Backbone.Model.extend({
    urlRoot: '/api/articles',
    
    defaults: {
        title: '',
        content: '',
        author: '',
        tags: [],
        published: false,
        createdAt: null,
        updatedAt: null
    },
    
    initialize: function() {
        this.on('change', this.updateTimestamp);
        
        if (!this.get('createdAt')) {
            this.set('createdAt', new Date().toISOString());
        }
    },
    
    updateTimestamp: function() {
        this.set('updatedAt', new Date().toISOString(), { silent: true });
    },
    
    publish: function() {
        this.set('published', true);
        return this.save();
    },
    
    unpublish: function() {
        this.set('published', false);
        return this.save();
    },
    
    addTag: function(tag) {
        var tags = this.get('tags').slice();
        if (tags.indexOf(tag) === -1) {
            tags.push(tag);
            this.set('tags', tags);
        }
    },
    
    removeTag: function(tag) {
        var tags = this.get('tags').slice();
        var index = tags.indexOf(tag);
        if (index > -1) {
            tags.splice(index, 1);
            this.set('tags', tags);
        }
    },
    
    getExcerpt: function(length) {
        length = length || 100;
        var content = this.get('content') || '';
        if (content.length <= length) {
            return content;
        }
        return content.substring(0, length) + '...';
    }
});

十一、总结 #

11.1 Model核心API #

方法 说明
get(attr) 获取属性值
set(attr, value) 设置属性值
unset(attr) 删除属性
clear() 删除所有属性
has(attr) 检查属性是否存在
escape(attr) 转义后的属性值
toJSON() 获取属性副本
clone() 克隆模型
isNew() 是否为新模型

11.2 最佳实践 #

  1. 使用 defaults 设置合理的默认值
  2. 使用 get/set 方法而非直接访问 attributes
  3. 使用 escape 处理用户输入
  4. 合理使用事件监听
  5. 将业务逻辑封装在模型方法中
最后更新:2026-03-28