转换为原始 [duplicate]

Convert to primitive [duplicate]

提问人:jeweler23 jeweler23 提问时间:11/16/2023 最后编辑:Mister Jojojeweler23 jeweler23 更新时间:11/17/2023 访问量:107

问:

console.log(sum(1)(2)(3));  // -> 6
console.log(sum(3)(15));   // -> 18 

function sum(a) {
  let currentSum = a;

  function f(b) {
    currentSum += b;
    return f;
  }
  f.toString = function() {
    return currentSum;
  };
  return f;
}

此函数添加传递给它的参数,并在所有添加后返回字符串 currentSum。我真的不明白转换为原语是如何发生的,以及为什么要通过函数编写它

JavaScript 函数 类型

评论

1赞 Mister Jojo 11/16/2023
看起来像一个闭合。你不添加一些关于如何使用它的代码吗?
1赞 jeweler23 jeweler23 11/16/2023
sum(1)(2)(3) // 返回 6.如果我正确理解你想要什么
3赞 Weijun Zhou 11/16/2023
sum(1)(2)(3)不返回 。它返回一个函数对象,当用于例如 可以通过 自动转换为字符串。所以可以打印 6.6console.logtoStringconsole.log(sum(1)(2)(3))
1赞 Mister Jojo 11/16/2023
所以,这是一个带有“链接”方法的闭包......
1赞 Mister Jojo 11/16/2023
因为 .toString() 是任何 JS 对象的默认方法。此闭包使此方法重载。所以用这个方法来显示信息console.log().tostring()

答:

1赞 KooiInc 11/16/2023 #1

Function 的默认函数将返回字符串化函数。换句话说:函数的原始值是......手头的功能。要显示 中的(中间的、封闭的)基元值,您需要重写 的函数。toStringcurrentSumftoStringf

也许下一个片段澄清了这一点。

注意:第一个代码段中的最后一个代码使用 .为什么有效?这在 MDN 中进行了解释:console.log+sum(1)(2)(3)

一元加号对其操作数执行数字强制,对于大多数没有@@toPrimitive的对象,这意味着调用其 valueOf()。但是,如果对象没有自定义 valueOf() 方法,则基本实现将导致忽略 valueOf(),并改用 toString() 的返回值。

// note: default values for parameters added
function sum(startValue = 0) {
  // [currentSum] is enclosed for further operations
  let currentSum = startValue;
  
  function f(value = 0) {
    currentSum += value;
    // returning the function
    // makes it possible to call
    // it again with a new value
    return f;
  }
  
  // f.toString would deliver the stringification
  // of the function f. To retrieve the value of 
  // [currentSum] that should be overridden.
  f.toString = function() {
    return currentSum;
  };
  
  // return the function with the overridden
  // toString method
  return f;
}

function someFunction() {
  return `Hi! I am the result of someFunction()`;
}

// the primitive value of [someFunction] is ...
// a function, so you can call it using 
// its valueOf
console.log(`someFunction.valueOf()(): ${someFunction.valueOf()()}`);

// a functions default 'toString' returns
// the string representation of the function
console.log(`someFunction.toString(): ${someFunction.toString()}`);


const six = sum(1)(2)(3);
// six is a function
console.log(`const six = sum(1)(2)(3);
typeof six: ${typeof six}`);

// toString (of the function) is automatically 
// invoked within a template string
console.log(`current value of six: ${six}`);

// change [currentSum] (six is still a function)
console.log(`typeof six(10): ${typeof six(10)}`);

// the value of six has changed
console.log(`current value of six: ${six}`);

// comparisons with a Number
// no type coercion (==)
console.log(`six == 16 ${six == 16}`);

// use toString for type coerced comparison with Number
console.log(`six.toString() === 16 ${six.toString() === 16}`);

// [six] is still a function, so
console.log(`six === 16 ${six === 16}`);

