JS 类型转换
1. if 的判断
if(xxx){
}
JS 是如何处理的?
解密:对于括号里的表达式,会被强制转换为布尔类型。
原理:
类型 | 结果 |
---|---|
Undefined | false |
Null | false |
Boolean | 直接判断 |
Number | +0,-0,或者 NaN 为 false,其他为 true |
String | 空字符串为 false,其他都为 true |
Object | true |
结果为 true 的只有:
1. Object
2. 除空字符串以外的 String
3. 除 +0,-0 和 NaN 以外的 Number
结果为 false 的:undefined、null、boolean 直接判断、+0,-0 或者 NaN、空字符串。
空字符串为 false,空白字符串为 true。
2. == 的判断
对于==的判断,js是怎么处理的?
解密:
x | y | 结果 |
---|---|---|
null | undefined | true |
Number | String | x == toNumber(y) |
Boolean | (any) | toNumber(x) == y |
Object | String or Number | toPrimitive(x) == y |
String | 空字符串为 false,其他都为 true | false |
otherwise | otherwise | false |
toNumber:
type | Result |
---|---|
Undefined | NaN |
Null | 0 |
Boolean | true --> 1,false --> 0 |
String | "abc" --> NaN,"123" --> 123 |
toPrimitive:
对于 Object 类型,先尝试调用 .valueOf 方法获取结果。 如果没定义,再尝试调用 .toString方法获取结果
流程控制语句
关键的三个:swich、for、while
###1. if
if 语句是编程语言最常用的语句,语法:
if(condition){
//true statement
}else {
//false statement
}
其中 condition
可以是任意表达式,结果不一定是布尔值,JavaScript 解释器会自动调用 Boolean() 将表达式结果转为布尔值。如果表达式为真,执行第一个代码块内语句;如果为假,执行第二个代码块内语句。
只有一条语句的时候代码块不是必需的,出于维护性考虑我们建议添加
if 语句可以单独使用,也可以和多个else连续使用:
if(a > 2){
// statement
}
if( a == 1){
}else if(a == 2){
}else if(a == 3 ){
}else{
}
2. label
label语句是很多熟练的jser都会忽略的知识,我们可以为代码添加标签,方便后续使用,语法:
labelname: statement;
label语句单独使用的时候没有什么作用几乎,经常和其它语句结合使用,但是一些面试题会针对这个提问
var a = 1,
b = 2,
c = 3,
d = 4,
e = 5,
f = 6;
a:b:c:d:e:f:7;
3. swich
switch 语句和if语句关系密切,语法:
case value1:
statement;
break;
case value2:
statement;
break;
case value3:
statement;
break;
default:
statement;
}
我们可以看到if语句使用多个else的时候写法很繁琐,可读性也下降,switch语句可以轻松解决:
switch(a){
case 1:
statement;
break;
case 2:
statement;
break;
case 3:
statement;
break;
default:
statement;
}
如果表达式等于 case 的值,对应的语句就会执行,break 关键字会使程序跳出 switch 语句,很多编程规范强调必须添加 break,不添加不会有语法错误,程序会多次判断 case,进入相应流程。
没有一个值符合case,流程进入 default 子句,很多规范也强调必须添加default部分
JavaScript switch语句虽然参考的C语言的写法,但有特殊性:
1. switch 和 case 可以使用任意表达式,不一定是常量
2. switch 语句进行比较的时候是全等于(===)操作,不会发生类型转换
4. while 和 do-while
while
while 语句属于前测试循环语句,也就是在循环体内的代码被执行之前,就会对条件求值,不符合的话就不会执行(先判断,符合条件再执行,不符合条件不执行):
while(expression){
statement;
}
例子:
var i = 10;
while(i > 0){
console.log(i);
i--;
}
do-while
do-while 是后测试循环语句,在出口条件判断之前就会执行一次代码(先执行,然后再根据条件判断,符合条件继续执行):
do{
statement;
}while(expression);
例子:
var i = 4;
do{
console.log(i);
i--;
}while(i > 5);
5. for
for语句也是前测试循环语句,但具备在执行循环代码以前初始化变量和定义循环后要执行代码的能力,改造一下 while 语句(即可以和 while 进行相互的改造):
for(var i = 10; i > 0; i--){
console.log(i);
}
6. for-in
for-in 是一种迭代语句,用于枚举对象的属性:
for(property in object){
statement
}
例子:
for(var prop in window){
console.log(prop);
}
因为 ECMAScript 规定对象中的属性没有顺序,所以 for-in 遍历出来的属性的顺序也不是固定的(虽然大部分浏览器是按属性名称排序,我们不能依赖这个)
7. break 和 continue
break 关键字在 switch 语句中已经见过,这两个关键字多用在循环语句中:
break 用于强制退出循环体,执行循环后面的语句
continue 用于退出本次循环,执行下次循环
例子:
for(var i = 1; i< 10; i++){
if(i % 4 === 0){
break;
}
console.log(i);
}
for(var i = 1; i< 10; i++){
if(i % 4 === 0){
continue;
}
console.log(i);
}
这是 break 和 continue 最常规的用法,其实这两个关键字后面可以跟上我们之前提到的label,退出指定位置的代码,对于多层循环是个有用的技巧,但是难以理解,一般不推荐使用(如同C语言中被误解的goto)
8. with
with语句同样很少用到,作用是把代码的作用域设置到一个特定对象里,由于其带来性能的严重副作用和可读性的困难,几乎不被使用:
with(location){
console.log(hostname);
console.log(href);
}
函数和作用域
JavaScript 函数是指一个特定代码块,可能包含多条语句,可以通过名字来供其它语句调用以执行函数包含的代码语句。
比如我们有一个特定的功能需要三条语句实现:
statement1;
statement2;
statement3;
那么每次想实现这个功能的时候就需要写这三句话,很麻烦,我们可以把这三条语句打包为一个函数:
// 函数的声明
function doSomething(){
statement1;
statement2;
statement3;
}
这样每次想实现功能的时候我们就调用一下函数就可以了,调用函数通过 函数名称() 的形式调用:
// 函数的调用
doSomething();
1. 声明函数
- 函数声明
function printName(){
console.log('Aman')
}
printName()
- 函数表达式
var printName = function(){
console.log('Aman')
}
printName()
- 参数
function printName(name){
console.log(name)
}
printName('hunger')
printName('valley)
其中的 name 就是参数,即变量名。
函数在定义的时候可以写多个参数 :
function printPersonInfo(name, age, sex){
console.log(name)
console.log(age)
console.log(sex)
}
多个参数在函数调用时,也会一一对应。
- arguments
在函数内部,你可以使用 arguments 对象获取到该函数的所有传入参数:
function printPersonInfo(name, age, sex){
console.log(name)
console.log(age)
console.log(sex)
console.log(arguments)
console.log(arguments[0])
console.log(arguments.length)
console.log(arguments[1] === age)
}
printPersonInfo('Aman', 25, 'female')
3. 重载
重载是很多面向对象语言实现多态的手段之一,在静态语言中确定一个函数的手段是靠方法签名——函数名+参数列表,也就是说相同名字的函数参数个数不同或者顺序不同都被认为是不同的函数,称为函数重载。
在 JavaScript 中没有函数重载的概念,函数通过名字确定唯一性,参数不同也被认为是相同的函数,后面的覆盖前面的,这是不是意味着 JavaScript 不能通过重载功能实现一个函数,参数不同功能不同呢?
在 JavaScript 中,函数调用没必要把所有参数都传入,只要你函数体内做好处理就行,但前提是传的参数永远被当做前几个:
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
printPeopleInfo('hunger', 3);
printPeopleInfo('hunger', 3, 'male');
4. 返回值
有时候我们希望在函数执行后给我们一个反馈,就像表达式一样,给我们个结果,我们可以通过 return 来实现:
function fn(a, b){
a++;
b++;
return a + b;
}
var result = fn(2, 3);
console.log(result);
这样我们就能拿到函数希望给我的反馈了,调用 return 后,函数立即中断并返回结果,即使后面还有语句也不再执行。
其实我们不写return语句,函数也会默认给我们返回undefined。
5. 声明提前
- 变量的声明前置
console.log(a)
var a = 1
执行时实际为:
var a
console.log(a)
a = 1
此时输出为 undefined
需要再次 console.log(a) ,才会输出为 1 。即:
var a
console.log(a)
a = 1
console.log(a)
// 此时 console.log(a) 输出为 1
-
函数的声明前置
和变量的声明会前置一样,函数声明同样会前置,如果我们使用函数表达式,那么规则和变量一样:
console.log(fn) //undefined
var fn = function(){}
如果我们使用函数声明的方式,那么即使函数写在最后也可以在前面语句调用:
fn() // "1"
function fn(){
console.log('1')
}
立刻执行的函数表达式
(function(){
console.log('Aman')
})()
即,(function(){console.log('Aman')})浏览器认为它是一个表达式,这个表达式的结果是一个值,这个值是一个引用类型的函数,这个时候后面就可以加 ()。
6. 命名冲突
当在同一个作用域内定义了名字相同的变量和方法的话,会根据前置顺序产生覆盖:
var fn = 3;
function fn(){}
console.log(fn); // 3
相当于:
var fn
function fn(){} //覆盖上面的
fn = 3 //重新赋值
console.log(fn)
当函数执行有命名冲突的时候,可以认为在还是内部一开始有隐藏的声明变量这个操作:
function fn(fn){
console.log(fn);
var fn = 3;
console.log(fn);
}
fn(10) //10 3
执行时等价于:
function fn(){
var fn fn = 10 console.log(fn);
fn = 3
console.log(fn);
}
但已经声明过一次已经有值的,再次声明也不会变,即声明不会被再次声明覆盖:
console.log(fn);
function fn(){ }
var fn = 3
实际运行为:
function fn(){ }
var fn
console.log(fn);
fn = 3
// 所以 console.log(fn) 就是一个函数
7. 递归
简单来说就是自己调用自己,递归需要设置结束条件:
function factorial(n){
if(n === 1){
return 1
}
return n * factorial(n-1)
}
factorial(3) //6
算法简单,逻辑清晰,但效率低。
8. 作用域
在大多数语言中都是用花括号 {} 来形成一个作用域,俗称块作用域,C 语言例子:
{
int a = 2;
}
a++; //报错,a不存在
这也是我们大多数人能接受的理解方式,但在 JavaScript 中 {} 并没有带来块作用域,JavaScript 的作用域是靠函数来形成,也就是说一个函数内定义的变量,函数外不可以访问:
function fn(){
var a = 1;
if(a > 2){
var b = 3;
}
console.log(b);
}
fn(); // undefined
console.log(a); // "ReferenceError: a is not defined
- var
在声明变量的时候需要 var,这样声明的变量作用域才符合我们上面提到的规则,那么不写 var 会怎么样呢:
function fn(){
a = 1;
}
fn();
console.log(a); // 1
可以看到不写 var, 会声明一个全局的变量,这是我们在编程中应该要避免,即使真的需要全局变量,也应该在最外层作用域使用 var 声明。
网友评论