Object.observe简介

现在,双向数据绑定是客户端应用程序的关键功能之一。 如果没有数据绑定,则每当模型发生更改时,开发人员都必须处理大量逻辑以将数据手动绑定到视图。 像KnockoutAngularJSEmber这样的JavaScript库都支持双向绑定,但是这些库使用不同的技术来检测更改。

淘汰赛和灰烬使用可观察到的东西。 可观察对象是包装在模型对象属性周围的函数。 只要相应对象或属性的值发生更改,就会调用这些函数。 尽管这种方法行之有效,并且可以检测并通知所有更改,但它却剥夺了使用纯JavaScript对象的自由,因为现在我们必须处理函数。

Angular使用脏检查来检测更改。 这种方法不会污染模型对象。 它为添加到模型中的每个对象注册观察者。 只要Angular的摘要周期开始并且数据有任何更改,就会执行所有这些观察程序。 这些更改由相应的观察者处理。 该模型仍然是一个普通对象,因为没有围绕它创建包装器。 但是,随着观察者数量的增加,此技术会导致性能下降。

什么是Object.observe

Object.observe (又名Oo )是作为ECMAScript 7的一部分添加到JavaScript的功能,以支持浏览器中本机的对象更改检测。 尽管ES7尚未完成,但是基于闪烁的浏览器(Chrome和Opera)已经支持此功能。

由于Object.observe将由浏览器本地支持,并且可以直接在对象上运行而无需在其周围创建任何包装,因此该API既易于使用,又是性能的双赢。 如果浏览器支持Object.observe则可以实现双向绑定,而无需外部库。 这并不意味着一旦实现Oo ,所有现有的双向绑定库都将Oo 。 在使用Oo检测到更改后,我们仍然需要它们有效地更新UI。 此外,如果不是所有目标浏览器都支持Oo ,则库将在内部填充更改检测的逻辑。

观察对象的属性

现在,您已经了解了Oo的优点,让我们来看一下它的实际作用。

observe()方法是在Object定义的异步静态方法。 它可用于查找对象的更改,它接受三个参数:

  • 要观察的对象
  • 检测到更改时要调用的回调函数
  • 一个可选数组,其中包含要注意的更改类型

让我们看一个使用该方法的例子。 考虑以下代码段:

var person = {
  name: 'Ravi',
  country: 'India',
  gender: 'Male'
};

function observeCallback(changes){
  console.log(changes);
};

Object.observe(person, observeCallback);

person.name = 'Rama';  // Updating value
person.occupation = 'writer';  // Adding a new property
delete person.gender;  // Deleting a property

在这段代码中,我们创建了带有一些数据的对象文字。 我们还定义了一个名为observeCallback()的函数,该函数将用于记录对象的更改。 然后,我们开始使用Oo观察变化。 最后,我们对对象进行了一些更改。

如果您在控制台上看到输出,您将看到检测到并记录了所有三个更改。 以下屏幕截图显示了代码段产生的结果:

object.observe-example-1

Oo异步运行,它将所有发生的更改分组,并在调用时将它们传递给回调。 因此,这里我们收到了三个应用于对象的三个更改的条目。 如您所见,每个条目都包括更改后的属性的名称,旧值,更改的类型以及带有新值的对象本身。

下面报告了先前代码的实时演示(请记住打开控制台以查看结果):

请参阅CodePen上的SitePoint( @SitePoint )提供的Pen emKveB

在我们的代码中,我们没有指定要查找的更改类型,因此它会观察添加,更新和删除。 可以使用observe方法的第三个参数来控制它,如下所示:

Object.observe(person, observeCallback, ['add', 'update']);

注册通知

observe()方法能够检测对添加到对象的直接属性所做的更改。 它无法检测使用getter和setter创建的属性的更改。 由于这些属性的行为由作者控制,因此更改检测也必须归作者所有。 要解决此问题,我们需要使用一个通告程序(可通过Object.getNotifier() )来通知对该属性所做的更改。

考虑以下代码段:

function TodoType() {
  this.item = '';
  this.maxTime = '';
  
  var blocked = false;
  
  Object.defineProperty(this, 'blocked', {
    get:function(){
      return blocked;
    },
    set: function(value){
      Object.getNotifier(this).notify({
        type: 'update',
        name: 'blocked',
        oldValue: blocked
      });
      blocked = value;
    }
  });
}