// to compare a [sum] result with a number 
// with type coercion (===)
// it can be converted to Number (+)
// see answer text for explanation.
console.log(`+sum(1)(2)(3) === 6 ${+sum(1)(2)(3) === 6}`);
.as-console-wrapper {
    max-height: 100% !important;
}

为了好玩:因为 a 只是另一个对象,你也可以用你自己的 'value' 方法扩展它。在这种情况下,您必须显式调用扩展方法来检索包含的值。Function

function sum(a = 0) {
  let currentSum = a;

  const f = (value = 0) => {
    currentSum += value;
    return f;
  }
  
  // extend
  f.value = _ => currentSum;
  f.reset = _ => { currentSum = 0; return f; }
  f.increment = _ => { currentSum += 1; return f; }
    
  return f;
}

const six = sum()(1)(2)(3);
console.log(`six.value(): ${six.value()}`);
console.log(`six(10).value(): ${six(10).value()}`);
console.log(`six.increment().value(): ${six.increment().value()}`);
console.log(`six.reset().value(): ${six.reset().value()}`);
console.log(`six(1)(2)(3).value(): ${six.reset()(1)(2)(3).value()}`);
.as-console-wrapper {
    max-height: 100% !important;
}

更进一步的步骤是将方法转换为 getters(这样你就不需要使用括号了),或者将你自己的 setter 添加到函数中:

function sum(a = 0) {
  let currentSum = a;

  function f(value = 0){
    currentSum += value;
    return f;
  }
  
  const extensions = {
    get value() { return currentSum; },
    set value(val) {currentSum = val; return f; },
    get reset() { currentSum = 0; return f; },
    get increment() { currentSum += 1; return f; },
  };
  
  Object.entries(Object.getOwnPropertyDescriptors(extensions))
    .forEach( ([key, descriptor]) => { 
      Object.defineProperty(f, key, descriptor); 
    } );
  
  return f;
}

const six = sum(1)(2)(3);
console.log(`native six.toString(): ${six}`);
console.log(`six.value: ${six.value}`);
console.log(`six(10).value: ${six(10).value}`);
console.log(`six.increment.value: ${six.increment.value}`);
console.log(`six.reset.value: ${six.reset.value}`);
console.log(`six.increment(2)(3).value: ${six.increment(2)(3).value}`);
six.value = 12;
console.log(`six.value = 12;
six(30).value: ${six(30).value}`);
.as-console-wrapper {
    max-height: 100% !important;
}

评论

0赞 jeweler23 jeweler23 11/17/2023
我理解正确吗?我们将第一个参数 a 写入变量 currentSum,sum 返回函数 f,但没有调用它,事实证明,如果我们传递第二个参数 b(2),那么通过闭包我们得到 currentSum 的值并将其与 2 相加,再次返回 f 作为下一个参数,如果没有, 然后我们退出函数并输出结果,我们将 currentSum 转换为原始 f,我们使用 toString 方法,我们传递到那里,我们需要将 currentSum 转换为字符串,当使用 == 或 alert 进一步时,会返回字符串值 currentSum 吗?
0赞 KooiInc 11/17/2023
不完全是。该函数可以称为工厂函数,该函数返回一个修改后的函数,以将值添加到封闭的值(第一次调用的参数值)。如果调用不带参数的函数,它仍将返回该函数。只有当隐式或显式使用时,它才会返回原始值(根据函数中的重写。我在第一个片段中添加了额外的注释和价值比较,希望能使事情更清楚sumsumtoStringFunction.toStringsum
1赞 Mister Jojo 11/16/2023 #2

Q&R
-1- 什么是?
在 JS 中,一切都是 Object(即使它们被定义为函数)。
sum()

-2- 什么是?
它是 里面的局部值。
此局部值只能在 的作用域内更改。
currentSumsum()sum()

-3- 什么是?
一个对象函数,它添加他的参数值
并返回自身(一个函数)
fcurrentSum

-4- 什么是?
它是对象上的重载方法,它重载了 Deault(JavaScript 是一个原型对象
模型)
f.toStringfObject.prototype.toString()

-5- 发生了什么?
有不同的步骤:
console.log(sum(1)(2)(3));

__a) -> currentSum = 1,并查看 sum() 的最后一行
__b) -> currentSum += 2 和 __c) -> currentSum += 3 和

