Backbone.js模型属性 #

一、属性基础 #

1.1 属性存储 #

Backbone.js模型的属性存储在 attributes 对象中:

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

console.log(user.attributes);

1.2 属性访问原则 #

text
推荐方式:使用 get/set 方法
├── 触发事件
├── 支持验证
├── 支持计算属性
└── 保持封装性

不推荐:直接访问 attributes
├── 不触发事件
├── 绕过验证
└── 破坏封装性

二、获取属性 #

2.1 get方法 #

javascript
var user = new Backbone.Model({
    name: '张三',
    age: 25,
    email: 'zhangsan@example.com'
});

var name = user.get('name');
var age = user.get('age');

console.log(name);
console.log(age);

2.2 获取嵌套属性 #

javascript
var user = new Backbone.Model({
    name: '张三',
    address: {
        city: '北京',
        district: '朝阳'
    }
});

var address = user.get('address');
console.log(address.city);

2.3 toJSON方法 #

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

var json = user.toJSON();
console.log(json);
console.log(JSON.stringify(user));

2.4 获取属性列表 #

javascript
var user = new Backbone.Model({
    name: '张三',
    age: 25,
    email: 'zhangsan@example.com'
});

var keys = Object.keys(user.attributes);
console.log(keys);

三、设置属性 #

3.1 设置单个属性 #

javascript
var user = new Backbone.Model();

user.set('name', '张三');
user.set('age', 25);

console.log(user.toJSON());

3.2 设置多个属性 #

javascript
var user = new Backbone.Model();

user.set({
    name: '李四',
    age: 30,
    email: 'lisi@example.com'
});

console.log(user.toJSON());

3.3 链式设置 #

javascript
var user = new Backbone.Model();

user.set('name', '张三')
    .set('age', 25)
    .set('email', 'zhangsan@example.com');

console.log(user.toJSON());

3.4 set方法选项 #

javascript
var user = new Backbone.Model({ name: '张三' });

user.on('change', function() {
    console.log('属性已变化');
});

user.set('name', '李四', {
    silent: false,
    validate: true
});

选项详解:

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

3.5 静默设置 #

javascript
var user = new Backbone.Model({ name: '张三' });

user.on('change', function() {
    console.log('触发了change事件');
});

user.set('name', '李四', { silent: true });
console.log(user.get('name'));

四、删除属性 #

4.1 unset方法 #

javascript
var user = new Backbone.Model({
    name: '张三',
    age: 25,
    email: 'zhangsan@example.com'
});

user.unset('email');
console.log(user.has('email'));
console.log(user.toJSON());

4.2 clear方法 #

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

user.clear();
console.log(user.toJSON());

4.3 使用set删除 #

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

user.set('age', null, { unset: true });
console.log(user.has('age'));

4.4 删除触发事件 #

javascript
var user = new Backbone.Model({ name: '张三' });

user.on('change:name', function(model, value) {
    console.log('name属性已删除');
});

user.unset('name');

五、检查属性 #

5.1 has方法 #

javascript
var user = new Backbone.Model({
    name: '张三',
    age: 0,
    email: ''
});

console.log(user.has('name'));
console.log(user.has('age'));
console.log(user.has('email'));
console.log(user.has('phone'));

5.2 检查非空属性 #

javascript
var user = new Backbone.Model({
    name: '张三',
    age: 0,
    email: ''
});

function hasValue(model, attr) {
    var value = model.get(attr);
    return value !== null && value !== undefined && value !== '';
}

console.log(hasValue(user, 'name'));
console.log(hasValue(user, 'age'));
console.log(hasValue(user, 'email'));

5.3 检查属性类型 #

javascript
var user = new Backbone.Model({
    name: '张三',
    age: 25,
    tags: ['js', 'backbone'],
    active: true
});

console.log(typeof user.get('name'));
console.log(typeof user.get('age'));
console.log(Array.isArray(user.get('tags')));
console.log(typeof user.get('active'));

六、属性转义 #

6.1 escape方法 #

javascript
var user = new Backbone.Model({
    name: '<script>alert("XSS")</script>',
    bio: '<p>这是<b>简介</b></p>'
});

var safeName = user.escape('name');
var safeBio = user.escape('bio');

console.log(safeName);
console.log(safeBio);

6.2 安全渲染 #

javascript
var UserView = Backbone.View.extend({
    template: _.template(
        '<div class="user">' +
        '  <h2><%= name %></h2>' +
        '  <p><%= bio %></p>' +
        '</div>'
    ),
    
    render: function() {
        var data = {
            name: this.model.escape('name'),
            bio: this.model.escape('bio')
        };
        this.$el.html(this.template(data));
        return this;
    }
});

七、属性变化追踪 #

7.1 previous方法 #

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

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

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

7.2 previousAttributes方法 #

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

user.on('change', function(model) {
    var oldAttrs = model.previousAttributes();
    var newAttrs = model.toJSON();
    
    console.log('变化前:', oldAttrs);
    console.log('变化后:', newAttrs);
});

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

7.3 changedAttributes方法 #

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

user.on('change', function(model) {
    var changed = model.changedAttributes();
    console.log('变化的属性:', changed);
});

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

