a = 1,a = a++,a等于2?错!

142 阅读2分钟

前言

室友最近在学习vue3的响应式原理,突然在寝室群抛了一道题出来,菜的我不敢吱声,只能默默打开我的浏览器,实践是校验真理的唯一标准。

无标题.png

weak.png

初见

让我们来看看原问题

const data = {
name: 'fhj',
age: 18,
}
const obj = new Proxy(data, {
    get(target, key) {
        return target[key]
    },
    set(target, key, newVal) {
        target[key] = newVal
    }
})
obj.age = obj.age++;
console.log(obj.age)

我的第一反应是

obj.age = (obj.age = obj.age + 1)

然后从右向左执行按照这个逻辑应该打印19,但是...

ans.png
image.png

规范

为了找到答案,我去查了查ECMAScript的规范

G5PT30L3VN`U6I9OV@K)QQ4.png
可以理解成将老值保存下来,再进行自增,最后将老值返回。

代入规范

const data = {
  name: "fhj",
  age: 18,
};
const obj = new Proxy(data, {
  get(target, key) {
    return target[key];
  },
  set(target, key, newVal) {
    target[key] = newVal;
  },
});
obj.age = obj.age++;
console.log(obj.age);
(obj.age = 18)
obj.age++;
1. lhs -> obj.age;
2. oldValue = 18;
3. newValue = oldValue + 1 = 19;
4. 此处oldValue是Number跳过
5. obj.age = newValue(19)
6. return oldValue(即18)
obj.age = obj.age++ = 18

验证规范

Proxy

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截。

const data = {
  name: "fhj",
  age: 18,
};
const obj = new Proxy(data, {
  get(target, key) {
  //target为原对象,也就是data
    console.log('get:', target, key);
    return target[key];
  },
  set(target, key, newVal) {
  //newVal设置的新值
    console.log('set:', target, key, newVal)
    target[key] = newVal;
  },
});
// 此处obj就是data的代理对象
console.log(obj.age) //通过obj访问data的属性,触发get
obj.age = 2; //通过obj设置data的属性,触发set

9MY{09@UI9R@)Q(79GFFV.png

验证

const data = {
  name: "fhj",
  age: 18,
};
const obj = new Proxy(data, {
  get(target, key) {
    console.log('get', target, key);
    return target[key];
  },
  set(target, key, newVal) {
    console.log('set', target, key, newVal)
    target[key] = newVal;
  },
});
obj.age = obj.age++;
console.log(obj.age);

test.png

get: { name: 'fhj', age: 18 } age        (规范第二步 读取age的值)
set: { name: 'fhj', age: 18 } age 19     (规范第五步 将newVal的值给age)
set: { name: 'fhj', age: 19 } age 18     (obj.age = ...设置值触发,此处18就是规范第六步返回的老值)
get: { name: 'fhj', age: 18 } age       (console.log(obj.age);访问值触发)
18

a = a++, a = 2 ?

回到标题 a = a++,a = 2 ?

let a = 1;
a = a++;
console.log(a)
a++
1.lhs -> a;
2. oldValue = 1;
3. newValue = oldValue + 1 = 2;
4. 此处oldValue是Number跳过
5. a = newValue(2)
6. return oldValue(即1)

如有错误,欢迎━(`∀´)ノ亻!斧正。