var let const的区别
- var是挂载在window上的,但是let和const并没有
- let和const有块的概念,不可以跨块访问,var可以跨块访问
- 都不可以跨函数访问
- 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();
转换规则:
- 如果toString方法存在并且返回原始类型,返回toString的结果。
- 如果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)其中一个是字符串,那么九江另一个操作数转换为字符串,然后拼接
- 有一个操作数是对象,数值,或者布尔值,就调用他们的toString()转化为字符串,而对于undeifined和null就调用Sting()函数
{}+[]是一个特殊情况: 在js中{}代表复合语句,在js中会将开头的{}堪称一个代码块,而不是一个Object(在es6以前只有函数作用域与全局作用域,还没有块级作用域)而这里的{}只能是空符号,不表明任何意思。这里的+[]是一个隐式转换,所以参与运算的只有+[],在这里将[]转换成了number类型,所以得出结果为0。
- {} + [] =0
- [] + 0 = "0"
- {} + 0 = 0
- ({} + []) =[object Object]
比较运算符
- 如果是对象,就通过toPrimitive转化对象
- 如果是字符串,就通过unicode字符索引来比较
==的比较规则
- 比较undefined和null,返回true
- boolean,number,string之间比较都转化为number进行比较
- 其中一方为object,将object转化为原始值进行判断