7.4 hasChanged方法 #

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

user.on('change', function(model) {
    if (model.hasChanged('name')) {
        console.log('name已变化');
    }
    if (model.hasChanged('age')) {
        console.log('age已变化');
    }
});

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

八、属性事件 #

8.1 change事件 #

javascript
var user = new Backbone.Model();

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

user.set('name', '张三');

8.2 change:attr事件 #

javascript
var user = new Backbone.Model();

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

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

user.set({ name: '张三', age: 25 });

8.3 批量监听 #

javascript
var user = new Backbone.Model();

user.on({
    'change:name': function(model, value) {
        console.log('name:', value);
    },
    'change:age': function(model, value) {
        console.log('age:', value);
    },
    'change:email': function(model, value) {
        console.log('email:', value);
    }
});

user.set({
    name: '张三',
    age: 25,
    email: 'zhangsan@example.com'
});

8.4 事件上下文 #

javascript
var UserView = Backbone.View.extend({
    initialize: function() {
        this.listenTo(this.model, 'change', this.render);
        this.listenTo(this.model, 'change:name', this.onNameChange);
    },
    
    render: function() {
        console.log('重新渲染');
        return this;
    },
    
    onNameChange: function(model, value) {
        console.log('姓名变化:', value);
    }
});

九、默认值处理 #

9.1 defaults对象 #

javascript
var User = Backbone.Model.extend({
    defaults: {
        name: '匿名用户',
        age: 0,
        email: '',
        role: 'user'
    }
});

var user = new User();
console.log(user.toJSON());

9.2 defaults函数 #

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

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

9.3 默认值合并 #

javascript
var User = Backbone.Model.extend({
    defaults: {
        name: '匿名',
        age: 0,
        role: 'user'
    }
});

var user = new User({ name: '张三' });
console.log(user.toJSON());

9.4 深层默认值 #

javascript
var User = Backbone.Model.extend({
    defaults: function() {
        return {
            name: '',
            settings: {
                theme: 'light',
                language: 'zh-CN',
                notifications: true
            }
        };
    }
});

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

user1.get('settings').theme = 'dark';

console.log(user1.get('settings').theme);
console.log(user2.get('settings').theme);

十、实用技巧 #

10.1 属性类型转换 #

javascript
var Product = Backbone.Model.extend({
    defaults: {
        price: 0,
        quantity: 1,
        active: false
    },
    
    set: function(key, value, options) {
        if (typeof key === 'object') {
            options = value;
            value = key;
            key = null;
        }
        
        var attrs = key || value;
        
        if (attrs.price !== undefined) {
            attrs.price = parseFloat(attrs.price) || 0;
        }
        if (attrs.quantity !== undefined) {
            attrs.quantity = parseInt(attrs.quantity, 10) || 0;
        }
        if (attrs.active !== undefined) {
            attrs.active = Boolean(attrs.active);
        }
        
        return Backbone.Model.prototype.set.call(this, attrs, options);
    }
});

var product = new Product({ price: '99.99', quantity: '5', active: 'true' });
console.log(product.toJSON());

10.2 计算属性 #

javascript
var Rectangle = Backbone.Model.extend({
    defaults: {
        width: 0,
        height: 0
    },
    
    getArea: function() {
        return this.get('width') * this.get('height');
    },
    
    getPerimeter: function() {
        return 2 * (this.get('width') + this.get('height'));
    },
    
    isSquare: function() {
        return this.get('width') === this.get('height');
    }
});

var rect = new Rectangle({ width: 10, height: 5 });
console.log('面积:', rect.getArea());
console.log('周长:', rect.getPerimeter());
console.log('是否正方形:', rect.isSquare());

10.3 属性别名 #

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('李 四');

10.4 属性观察者 #

javascript
var User = Backbone.Model.extend({
    initialize: function() {
        this.on('change:email', this.validateEmail, this);
    },
    
    validateEmail: function(model, email) {
        if (email && !email.match(/^[\w-]+@[\w-]+\.[a-z]+$/i)) {
            console.warn('邮箱格式可能不正确:', email);
        }
    }
});

var user = new User();
user.set('email', 'invalid-email');
user.set('email', 'valid@example.com');

十一、总结 #

11.1 属性操作API #

方法 说明 返回值
get(attr) 获取属性值 属性值
set(key, value, options) 设置属性值 this
unset(attr, options) 删除属性 this
clear(options) 删除所有属性 this
has(attr) 检查属性是否存在 Boolean
escape(attr) 获取转义后的属性值 String
toJSON() 获取属性副本 Object

11.2 变化追踪API #

方法 说明 返回值
previous(attr) 获取变化前的属性值 属性值
previousAttributes() 获取变化前的所有属性 Object
changedAttributes(diff) 获取变化的属性 Object
hasChanged(attr) 检查属性是否变化 Boolean

11.3 最佳实践 #

  1. 始终使用 get/set 方法访问属性
  2. 使用 escape 处理用户输入
  3. 使用函数形式的 defaults 避免引用共享
  4. 合理使用事件监听属性变化
  5. 将计算属性封装为模型方法
最后更新:2026-03-28