2.3.5 条件语句
==和!=会进行隐式强制类型转化
===和!===则不会进行隐式强制类型转化
var number = 100; if(number % 2 == 0) { alert("是偶数"); } else { alert("是奇数"); }
if(10 == "10") { alert("相等"); } else { alert("不相等"); }
if(10 === "10") { alert("相等"); } else { alert("不相等"); }
一个简单的代码:
用户输入一个数,判断奇偶数
根据刚才的数据类型分析,你注意到了,我们在输入数据的时候,它怎么知道我是字符串呢,还是数字呢,虽然都是var类型
我不想记,我自主强制类型转化,这样靠谱点,这样严谨点就舒服了
输入的时候默认是string
运算的时候帮你转化(什么时候转化呢?),俺也不知道
一些会不会帮你转化呢,不知道~
var number = prompt("请输入一个数字:"); if(parseInt(number) % 2 == 0) { alert("偶数"); }else { alert("奇数"); }
三元表达式也是可以用的
var number = parseInt(prompt("请输入年份:")); alert( number % 400 == 0 || (number % 100 != 0 && number % 4 == 0) ? "是" : "不是" );
2.3.6 switch语句
与java等语言不同的是,这里变量就只有var类型,所以就有以下操作
switch不支持类型转化:
所以switch里写不同基本数据类型的值,没必要
var number = prompt("请输入:"); switch (number) { case 1: alert('整数1'); break; case "2": alert('字符串2'); break; case undefined: alert("未定义类型"); break; case null: alert(null); break; case true: alert(true); break; case 1.5: alert("小数1.5"); break; default: alert("你输入的是个啥?"); break; }
2.3.7 循环语句
js支持while,do while,for三种循环
很类似,不多讲
for循环有点特点:
var sum = 0; for(var i = 0; i < 10; i++) { sum += i; } alert(sum);
这是个常规写法
在mdn中有很丰富的例子:[for](for - JavaScript | MDN (mozilla.org))
随后讲解了数组,讲一讲for of的写法
2.3.8 数组
没错,数组的类型还是var,只是内部类型是数组
没错,数组元素的类型还是var,所以各个元素的内部类型可能不同
创建方法:
var arr1 = new Array();//大写A
//通过new关键字构造
var arr2 = [];//空数组
var arr3 = [1, 'a', 1.5, true, undefined, null];
此时变量即有个属性length,代表数组的长度
var arr1 = new Array(); var arr2 = []; var arr3 = [1, 'a', 1.5, true, undefined, null]; arr1.push(1); arr2.push("2"); arr3.push(3.0); alert(arr1.length + " " + arr2.length + " " + arr3.length);
数组增加元素和删除元素用的是push和pop
跟栈是一样的
跟java的Vector差不多,还可以indexof等等操作,不细讲了
四种遍历数组的方式:
for循环,通过次数
下标访问依旧是arr[i]
修改操作就是下标访问赋值即可~
赋值是不会影响数组大小的
var arr = [1, 'a', 1.5, true, undefined, null]; for(var i = 0; i < arr.length; i++) { console.log(arr[i] + " \n"); }
while循环出栈
var arr = [1, 'a', 1.5, true, undefined, null]; while(arr.length > 0) { console.log(arr.pop()); }
for of 循环
类似于java的foreach,Java是int x : arr
var arr = [1, 'a', 1.5, true, undefined, null]; for(var x of arr) { console.log(x); }
while循环出队列
shift就是poll方法 var arr = [1, 'a', 1.5, true, undefined, null]; while(arr.length != 0) { console.log(arr.shift()); }
值得注意的是,数组越界的话,不会有事,因为那个未定义值,就是undefined呗~
var arr = [1, 'a', 1.5, true, undefined, null];
alert(arr[-100] + " " + arr[100]);
数组的打印,数组是有自己的toString方法的,所以可以直接被log
var arr = [1, 'a', 1.5, true, undefined, null];
console.log(arr);
数组的删除,除了pop和shift外,还可以通过splice方法指定下标删除
第一个参数为要删除的起始元素的下标
第一个参数为删除的元素个数
var arr = [1, 'a', 1.5, true, undefined, null];
arr.splice(1, 2);
for(var x of arr) {
console.log(x);
}
数组的排序sort:
内部什么规则,不需要懂
一般我们也不会让不同类型的在一个数组里
数组的截取slice:
一样的,2是from,5是to,[2, 5) 的区域
以返回值的形式返回截取部分,不影响原本数组
并且与java不同的是,截取后的子数组,并不是与原数组共享内存空间的
var arr = [1, 'a', 1.5, true, undefined, null]; var array = arr.slice(2, 5); array[0] = 2.0; console.log(arr); console.log(array);
更多详细内容,可以研究mdn:Array - JavaScript | MDN (mozilla.org)
2.3.9 函数
语法:
形参列表不需要规定类型,因为他们都是var类型,返回值也是var,只需要function关键字去创建函数即可
不支持重载,因为js里面最让我震惊的就是,无论你调用的时候多少个实参,无论多了还是少了甚至不传,都不会出错
少了我就undefined,多了我就忽略
因为列表都是var,那么重载的方式就只能更改传入的参数个数了,但是js这一点奇葩,直接回绝了重载这一种机制
//函数定义/函数声明
function 函数名(形参列表) {
函数体
return 返回值;
}
//函数调用
函数名(实参列表); //无返回值,也可以说返回了无定义类型undefined
变量 = 函数名(实参列表) // 有返回值
函数定义的位置随意,在整个js代码块里,都可以使用这个函数
你可以理解为,整个js代码甚至整个html代码,最先执行的就是函数的声明
所以,行内式也能调用函数
var year = prompt("请输入年份:"); var flag = judge(parseInt(year)); alert(flag); function judge(year) { return year % 400 == 0 || (year % 100 != 0 && year % 4 == 0); }
获取参数列表:
在函数中,隐藏了一个属性,就是参数列表数组:arguments
function printArguments(name1, name2) { for(var x of arguments) { console.log(x); } } printArguments(1, 2);
数组的大小就是传入形参的个数,而刚刚我也提到了,多传少传,都不会报错,那么就有以下操作:
function printArguments(name1, name2) { for(var x of arguments) { console.log(x); } } printArguments(1);
function printArguments(name1, name2) { console.log(arguments.length); for(var x of arguments) { console.log(x); } } printArguments(1, 2, 3);
这个形参形同虚设,你甚至定义的时候干脆不写形参了(逃过起名危机),通过这个数组下标访问参数就行了
是不是很随意,很佛系O(∩_∩)O哈哈~
这有点像java的一个语法:
public static void method(int... arr) {
//arr数组的元素个数,由传过来个整形个数决定
}
不安全,官方建议不适用的方法:eval方法,这个方法可以通过方法名调用方法
跟java中的unsafe类里的东西一样,使用起来危险,需要通过反射获取
function printArguments(name1, name2) { console.log(arguments.length); for(var x of arguments) { console.log(x); } } // printArguments(1, 2, 3); var name = prompt("函数名:"); var numb1 = prompt("参数1:"); var numb2 = prompt("参数2:"); var numb3 = prompt("参数3:"); eval(name + "(" + numb1 + "," + numb2 + "," + numb3 + ")");
官方是这么说的
而我们在控制台写js代码,底层原理就是用了eval,让代码生效的
2.3.10 作用域
有了函数之后,就有作用域的说法了,作用域的划分跟java和c类似,{}内部是一个局部
var num = 10; console.log(num); function test1() { var num = 20; console.log(num); } function test2() { num = 30; console.log(num); } test1(); test2(); console.log(num);
var num = 10; console.log(num); function test1() { var num1 = 20; console.log(num1); } function test2() { console.log(num1); } test1(); test2(); console.log(num);
但是,如果test2改成这样:
var num = 10; console.log(num); function test1() { var num1 = 20; console.log(num1); } function test2() { num1 = 20; console.log(num1); } test1(); test2(); console.log(num); console.log(num1);
乐,自动创建一个全局变量了~
所以,js的代码规则很杂,你写错了,会有点惊喜或者惊吓给你
但是,主要你老老实实写代码,不就好了吗~
函数以外的区域是全局区域,他们也有{},也有局域
if(1 < 2) { //无论进没进去,a都是可以打印出来的,只不过是undefined还是20的区别 var a = 20; } alert(a);
与函数不同的是
函数内var或者let,在函数内是局部的
var的作用域是在函数这个“小全局”“小整体”
let是对应的{}内
而在函数外面的代码,var创建后,即使他在局部范围内,也是全局的,而let则严格是局部的
function f() { if (1 < 2) { let a = 20; } alert(a); } f(); if (1 < 2) { let a = 20; } alert(a);
function f() { if (1 < 2) { var a = 20; } alert(a); } f(); if (1 < 2) { var a = 20; } alert(a);
if (1 > 2) {
var a = 20;
}
alert(a);
if (1 > 2) {
let a = 20;
}
alert(a);
好好写代码,别玩太花!
2.3.11 对象
用字面量创建对象(常用)
var a = {}; //空对象,这个对象里啥也没有 var student = { name: '小马',//逗号分割 height: 198, //没有必要写类型,因为都是var weight: 170, sayHello: function() { console.log("hello"); } }; console.log(a); console.log(student);
对象属性方法的访问与修改:
对于属性,可以“ . 属性名 ”去访问和修改,也可以“ [‘属性名’] ”去访问和修改
对于方法,就只能“ .函数名 ”去访问和修改,也可以“ ['函数名']() ”去访问和修改
没错,是可以修改
你可以将其看成属性,也是var类型,但是内部是函数指针的数据类型
var student = { name: '小马', height: 198, weight: 170, sayHello: function() { console.log("hello"); } }; console.log(student.name); console.log(student['height']); student.weight = 120; console.log(student.weight); student.sayHello(); student.sayHello = function() { console.log("Nothello"); } var pf = student.sayHello;//函数指针 pf();//函数指针访问函数 //前面为什么不能这样访问?之前那个是函数名字符串,而这是函数指针!
new Object 创建对象
首先是一个空对象,访问里面没有的属性或者方法,就会自动为那个对象添加属性和方法,后续也可以通过这个对象访问刚刚建立的成员
new Object() 替换成 {} 也是一样的效果
var object = new Object();//{} object.name = "小马"; object.height = 198; object.weight = 199; object.sayHello = function () { console.log("hello"); }; console.log(object.name); console.log(object["height"]); object.weight = 120; console.log(object.weight); object.sayHello(); object.sayHello = function () { console.log("Nothello"); }; var pf = object["sayHello"]; pf();
通过函数来构造
通过这种业务模式可以构造多个相同类型的对象
类似于java的构造方法
function Cat(name, type, sound) { this.name = name; this.type = type; this.miao = function () { console.log(sound); //sound在这里是个小全局,所以访问得到 }; }
区别于普通函数,它又this关键字,它的构造由new构造
在里面不要搞花样了,按着这个初心老实写代码,就不会出错了!
var cat1 = new Cat("猫1", 1, 111); var cat2 = new Cat("猫2", 2, 222); action(cat1); action(cat2); function action(cat) { console.log(cat.name); console.log(cat["type"]); cat.miao(); cat.miao = function () { console.log("hhh"); }; cat["miao"](); }
2.4 Java对象与JavaScript对象的区别
2.4.1 JS没有类的概念
对象其实就是,属性+方法的集合
JS的前两种方法,也没有提供类名,只是单纯的为一个var对象添加属性和方法而已
而第三种方法,“构造方法”也只不过是一个脚本,把一些属性和方法打包成函数,再通过new关键字实现给var对象添加这一套属性方法的功能
这样构造的对象未来也可以各自添加个别的属性和方法呀~
总的来说,只能说明这个var变量,有这么些属性和方法,但是没有具体的类
2.4.2 JS不区分属性和方法
刚才也实验了,对象的方法,其实就是函数指针
2.4.3 JS没有private和public等访问限制的机制
只要有导入,在外界随意访问~
2.4.4 JS中没有继承,更没有多态
没有类,当然没有继承和多态
你最多能做的是,“嵌套对象”