__d) => 调用 的方法。
let fctA = sum(1)return flet fctB = fctA(2)return flet fctC = fctA(3)return flet D = fctC.toString()toString()f

let fctA = sum(1);
let fctB = fctA(2);
let fctC = fctA(3);
let D = fctC.toString(); //--> sum is: 6

console.log( D );

function sum(a)
  {
  let currentSum = a;
  function f(b) 
    {
    currentSum += b;
    return f;
    }
  f.toString = function()
    {
    return `sum is: ${currentSum}`;
    };
  return f;
  }

但是我们如何进入[?],因为在最后一个参数之后,我们又回来了f.toStringf

是的,它仍然返回.
但也是一个 JS 对象,它 [本身] 有一个名为 的 [默认] 方法。 由于此方法已存在于所有 JS 对象中,因此默认情况下会覆盖此方法。
fftoStringf.toString

--

编写 js 函数的方法至少有 2 种:(1)
(2)
function foo() {...}var foo = function() {...}

在此代码中,这是方式 (2)。
但也意味着 -> 是 Object 上的一种方法。
f.toString = function() {...}f.toStringtoStringf

--

也许这可能会有所帮助

console.log( sum(1)(2)(3) );
         ║    ┗┳━┛  ┃  ┃
         ║   A ▉────┃──┃──🭬let currentSum = 1;
         ║     ┃    ┃  ┃    return f;
         ║     ┗━┳━━┛  ┃    
         ║     B ▉─────┃──🭬currentSum += 2;
         ║       ┃     ┃    return f;    
         ║       ┗━━┳━━┛  
         ║        C ▉─────🭬currentSum += 3;
         ║          ║         return f;
         ║          ║ 
        D╙──────────╨🭬call prototype method of function.toString()
                       find overiding method: f.toString()
                            return `sum is: ${currentSum}`;

评论

0赞 jeweler23 jeweler23 11/16/2023
1.It 事实证明,我们已经创建了一个 sum 函数和一个局部变量 currSum,它存储了第一个参数 a 2.接下来,函数 f 及其局部环境被初始化 3.然后我们的 sum 函数返回 f 并出现加法 currSum 和 b。现在函数 f 返回自身 4.这之前我很清楚。但是我们如何进入 f.toString,因为在最后一个参数之后我们返回了 f?
0赞 jeweler23 jeweler23 11/17/2023
知道了!!我不太明白在没有()的情况下编写函数的方法
0赞 jeweler23 jeweler23 11/17/2023
我理解正确吗?我们将第一个参数 a 写入变量 currentSum,sum 返回函数 f,但没有调用它,事实证明,如果我们传递第二个参数 b(2),那么通过闭包我们得到 currentSum 的值并将其与 2 相加,再次返回 f 作为下一个参数,如果没有, 然后我们退出函数并输出结果,我们将 currentSum 转换为原始 f,我们使用 toString 方法,我们传递到那里,我们需要将 currentSum 转换为字符串,当使用 == 或 alert 进一步时,会返回字符串值 currentSum 吗?
0赞 Mister Jojo 11/17/2023
@jeweler23jeweler23 当你写 : 时,这可以分解为步骤: , , .但写起来还是比较容易的.sum(1)(2)(3) 也是如此。a=b*c*d*eM1=b*cM2=M1*da=M2*da=b*c*d*e
0赞 Mister Jojo 11/17/2023
@jeweler23jeweler23 你似乎忽略了 Javascript 是一种基于对象的语言这一事实。也就是说,函数的创建是 Object 的创建,它是从引用原型构建的,由多种方法(如方法)制成。toString