var todo = new TodoType();

todo.item = 'Get milk';
todo.maxTime = '1PM';

console.log(todo.blocked);

Object.observe(todo, function(changes){
  console.log(changes);
}, ['add', 'update']);

todo.item = 'Go to office';
todo.blocked = true;

TodoType是具有两个属性的构造函数。 除了它们之外, blocked使用加入Object.defineProperty 。 在我们的示例中,为此属性定义的设置器很简单。 在典型的业务应用程序中,它可能会执行一些验证,并且在验证失败的情况下可能不会设置值。 但是,我想保持简单。
最后,您可以看到在我们的示例中,仅当有更新时才发送通知。

blocked的属性所做的更改在Chrome开发人员工具中产生以下结果:

object.observe-example-2

下面是该示例的实时演示(请记住打开控制台以查看结果):

请参阅CodePen上 SitePoint( @SitePoint )的Pen NPzgOO

观察多个变化

有时,在以某种方式修改了两个或更多属性之后,我们可能需要运行计算。 尽管我们可以使用通知程序分别通知这两个更改,但最好发送一个带有自定义类型名称的通知,以表明两个值均已修改。 这可以使用notifier.performChange()方法完成。 此方法接受三个参数:

  • 自定义类型的名称
  • 回调函数执行更改。 从此函数返回的值用于更改对象
  • 应用更改的对象

让我们向上面定义的类TodoType添加一个名为done的新属性。 此属性的值指定待办事项是否已完成。 当值done设置为true ,我们需要设置属性的值blocked ,以true为好。

以下代码段定义了此属性:

var done = false;
Object.defineProperty(this, 'done', {
    get: function(){
      return done;
    },
    set: function(value){
      if(value){
        var notifier = Object.getNotifier(this);
        
        if(blocked && value) {
          notifier.performChange('doneAndUnblocked', function(){
            done = value;
            blocked = false;
            
            return { oldDone: false, oldBlocked: true };
          }, this);
        }
        else{
          notifier.notify({
            type: 'update',
            name: 'done',
            oldValue: done
          });
          
          done = value;
        }
      }
    }
});

一旦执行performChange的回调内的逻辑,将通过传入的自定义更改类型来通知更改。 默认情况下, Object.observe不会观察到此类型。 我们需要明确要求Oo观察自定义类型的更改。 以下代码段显示了todo对象上的修改后的Oo ,以观察自定义类型以及添加和更新类型的更改:

Object.observe(todo, function(changes){
  console.log(changes);
}, ['add', 'update', 'doneAndUnblocked']);

todo.blocked = true;
todo.done = true;

上面的代码片段在将done设置为true之前,将blocked的值设置为true 。 因此,它将发送具有自定义更改类型的通知。 以下屏幕快照显示了自定义类型返回的更改对象的详细信息:

object.observe-example-3

下面是该示例的实时演示(请记住打开控制台以查看结果):

请参阅CodePen上的SitePoint( @SitePoint )的笔yyEXGd

观察阵列

观察数组类似于观察对象。 唯一的区别是观察者功能必须使用Array.observe而不是Object.observe注册。 以下代码段演示了这一点:

var array = ['morning', 'Afternoon', 'Evening'];

var arrayObserver = function(changes){
  console.log(changes);
};

Array.observe(array, arrayObserver);

array[0] = 'Morning';
array.push('Night');
array.splice(1, 1);

下面是该示例的实时演示(请记住打开控制台以查看结果):

见笔GgGEzQ由SitePoint( @SitePoint上) CodePen

删除注册的观察者

可以分别使用Object.unobserve()Array.unobserve()删除对象或数组上已注册的观察者。 此方法接受两个参数,对象或数组以及要删除的回调。 因此,要使用此方法,我们需要引用回调。

Object.unobserve(person, observeCallback);

结论

一旦所有浏览器都完全支持Oo ,所有客户端库中的更改检测都将标准化。 Aurelia已经开始使用它, Angular 2的更改检测库watchtower.js在内部使用OoEmber将来还将使用它进行更改检测。 Angular 2和Aurelia实施了pollyfills,以在Oo本身不可用时回退。

有了这些强大的浏览器,围绕客户端双向绑定的未来将更加光明。 让我们期待其他浏览器早日赶上!

From: https://www.sitepoint.com/introduction-object-observe/

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值