toString 实现无限累加

384

题目

用 js 实现无限累加

add(1) add(1)(2) add(1)(2)(3)

function add(...args) {
  const fn = function(...fn_args) {
      return add.apply(null, [...args, ...fn_args])
  }
  fn.toString = function() {
      return args.reduce((res, cur) => (res + cur))
  }
  return fn
}

+ add(1) // 1
+ add(1, 2) // 3
+ add(1)(2)(3) // 6

另一种解法

function curry(fn) {
  let allArgs = []
  return function tmp(...args) {
    if (args.length) {
      allArgs = [...allArgs, ...args]
      return tmp
    } else {
      const res = fn.apply(null, allArgs)
      allArgs = []
      return res
    }
  }
}

function add(...args) {
  return args.reduce((res, cur) => (res + cur))
}

const addFn = curry(add)

addFn(1)()            // 1
addFn(1, 2)()         // 3
addFn(1)(2, 3)()      // 6
addFn(1)(2, 3)(4)()   // 10

概念

object.toString() 返回一个表示该对象的字符串。

object.valueOf() 返回指定对象的原始值。

可重写 toString、valueOf 方法覆盖

不同类型对象的 valueOf() 方法的返回值

对象返回值
Array返回数组对象本身。
Boolean布尔值。
Date存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。
Function函数本身。
Number数字值。
Object对象本身。这是默认情况。
String字符串值。
Math 和 Error 对象没有 valueOf 方法。

参考:toString valueOf typeof instanceof 基本类型

使用

object.toString() 判断类型

function getType(obj) {
    const str = Object.prototype.toString.call(obj)
    const map = {
        '[object Boolean]': 'boolean',
        '[object Number]': 'number',
        '[object String]': 'string',
        '[object Function]': 'function',
        '[object Array]': 'array',
        '[object Date]': 'date',
        '[object RegExp]': 'regExp',
        '[object Undefined]': 'undefined',
        '[object Null]': 'null',
        '[object Object]': 'object',
        '[object Map]': 'map',
        '[object Set]': 'set'
    }
    return map[str]
}

function getType(obj) {
    return Object.prototype.toString.call(obj).slice(8, -1).toLowercase()
}

function isType(obj, t) {
    return Object.prototype.toString.call(obj).slice(8, -1).toLowercase() === t.toLowercase()
}

对比 typeof instanceof

typeof

常用来判断基本类型 string/number/boolean/symbol/bigint 以及 function

typeof null === 'object' // JavaScript 诞生以来便如此
typeof返回值
Undefined"undefined"
Null"object"
Boolean"boolean"
Number"number"
BigInt(ECMAScript 2020 新增)"bigint"
String"string"
Symbol (ECMAScript 2015 新增)"symbol"
Function 对象 (按照 ECMA-262 规范实现 [[Call]])"function"
其他任何对象"object"
宿主对象(由 JS 环境提供)取决于具体实现
instanceof

obj instanceof Object

检测构造函数的 prototype 属性是否出现在某个实例对象的原型链

class O {
    constructor() {}
}

class A extends O {}
const a = new A()

a instanceof A // true
a instanceof O // true

instanceof 简易实现

// 原理: a.__proto__(.__proto__....) === A.prototype
function _instanceof(a, A) {
    const F = A.prototype
    let obj = a.__proto__
    
    while(true) {
        if (obj === null) {
            return false
        }
        if (obj === F) {
            return true
        }
        obj = obj.__proto__
    }
}

类型转换-对象转原始类型

对象在转换类型的时候,会调用内置的 [[ToPrimitive]] 函数。

(可以重写 Symbol.toPrimitive ,该方法在转原始类型时调用优先级最高。toPrimitive

对于该函数来说,算法逻辑一般来说如下:

  • 如果已经是原始类型了,那就不需要转换了
  • 调用 object.valueOf(),如果转换为基础类型,就返回转换的值
  • 调用 object.toString(),如果转换为基础类型,就返回转换的值
  • 如果都没有返回原始类型,就会报错
const a = {
  valueOf() {
    return 1
  },
  toString() {
    return '2'
  }
}

+ a // 1
1 + a // 2
1 > a // false
1 == a // true
1 === a // false

扩展: 相等性判断

ES2015中有四种相等算法:

  • 抽象(非严格)相等比较 (==)
  • 严格相等比较 (===): 用于 Array.prototype.indexOf, Array.prototype.lastIndexOf, 和 case-matching
  • 同值零: 用于 %TypedArray% 和 ArrayBuffer 构造函数、以及Map和Set操作, 并将用于 ES2016/ES7 中的String.prototype.includes
  • 同值: 用于所有其他地方

JavaScript提供三种不同的值比较操作:

  • === 严格相等比较
  • == 抽象相等比较
  • Object.is