类型转化,暂时性死区

171 阅读5分钟

var let const的区别

  1. var是挂载在window上的,但是let和const并没有
  2. let和const有块的概念,不可以跨块访问,var可以跨块访问
  3. 都不可以跨函数访问
  4. const在定义之后不可以再被修改

暂时性死区

ES6规定,let/const命令会使区域形成封闭作用域,在声明之前使用该变量,会报错,被称为暂时性死区

valueOf和toString方法

Object.prototype.valueOf()

用MDN的话来说,valueOf()方法返回指定对象的原始值。

JS调用valueOf方法用来把对象转换为原始类型的值(数值,字符串和布尔值)。但是我们很少需要自己调用此函数,valueOf方法一般都会被JavaScript自动调用

Object.prototype.toString()

toString()方法返回一个表示该对象的字符串 每个对象都有toString方法,当对象被表示为文本值时或者以期望字符串的方法引用对象时,该方法被自动调用

原始类型

好,铺垫一下,先了解下 javascript 的几种原始类型,除去 Object 和 Symbol,有如下几种原始类型:

  • Number
  • String
  • Boolean
  • Undefined
  • Null 在 JavaScript 进行对比或者各种运算的时候会把对象转换成这些类型,从而进行后续的操作,下面逐一说明:

String类型转换

在某个操作或者运算需要字符串而该对象又不是字符串的时候,会触发该对象的String转换,会将非字符串的类型自动转为String类型,系统内部会自动调用toString函数

var obj = {name: 'Coco'};
var str = '123' + obj;
console.log(str);  // 123[object Object]

//等价于
var obj = {name: 'Coco'};
var str = '123' + obj.toString();

转换规则:

  1. 如果toString方法存在并且返回原始类型,返回toString的结果。
  2. 如果toString方法不存在或者返回的不是原始类型,调用valueOf方法,如果valueOf方法存在,并且返回原始类型数据,返回valueOf的结果 3.其他情况,抛出错误

number类型转换

上面描述的是 String 类型的转换,很多时候也会发生 Number 类型的转换:

调用 Number() 函数,强制进行 Number 类型转换

调用 Math.sqrt() 这类参数需要 Number 类型的方法

  • obj == 1 ,进行对比的时候
  • obj + 1 , 进行运算的时候 与 String 类型转换相似,但是 Number 类型刚好反过来,先查询自身的 valueOf 方法,再查询自己 toString 方法:

如果 valueOf 存在,且返回原始类型数据,返回 valueOf 的结果。 如果 toString 存在,且返回原始类型数据,返回 toString 的结果。 其他情况,抛出错误。

对象转原始类型

对象在转换类型的时候,会调用内置ToPrimitive函数,对于该函数,算法逻辑一般来说如下:

  • 如果input是原始值,直接返回这个值
  • 否则,如果input是对象,调用input.valueOf(),如果结果是原始值,返回结果
  • 否则,调用input.toString()。如果结果是原始值,返回结果
  • 否则,抛出错误

布尔转换

什么时候会进行布尔转换呢:

布尔比较时 if(obj) , while(obj) 等判断时 简单来说,除了下述 6 个值转换结果为 false,其他全部为 true:

  • undefined
  • null
  • -0
  • 0或+0
  • NaN
  • ''(空字符串)

function转换

我们定义一个函数如下:

function test() {
    var a = 1;
    console.log(1);
}

如果我们仅仅是调用test而不是test(),看看会发生什么? 可以看到,我们把我们定义的test函数重新打印了一半,其实,这里自行调用了函数的valueOf方法: 我们改写一个test函数的valueOf方法

test.valueOf = function() {
    console.log('调用 valueOf 方法');
    return 2;
}
 
test;
// 输出如下:
// 调用 valueOf 方法
// 2

与number转换类似,如果函数的valueOf方法返回的不是一个原始类型,会继续找到它的toString方法

test.valueOf = function() {
    console.log('调用 valueOf 方法');
    return {};
}
 
test.toString= function() {
    console.log('调用 toString 方法');
    return 3;
}
 
test;
// 输出如下:
// 调用 valueOf 方法
// 调用 toString 方法
// 3

解决面试题

//add(1) // 1
//add(1,2)(3) //6
//add(1)(2)(3)(4)(5) // 15
function add () {
    var args = Array.prototype.slice.call(arguments);
 
    var fn = function () {
        var arg_fn = Array.prototype.slice.call(arguments);
        return add.apply(null, args.concat(arg_fn));
    }
 
    fn.valueOf = function () {
        return args.reduce(function(a, b) {
            return a + b;
        })
    }
 
    return fn;
}

加法运算规则

加法运算规则很简单,只会触发两种情况

  1. 两个操作符都是数值,就执行常规的加法运算,

  2. 其中一个操作数是字符串 (1)两个操作数都是字符串,就把两个拼接起来

(2)其中一个是字符串,那么九江另一个操作数转换为字符串,然后拼接

  1. 有一个操作数是对象,数值,或者布尔值,就调用他们的toString()转化为字符串,而对于undeifined和null就调用Sting()函数

{}+[]是一个特殊情况: 在js中{}代表复合语句,在js中会将开头的{}堪称一个代码块,而不是一个Object(在es6以前只有函数作用域与全局作用域,还没有块级作用域)而这里的{}只能是空符号,不表明任何意思。这里的+[]是一个隐式转换,所以参与运算的只有+[],在这里将[]转换成了number类型,所以得出结果为0。

  • {} + [] =0
  • [] + 0 = "0"
  • {} + 0 = 0
  • ({} + []) =[object Object]

比较运算符

  1. 如果是对象,就通过toPrimitive转化对象
  2. 如果是字符串,就通过unicode字符索引来比较

==的比较规则

  1. 比较undefined和null,返回true
  2. boolean,number,string之间比较都转化为number进行比较
  3. 其中一方为object,将object转化为原始值进行判断