3.循环、引用值、显示及隐式类型转换
3.1 for循环
3.1.1 for循环的声明格式
for循环的步骤
for(var i = 0; i < 10; i++) {
console.log('to do something');
}
1.声明变量i并且赋值 i = 0;
2.根据条件判断返回相应的boolean值;
3.增加变量i的值
// 相当于
var i = 0;
for(;i<10;) {
console.log('to do something');
i++
}
3.1.2 for循环转化为while循环
var i = 0;
for(;i < 10;) {
console.log('to do something');
i++;
}
// 相当于while循环
var i = 0;
while(i < 10) {
console.log('to do something');
i++;
}
3.1.3 for循环中的判断条件
// 声明i不能等于0,否则下面的for不满足执行条件i == 0返回false;
var i = 1;
for(; i;) { // 判断条件是i,但是判断条件一直满足true,因为i ==1, i==2, i==3 ... i==N返回的boolean值都是true,所以程序是死循环
console.log(i);
i++;
}
// 解决问题
var i = 1;
for(; i;) {
if(i == 11) {
console.log(i);
break;
}
i++;
}
// 如果要求不能用break和continue,也要实现上面的效果,该怎么做呢?
var i = 1;
for(; i;) {
console.log(i);
if(i === 11) {
// 将0赋值给i,停止for循环。因为i在该for循环中也充当着条件判断,如果i == 0,那么返回的boolean值是false,也就终止了for循环。
i = 0;
}
i++;
}
// 不能用return
var i = 1;
for(; i;) {
console.log(i);
i++;
if(i === 11) {
return; // 报错:Uncaught SyntaxError:Illegal return statement(非法返回语句)
}
}
3.1.4 例题
1.从0开始做加法,加到什么时候总和小于100停止?
var sum = 0,
i = 1;
for(; i;) {
sum += i;
i++;
if(sum > 100) {
break;
}
console.log(sum);
}
// 或者
var sum = 0;
for(var i = 0; i < 100; i++) {
sum += i;
if(sum > 100) {
break;
}
console.log(sum);
}
2.100以内的数跳过可以被7整除或个位数是7的数?
for(var i = 0; i < 100;i++) {
// 当前的数模上7余数是0或者当前的数模上10余数是7(也就是说个位是7的数)
if(i % 7 === 0 || i % 10 === 7) {
continue; // 跳出当前循环,然后执行下一次循环
}
console.log(i);
}
3.打印出100以内可以被4,5,6整除的数
for(var i = 0; i < 100; i++) {
// 同时可以被4,5,6整除的数
if(i % 4 === 0 && i % 5=== 0 && i % 6 === 0) {
console.log(i);
}
}
4.打印0-100的数,要求()只能有一句,不能写判断条件,{}不能出现i++,i--;
var i = 100;
for(; i--;) {
// for循环为什么会暂停循环呢?因为i--为0的时候,此时i==0判断条件返回false,所以会停止循环。
console.log(i);
}
5.10的N次方怎么实现?
//10的0次方是1
//10的1次方是10
//10的2此方是100
//10的3次方是10000
var n = 5,
num = 1;
for(var i = 0; i < n; i++) {
num *= 10;
}
console.log(num);
6.实现n的阶乘?
var n = 5,
mul = 1;
for(var i = 1; i <= n; i++) {
mul *= i;
}
console.log(mul);
7.如果var num = 789;请输出结果987;
var num = 789;
var a = num % 10; // 9
var b = ( num - a ) % 100 / 10; // 8
var c = (num - a - b * 10) / 100; // 7
console.log(''+ a + b + c);
8.打印三个数中最大的数字
// 逻辑思路:
// 1. 比较a和b谁大?如果a > b为真执行第2步,如果a > b为假执行第3步。
// 2. 比较a和c的值,如果a > c为真打印出最大值a,如果为假打印出最大值c。
// 3. 比较 b和c的值,如果b > c为真打印出最大值b,如果为假打印出最大值c。
var a = 9,
b = 8,
c = 7;
if (a > b) {
if (a > c) {
console.log(a);
} else {
console.log(c);
}
} else {
if(b > c) {
console.log(b);
} else {
console.log(c);
}
}
9.打印100以内的质数(仅仅能被1和自己本身整除的数),1不是质数;
// 逻辑思路:仅仅能被1和自己本身整除的数,也就是说只能被整除2次;
var count = 0;
// 因为1不是质数,所以从2开始
for(var i = 2; i < 100; i++) {
// 为什么j <= i? i % j == 0,i要被j整除,被除数i要大于除数j,否则就不会被整除了
for(var j = 1; j <= i; j++) {
if( i % j === 0) {
count++;
}
}
if(count == 2) {
console.log(i);
}
// 在下一次外层循环的时候,count必须清除值
count = 0;
}
3.2 do-while循环
- do-while和while循环有什么区别呢?
- do-while无论判断条件是否成立,都将进行一次循环。while判断条件成立后,才会进行循环。
- do-while声明格式
3.3 初识array和object引用值
- 引用值: array object function date RegExp;
- 数组声明格式:
// 数组字面量声明
var arr = [1, 2, 3, 4, 5];
// 数组取值
console.log(arr[1]);
// 数组修改值
arr[1] = '我是修改之后的值';
// 默认属性length
console.log(arr.length);
- 对象声明格式:
// 对象字面量声明
var obj = {
'属性名/键名':'属性值/键值',
name:'小张',
age:18
}
// 对象取值
console.log(obj.name);
// 对象赋值
obj.name = '小王';
3.4 typeof判断类型(重点)
3.4.1 typeof的定义
- typeof()方法是JavaScript内置的方法,返回值是数据类型
- typeof()方法返回值是判断后的数据类型,但是是字符串形式返回的
- 对于object来说,object代表的是具体的对象,而Object代表的是像array/object这样的引用类型
- typeof()方法返回的值有哪些? number string boolean undefined function object
// 问题: 为什么typeof(null)返回的值是object呢?
// 解答: 因为null指代的是空对象的指针和空对象的占位符,在ES6的提案中否决了typeof(null)==null类型的想法,因为是历史遗留问题。
3.4.2 typeof()方法的重点出错题型
// 如果a未被定义的话,将打印什么结果?
typeof(a); // undefined
// 下面打印的结果是什么?a未被定义
console.log(typeof(typeof(a))); // string 为什么返回的是string字符串类型呢?因为typeof(a)返回的数据类型名称,然后再通过typeof()对数据名称进行数据类型判断,任何数据类型名称利用typeof()进行判断返回的都是string字符串类型。
// 基本的typeof数据类型判断
typeof(123); // number --> 是字符串类型的 -->string
typeof('123'); // string
typeof(true); // boolean
typeof(null); // object
typeof(undefined); // undefined
typeof(function(){}); // function
typeof({}); // object
typeof(NaN); // number
3.5 显示类型转换和隐式类型转换(重重点)
3.5.1 显示类型转换:
1.Number类型
//Number类型直接将参数转化为数字类型,如果不能转化则返回NaN
typeof(Number(123)); // 123 number
typeof(Number('123')); // 123 number
typeof(Number(true)); // 1 number
typeof(Number('true')); // NaN number
typeof(Number(null)); // 0 number
typeof(Number(undefined)); // NaN number
typeof(Number('1a')); // NaN number
typeof(Number('3.14')); // 3.14 number
typeof(Number('')); // 0 number
typeof(Number(' ')); // 0 number
typeof(Number(-0)); // -0 number
typeof(Number(-1)); // -1 number
2.parseInt()方法
- parseInt(参数1string,参数2):
参数1: 需要转化的数据,
参数2: radix 基底, 将传入的数据转化为radix进制的数
- par seInt函数将其第一个参数转换为一个字符串(使用toString()方法),对该字符串进行解析,然后返回一个整数或NaN。
- 参数1字符串开头的空白符将会被忽略。
- parseInt不能解析Infinity/-Infinity,返回NaN。
// parsetInt();方法是直接将数据转化为整型数据,不通过Number类型进行转化。
typeof(parseInt('123')); // 123 number
typeof(parseInt(true)); // NaN number --> 这就说明parseInt是直接转化数据为整型数据,和Number类型转换没关系。
typeof(parseInt(null)); // NaN number
typeof(parseInt(undefined)); // NaN number
typeof(parseInt(NaN)); // NaN number
// 对参数1进行toString()转化
parseInt({ toString: function() { return "3.14" } }); // 3 number;
// -0 和 +0的问题,为什么都是0呢?因为参数1会转换成字符串利用toString()的方法,new Number(+0/-0).toString();返回的都是0
parseInt(-0); // 0
parseInt(+0); // 0
// 下面两个例子说明,parseInt()没有四舍五入的功能,只会舍去小数点后面的数据。
typeof(parseInt('3.1459')); // 3 number
typeof(parseInt('3.859')); // 3 number
// 参数2:radix基底
// 下面例子是什么意思呢?
// 输出通过16进制转换数字10,然后用十进制表示的值
console.log(parseInt(10,16)); // 16
console.log(parseInt('b',16)); // 11
console.log(parseInt('z',16)); // NaN
// 二进制
console.log(parseInt('b',2); // NaN
console.log(parseInt('11010',2)); // 26 --> 逢2进1, 2^1+2^3+2^4 = 26;
// 16进制用: 0 1 2 3 4 5 6 7 8 9 a b c d e f表示,每逢16进1位;
// 2进制: 0 1表示,每逢2进1;
// 9进制: 0 1 2 3 4 5 6 7 8 9表示,每逢10进1;
3.parseFloat()方法
- parseFloat(参数):
参数1:需要转换的数据
- par seFloat函数将其第一个参数转换为一个字符串(使用toString),对该字符串进行解析,返回浮点数或NaN;
- parseFloat函数可以解析Infinity或者-Infinity;
- 参数1字符串开头的空白符将会被忽略。
// 直接转换为浮点类型,不会通过Number类型进行转换
parseFloat(3.1415926); // 3.1415926 number
// parseFloat能够解析Infinity/-Infinity
parseFloat(Infinity); // Infinity number
// 对参数进行字符串转化,toString()方法
parseFloat({ toString: function() { return "3.14" } }); // 3.14 number
4.toFixed()方法
- toFixed(参数)
参数是保留小数点后数字个数;介于[0-20]之间,不传参数默认0;
- 会进行对数据的四舍五入
var num = parseFloat('3.1415926');
var num2 = parseFloat('3.146');
console.log(num.toFixed(2)); // 3.14
console.log(num2.toFixed(2)); // 3.15
- toFixed()参数过大会产生大数危机和浮点数精度的问题,196P
5.String类型和toString()方法
// String将数据直接转化为字符串类型
String(123); // 123 string
String('123'); // 123 string
String(NaN); // NaN string
String(null); // null string
String(true); // true string
\
- toString() 方法返回指定对象的字符串形式。
// str.toString();
// null和undefined没有toString()方法,具体原因学到包装类就会知道。
**undefined 和 null 只有原始值 不可以有属性和方法 不会产生包装类**\
**undefined/null 是一个原始值 不是对象 就没有原型 就调用不到Object.prototype(原型链最终原型)的 toString 方法**
6.Boolean类型
- Boolean判断为false的值: undefined null false '' NaN 0
// 除了undefined null false ''(空字符串) NaN 0 其它的值都为true
Boolean(undefined); // false
Boolean(null); // false
Boolean(false); // false
Boolean(''); // false
Boolean(' '); // true -->有空格
Boolean(NaN); // false
Boolean(0); // false
3.5.2 隐式类型转换(很重要important)
1.Number隐式转换
var a = '12a'; // Number('12a'); ---> NaN
a++; // 当系统检测到++运算后,会自动将a隐式转换为number类型,然后再进行运算
console.log(a); // NaN
var a = '12'; // Number('12');---> 12
a++; // a = 12 + 1;
console.log(a); // 13
// Number('3');---> 3 * 2
var a = '3' * 2; // (* / - %) 如果遇到这些运算符,其中有一个是数字,那么就会把字符串转为number类型
console.log(a); // 6
// 在判断比较运算符的情况下,如果有数字类型,就会将另一数据类型转为Number类型在做比较。
var a = '1' > 2; // false
var b = 1 > '2'; // false
var c = null < 3; // true
var a = 2 > 1 > 3;
// 运算步骤:
// 1. 2 > 1 返回true
// 2. 隐式转换Number(true);--> 1 > 3
// 3. 返回false
var a = 2 > 1 == 1;
// 运算步骤:
// 1. 2 > 1 返回true
// 2. 隐式转换Number(true);--> 1 == 1
// 3. 返回true
2.String隐式转换
// 字符串遇见 + 运算符,会当作字符串拼接
var a = '1' + 2; // String(2); '1'+'2' = 12 string
console.log(a); // 12 string
// 两个字符串之间的比较,比较的是ASCII码表上的值
var d = 'a' > 'b'; // false
// 因为字符串'a'在ASCII码对应97,'b'是98
3. ==和!=隐式转换, ===不进行隐式转换
// ==和!=如果存在数字类型,将另一数据类型转换成数字类型(除undefined/null),然后再对比
var a = 1 == '1'; // true --> Number('1'); 1
var a = 1 != '2'; // true
var a = 1 === '1'; // false 全等不进行转换
var name = '';
if(!name) { // 隐式转换,将字符串隐式转换成boolean类型,然后再去做非(!)运算 Boolean(name)-->Boolean('')-->false-->!false--->true
console.log('没姓名');
} else {
console.log('名字:' + name);
}
4. NaN和undefined和null
// NaN不等于包括自身的任何值
NaN == NaN; // false
//undefined 和 null,说明undefined和null在做==运算的时候,二者不与任何数据类型进行操作运算。
var a = undefined > 0; // false
var a = undefined < 0; // false
var a = undefined = 0; // false
var b = null > 0; // false;
var b = null < 0; // false;
var b = null == 0; // false;
// 比较独特的两个比较
var c = null == undefined; // true
var d = null === undefined; // false;
5. +(正) -(负) 运算符也会隐式转换
// 隐式转换为数字类型
var num = '123';
console.log(+num); // +123
console.log(-num); // -123
console.log(typeof(-num)); // number
6. isNaN方法()
- 运算逻辑:先通过Number()隐式转换,然后再通过isNaN()方法进行判断。Number(值)-->isNaN(值)-->Boolean值
console.log(isNaN('str')); // true
console.log(isNaN(undefined)); // true
console.log(isNaN(null)); // false
console.log(isNaN('12a')); // true
console.log(isNaN(a)); // Uncaught SyntaxError: Invalid or unexpected token 报错,因为a未被定义
console.log(isNaN(NaN)); // true
// 问题:
// 因为NaN == NaN == false,那么isNaN()方法是怎么判断出,NaN等于NaN的呢?
// (这个利用NaN永不填充)填充于自身;
var isNaN = function(value) {
var n = Number(value);
return n !== n; //NaN !== NaN true
};
// 另一种写法
function isNaN(num) {
var res = Number(num) + '';
if(res == 'NaN') {
return true;
} else {
return false;
}
}
3.5.3 隐式转换面试题
var a = false + 1; --> Number(false); --> 0 + 1 = 1;
console.log(a); // 1
var b = false == 1; Number(false);--> 0 == 1 --> false
console.log(b); // false
// 1. typeof(a);--> 'undefined';
// 2. (-true);--> Number(true); 1 --> number
// 3. (+undefined);--> Number(undefined); NaN --> number
// 4. 1 + NaN + '' --> NaN + '' --> 'NaN'
// 5. 'undefined' && 'NaN' --> 'NaN' --> Boolean('NaN') --> true
if (typeof(a) && (-true) + (+undefined) + '' ) {
console.log('通过了');
} else {
console.log('未通过');
}
// 1. 1 + 5 * '3' -->
// 2. 5 * Number('3') -->
// 3. 15 + 1 -->
// 4. 16 === 16 ---> true
if(1 + 5 * '3' === 16) {
console.log('通过');
} else {
console.log('未通过');
}
// 1. !!' ' --> Boolean(' ');--> true --> !true --> false--> !false --> true
// 2. !!'' --> Boolean(''); --> false --> !false --> true --> !true --> false
// 3. !!false --> !false --> true --> !true --> false
// 4. true + false - false || '未通过'
// 5. Number(true) + Number(false) -Number(false) || '未通过'
// 6. 1 + 0 - 0 || '未通过'--> 1
console.log(!!' ' + !!'' - !!false || '未通过' );
- 利用for循环,打印出斐波那契数列的第N项
// 因为斐波那契数列的第1位和第2位都是1,所以for循环从第2位开始
// 从第2位开始,也就是相当于每次循环将n3向后移动一位,然后重新赋值n1,n2的值
1 1 2 3 5 8 13 21
n1 n2 n3 n4 n5 n6 n7 n8;
n1 n2 n3 n4 n5 n6 n7 n8;
n1 n2 n3 n4 n5 n6 n7 n8;
var n = parseInt(window.prompt('N=?'));
var n1 = 1,
n2 = 1,
n3;
if(n <= 0) {
console.log('输入错误');
} else {
if(n <= 2) {
n3 = 1;
console.log(n3);
} else {
// 因为是从第二位开始,所以只能小于,不能等于。假设n = 5,那么n3只需要循环三次即可求到第三次的值
for(var i = 2; i < n; i++) {
n3 = n1 + n2;
// 从新赋值n1和n2;
n1 = n2;
n2 = n3;
}
console.log(n3);
}
}