te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>object - JavaScript - Proxy set vs. defineProperty - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

object - JavaScript - Proxy set vs. defineProperty - Stack Overflow

programmeradmin2浏览0评论

I want to build a proxy that detects changes to an object:

  • New properties are defined.
  • Existing properties are changed.

Code Sample 1 - defineProperty

const me = {
  name: "Matt"
}

const proxy = new Proxy(me, {
  defineProperty: function(target, key, descriptor) {
    console.log(`Property ${key} defined.`);
    return Object.defineProperty(target, key, descriptor);
  }
});

proxy // { name: 'Matt' }

proxy.name = "Mark";
// Property name defined.
// Mark

proxy.age = 20;
// Property age defined.
// 20

Code Sample 1 - Observations

  • proxy has a property name which is what I'd expect.
  • Changing the name property tells me that name has been defined; not what I'd expect.
  • Defining the age property tells me that age has been defined; as I'd expect.

Code Sample 2 - set

const me = {
  name: "Matt"
}

const proxy = new Proxy(me, {
  defineProperty: function(target, key, descriptor) {
    console.log(`Property ${key} defined.`);
    return Object.defineProperty(target, key, descriptor);
  },
  set: function(target, key, value) {
    console.log(`Property ${key} changed.`);
    return target[key] = value;
  }
});

proxy // { name: 'Matt' }

proxy.name = "Mark";
// Property name changed.
// Mark

proxy.age = 20;
// Property age changed.
// 20

Code Sample 2 - Observations

  • proxy has a property name which is what I'd expect.
  • Changing the name property tells me that name has been changed; as I'd expect.
  • Defining the age property tells me that age has been changed; not what I'd expect.

Questions

  • Why does defineProperty catch property changes?
  • Why does the addition of set override defineProperty?
  • How do I get the proxy to correctly trap defineProperty for new properties and set for property changes?

I want to build a proxy that detects changes to an object:

  • New properties are defined.
  • Existing properties are changed.

Code Sample 1 - defineProperty

const me = {
  name: "Matt"
}

const proxy = new Proxy(me, {
  defineProperty: function(target, key, descriptor) {
    console.log(`Property ${key} defined.`);
    return Object.defineProperty(target, key, descriptor);
  }
});

proxy // { name: 'Matt' }

proxy.name = "Mark";
// Property name defined.
// Mark

proxy.age = 20;
// Property age defined.
// 20

Code Sample 1 - Observations

  • proxy has a property name which is what I'd expect.
  • Changing the name property tells me that name has been defined; not what I'd expect.
  • Defining the age property tells me that age has been defined; as I'd expect.

Code Sample 2 - set

const me = {
  name: "Matt"
}

const proxy = new Proxy(me, {
  defineProperty: function(target, key, descriptor) {
    console.log(`Property ${key} defined.`);
    return Object.defineProperty(target, key, descriptor);
  },
  set: function(target, key, value) {
    console.log(`Property ${key} changed.`);
    return target[key] = value;
  }
});

proxy // { name: 'Matt' }

proxy.name = "Mark";
// Property name changed.
// Mark

proxy.age = 20;
// Property age changed.
// 20

Code Sample 2 - Observations

  • proxy has a property name which is what I'd expect.
  • Changing the name property tells me that name has been changed; as I'd expect.
  • Defining the age property tells me that age has been changed; not what I'd expect.

Questions

  • Why does defineProperty catch property changes?
  • Why does the addition of set override defineProperty?
  • How do I get the proxy to correctly trap defineProperty for new properties and set for property changes?
Share Improve this question edited Jun 3, 2023 at 17:37 dumbass 27.2k4 gold badges36 silver badges73 bronze badges asked Jun 13, 2020 at 9:52 Matthew LaytonMatthew Layton 42.3k57 gold badges207 silver badges333 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 16

Why does defineProperty catch property changes?

Because when you change a data property (as opposed to an accessor), through a series of specification steps it ends up being a [[DefineOwnProperty]] operation. That's just how updating a data property is defined: The [[Set]] operation calls OrdinarySet which calls OrdinarySetWithOwnDescriptor which calls [[DefineOwnProperty]], which triggers the trap.

Why does the addition of set override defineProperty?

Because when you add a set trap, you're trapping the [[Set]] operation and doing it directly on the target, not through the proxy. So the defineProperty trap isn't fired.

How do I get the proxy to correctly trap defineProperty for new properties and set for property changes?

The defineProperty trap will need to differentiate between when it's being called to update a property and when it's being called to create a property, which it can do by using Reflect.getOwnPropertyDescriptor or Object.prototype.hasOwnProperty on the target.

const me = {
  name: "Matt"
};

const hasOwn = Object.prototype.hasOwnProperty;
const proxy = new Proxy(me, {
  defineProperty(target, key, descriptor) {
    if (hasOwn.call(target, key)) {
      console.log(`Property ${key} set to ${descriptor.value}`);
      return Reflect.defineProperty(target, key, descriptor);
    }
    console.log(`Property ${key} defined.`);
    return Reflect.defineProperty(target, key, descriptor);
  },
  set(target, key, value, receiver) {
    if (!hasOwn.call(target, key)) {
      // Creating a property, let `defineProperty` handle it by
      // passing on the receiver, so the trap is triggered
      return Reflect.set(target, key, value, receiver);
    }
    console.log(`Property ${key} changed to ${value}.`);
    return Reflect.set(target, key, value);
  }
});

proxy; // { name: 'Matt' }

proxy.name = "Mark";
// Shows: Property name changed to Mark.

proxy.age = 20;
// Shows: Property age defined.

That's a bit off-the-cuff, but it'll get you heading the right direction.

You could do it just with a set trap, but that wouldn't be fired by any operation that goes direct to [[DefineOwnProperty]] rather than going through [[Set], such as Object.defineProperty.

发布评论

评论列表(0)

  1. 暂无评论