Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

让 (a == 1 && a == 2 && a == 3) 的值为true #45

Open
TieMuZhen opened this issue Nov 27, 2021 · 0 comments
Open

让 (a == 1 && a == 2 && a == 3) 的值为true #45

TieMuZhen opened this issue Nov 27, 2021 · 0 comments

Comments

@TieMuZhen
Copy link
Owner

TieMuZhen commented Nov 27, 2021

前备知识

首先了解类型转换规则Proxy 与 Object.defineProperty区别,然后思考当对象相加obj1 + obj2,相减obj1 - obj2obj1 == 2或者使用alert(obj)打印时会发生什么?

在这种情况下,对象会被自动转换为原始值,然后执行操作。

注意: 所有的对象在布尔上下文(context)中均为 true。所以对于对象,不存在 boolean 转换,只有字符串和数值转换
JavaScript 尝试查找并调用三个对象方法:

  1. 调用obj[Symbol.toPrimitive](hint) —— 如果这个方法存在的话,
  2. 否则,如果 hint 是"string" —— 先尝试obj.toString() obj.valueOf(),无论哪个存在。
  3. 否则,如果 hint 是 "number" "default" —— 先尝试obj.valueOf() obj.toString(),无论哪个存在。

下面的例子展示了, Symbol.toPrimitive属性是如何干扰一个对象转换为原始值时输出的结果的

+前缀是转换为数字,即Number(),!!前缀是转换为布尔型

// 一个没有提供 Symbol.toPrimitive 属性的对象,参与运算时的输出结果
var obj1 = {};
console.log(+obj1);      // NaN
console.log(`${obj1}`);  // "[object Object]"
console.log(obj1 + ""); // "[object Object]"

// 接下面声明一个对象,手动赋予了 Symbol.toPrimitive 属性,再来查看输出结果
var obj2 = {
  [Symbol.toPrimitive](hint) {
    if (hint == "number") {
      return 10;
    }
    if (hint == "string") {
      return "hello";
    }
    return true;
  }
};
console.log(obj2);        // "hello" -- hint 参数值是 "string"
console.log(+obj2);      // 10      -- hint 参数值是 "number"
console.log(`${obj2}`);  // "hello" -- hint 参数值是 "string"
console.log(obj2 + ""); // "true"  -- hint 参数值是 "default"

toString/valueOf

方法toStringvalueOf方法出现的比 symbol早。

如果没有Symbol.toPrimitive,那么 JavaScript 将尝试找到它们,并且按照下面的顺序进行尝试:

  • 对于 “string” hint,toString -> valueOf
  • 其他情况,valueOf -> toString

默认情况下,普通对象具有 toString 和 valueOf 方法:

  • toString方法返回一个字符串"[object Object]"
  • valueOf方法返回对象自身
let user = {name: "John"};

alert(user);  // [object Object]
alert(user.valueOf() === user);   // true

通常我们希望有一个“全能”的来处理所有原始转换。在这种情况下,我们可以只实现toString

let user = {
  name: "John",

  toString() {
    return this.name;
  }
};

alert(user); // toString -> John
alert(user + 500); // toString -> John500

返回类型

没有限制 toString() 是否返回字符串,或 Symbol.toPrimitive 方法是否为 hint “number” 返回数字。唯一强制性的事情是:这些方法必须返回一个原始值,而不是对象

解题方法

隐式转换

let i = 1;
const a = {
    valueOf: function () {
        return i++;
    }
}

// 或者

const a = (function() {
    let i = 1;
    return {
        valueOf: function () {
            return i++;
        }
    }
})()

Symbol.toPrimitive

//部署 [Symbol.toPrimitive] / valueOf/ toString 皆可
//一次返回1,2,3 即可。
let a = {
    [Symbol.toPrimitive]: (function(hint) {
            let i = 1;
            //闭包的特性之一:i 不会被回收
            return function() {
                return i++;
            }
    })()
}

Proxy

let a = new Proxy({i: 1}, {
    get(target, key) { 
        return () => target.i++;
    }
});

Object.defineProperty

let val = 1;
Object.defineProperty(window, 'a', {
    get() {
        return val++;
    }
})

参考文章

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant