JavaScript(1)
1、快速入门
1.1、引入js
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- <script>--> <!-- alert("hello word!");--> <!-- </script>--> <script src = "js/1.js"></script> </head> <body> </body> </html>
1.2、基本语法入门
<!--JavaScript严格区分大小写!--> <script> //1.基本数据类型,比Java简单,所有的基本数据类型都用var代替! var score = 100; // alert(score); //2.条件控制,和Java一样 if(score < 200){ alert("hello!"); }else { alert("goodBay!"); } /* * 多段注释和Java一样 * */ </script>
js代码的调试!--浏览器的应用!
js的代码要在浏览器中调试!
1、在浏览器中右键打开审查元素(或者找到开发者工具),常用以下功能:
2、
Elements:查看网页的组成,借鉴网页的结构,调试网页的元素属性就在这
Console:控制台,可以在这里写css代码,并输出
常用命令:在浏览器的控制台打印变量!
console.log(score)
Sources:当前源码目录,这个网页上的生成文件都放在这。在这里可以调试css代码,设置断点进行调试
Network:网络请求,抓包就在这
Application:相当于web里面的数据库,存放一些东西,查看cookie在这
1.3、数据类型
数值,文本,图形,音频,视频.......
变量:
在js中,var是个神奇的东西,var可以表示所有的数据类型,各种变量就不必说了,像类这种数据类型它也可以定义!
var 王者荣耀 = 倔强青铜;//可以用中文作为变量!Java也可以!!String 王者荣耀 = "倔强青铜";
number:
js不区分小数和整数,Number
123//整数123 123.1//浮点数123.1 1.123e3//科学计数法 -99//负数 NaN //not a number Infinity //表示无限大
字符串:
'abc' "abc"
布尔值:
true , false
逻辑运算:
&& 两个都为真,结果为真 || 一个为真,结果为真 ! 真即假,假即真
比较运算符:
= == 等于(类型不一样,值一样,也会判断为true)不要用这个来判断相等! === 绝对等于(类型一样,值一样,结果为true)js常用三个等于表判断! 须知: NaN === NaN 结果为false,即NaN与所有的数值都不相等,包括自己 只能通过 isNaN(NaN) 来判断这个数是否是NaN
浮点数问题:
console.log((1/3) === (1-2/3));//打印出来是false! 所以尽量避免使用浮点数进行运算,存在精度问题! console.log(Math.abs((1/3)-(1-2/3))<0.00000001);//打印出来是true,Math.abs()取绝对值 说明,如果有精度限制,是可以的。
null和undefined
-
null 空 undefined 未定义
数组
java必须是一系列相同类型的对象,js中不需要!
var arr = [1,2,3,4,5,"zyy",true,null];//都可以! new Array(1,2,3,'hello');//这样也可以,为了代码的可读性,推荐使用上一种方式! 取数组下标:如果越界了,就会 undefined//并不会报错!又说明了:比起Java,真是宽松的多!
对象:
对象是大括号括起来,数组是中括号。 var person = { //万物皆可var name:"zyy", age:20, tags:['js','java','web','...']//数组 } 每个属性之间用逗号隔开,最后一个不需要 如果是Java代码,长这样: Person person = new Person(1,2,3,4,5); 调用时:和Java类调用属性和方法的形式一样! person.name >"zyy" person.age >20
1.4、严格审查模式
由于js的宽松型,一些变量会成为全局变量(不用var),影响最终的代码合成,所以要有一个严格审查模式!
//前提:idea需要设置支持ES6语法 //'use strict';严格审查模式,预防js的随意性导致产生一些问题 //必须写在js的第一行! //新语法:(ES6)局部变量建议都用let去定义 'use strict'; let i = 1;
2、数据类型(详细)
2.1、字符串
1、一般字符串我们使用单引号或者双引号包裹
2、注意转义字符
\' 引号作为正常符号 \n 换行 \t table键 \u4e2d \u#### Unicode字符编码,这个表示“中” \x41 Ascll字符编码,这个代表“A”
3、多行字符串编写
//tab键上面的着重符```` var msg = `hello world 你好啊 你好`
4、模板字符串
//同样用到着重符 let name = "zyy"; let age = 3; let msg = `你好呀,${name}`
5、字符串长度
和Java一样,调用方法就可以了
str.length
6、字符串的可变性:不可变
console.log(student[0]); >s student[0] = 1; console.log(student[0]); >s //还是会输出s
7、大小写转换
//调用方法 student.toUpperCase(); >STUDENT student.toLowerCase(); >student
8、字符串的其他方法
student.indexOf('t');//输出字符串中't'第一次出现的下标 >1 student.substring(1);//从第一个字符截取到最后一个字符 student.substring(1,3)//左闭右开的截取1到3的字符
2.2、数组
Array可以包含任意的数据类型
var arr = [1,2,3,4,5,6];//数组初始化,通过下标取值和赋值 arr[0];取 arr[0] = 1;赋值 1、长度: arr.length 注意:假如给arr.length赋值,数组大小就会发生变化,如果赋值过小,元素就会丢失!也就是说,数组是可以改变的(对比字符串)。 2、indexOf,通过元素获取下表索引 arr.indexOf(2); 注意:字符串的“1”和数字1不同
3、slice()
截取array的一部分,返回一个新数组,类似于string中的substring!!
4、push(), pop() :对尾部操作(栈)
push() :压入到数组尾部数据 pop() :弹出尾部的一个元素,一次弹出一个!
5、unshift(),shift() :对头部进行操作
unshift :压入到数组头部数据 shift: 弹出头部一个数据
6、排序 sort()
var arr = ["b","c","a"]; arr.sort(); ["a","b","c"]
7、元素反转 reverse()
arr.reverse(); ["c","b","a"]
8、concat()
arr.concat([1,2,3]); ["c","b","a",1,2,3]; arr ["c","b","a"]//数组没有变化!
注意:concat()并没有修改数组,只是会返回一个新的数组
9、连接符 join(),用for循环遍历也可以
打印拼接数组,使用特定的字符连接
["c","b","a"] arr.join('-'); "c-b-a";//把拼接后的数据打印出来
10、多维数组
arr = [[1,2],[3,4],["5","6"]]; arr[1][1]; 4
2.3、对象
若干个键值对!
var 对象名 = { 属性名:属性值, 属性名:属性值, 属性名:属性值 } //定义了一个person对象,它有四个属性! var person = { name:"zhangyaoyaun", age:3, email:"1571868660@qq.com", score:100 }
js中对象,{...}表示一个对象,键值对描述属性XXX : XXX,多个属性之间使用逗号隔开,最后一个属性不加逗号!
JavaScript中的所有键都是字符串,值是任意对象!
1、对象赋值
person.name = "zyy"//就可以了!
2、使用一个不存在的对象属性,不会报错!只会undefind!
3、动态的删减属性,通过delete删除对象的属性
delete person.name true
4、动态的添加,直接给新的属性添加值即可
person.haha = "haha"
5、判断属性值是否在这个对象中! XXX in XXX!
'age' in person //因为所有的键都是字符串,所以要加上引号 true 'toString' in person true//因为person继承了其他的对象,所以父对象的方法它也有!
6、判断一个属性是否是这个对象自身拥有的 hasOwnProperty()
person.hasOwnProperty('toString') false person.hasOwnProperty('age') true
2.4、流程控制
if判断:和Java一样
var age = 3; if(age>3){//第一个判断 alert("haha"); }else if(age <5){//第二个判断 alert("kuwa"); }else{//否则 alert("abc") }
while循环,注意避免程序死循环
var age = [23,24,45,64,3,68,4,6,566,34]; while(age<100){ age = age + 1; console.log(age) } //do while 必定会执行一次 do{ age = age + 1; console.log(age) }while(age<100)
for 循环
for(let i = 0;i < 100 ; i++){ console.log(i) }
forEach循环
//函数 age.forEach(function(value){ console.log(value) }) for...in循环,当不知道数组长度时,这个比较快 //for(var index in object){} for(var num in age){ console.log(age[num]); }
2.5、Map和Set
es6 的新特性!和Java new对象的方式一样
Map:把两个一一对应的数组合成到一块,可以通过其中一个,找到另一个 //如果不用Map要定义两个数组 //var names = ["tom","jerry","jack"] //var scores = [100,89,98] var map = new Map([['tom',100],['jerry',89],['jack',98]]) var name = map.get('tom');//get方法:通过key获得value console.log(name);//就会输出100 map.set('admin',99);//set方法:新增或修改 map.delete('tom');//删除 Set:无序不重复的集合(去重!) var set = new Set([3,1,1,1]) console.log(set)//结果只输出3和1,去重了! set.add(2);//增加元素的方法 set.delete(1);//删除元素的方法 console.log(set.has(3));//判断是否含有元素,结果输出true 2.6、itrator遍历 新特性! 遍历数组: //以后就固定下来,for...in求下表;for...of列出值 var arr = [3,4,5] for (var x of arr){ console.log(x) } 遍历Map var map = new Map([['tom',100],['jerry',90],['jack',80]) for (let x of map){ console.log(x) } 遍历Set: var set = new Set([5,6,7]); for(let x of set){ console.log(x) }
3、函数
3.1、定义函数
定义方式一
绝对值函数
function abs(x){ if(x>=0){ return x; }else{ return -x; } }
注意:一旦执行到return代表函数结束,返回i结果!
如果没有执行return,函数执行完也会返回结果,结果就是undefined
定义方式二(个人比较喜欢,是js的风格)
var abs = function(x){ if (x>=0){ return x; }else{ return -x; } }
注意:function(x){.....}这是一个匿名函数。但是可以把结果赋值给abs,通过abs就可以调用函数!
方法一和方法二等价!
调用函数
两种定义方法只有一种调用方式!
abs(10) //10 abs(-10)//10
注意:在这里就会有一个问题
由于js的随意性,调用者可以输入任意多个参数(包括0个),也不会报错(只会取前有效个)
首先解决参数不存在的问题:手动抛出异常
var abs = function(x){ //手动抛出异常来判断 if(typrof x!=='number'){ throw 'Not a Number'; } if (x>=0){ return x; }else{ return -x; } }
要解决多余参数的问题,首先认识一个关键字arguments
arguments
arguments
是js免费赠送的关键字!(其实就是内置属性)
代表,传进来的所有参数,是一个数组!
就是说通过arguments把所有传进来的参数收集起来放到数组里了
var abs = function(x){ console.log("x = >"+x);//只会输出第一个有效值! for(var i = 0;i<arguments.length,i++){ console.log(arguments[i]); //会把所有传递的参数输出出来 } if (x>=0){ return x; }else{ return -x; }
问题:arguments包含所有的参数,我们有时候想使用多余的参数来进行附加操作。需要排除已有的参数。
解决这个问题,要了解另外一个关键字rest
rest
没有rest之前解决方式: if(arguments.length>1){ for(var i = 1;i<arguments.length;i++){ //.... } } ES6引入的新特性,rest,获取除了已经定义的参数以外的所有参数! function aaa(a,b,...rest){ console.log("a=>"+a);//输出a和undefined以及一个空数组 console.log("b=>"+b);//输出undefined和b以及一个空数组 console.log(rest);//输出除了a,b之后的所有参数! }
注意:rest参数只能写在最后面,必须用...标识!(注意格式)
3.2、变量的作用域
在js中,var定义变量实际上是有作用域的。
假设在函数体中声明,则在函数体外不可以使用(非要实现的话,后面可以研究一下·闭包·) function qj(){ var x = 1; x = x+1; } x = x + 2;//会报未定义的错误 如果两个函数使用了相同的变量名,只要在函数内部,就不冲突 function qj(){ var x = 1; x = x+1; } function qj2(){ var x = 'A'; x = x + 1; } 内部函数可以访问外部函数的成员,反之则不行 function qj(){ var x = 1; function qj2(){ var y = x + 1;//这是没问题的 } var z = y + 1;//这里会报未定义错误 } 假设内部函数变量和外部函数变量重名 function qj(){ var x = 1; function qj2(){ var x = 'A'; console.log('inner'+x);//输出:innerA } console.log('outer'+x);//输出:outer1 qj2(); }
逻辑:js中,函数查找变量从自身函数开始,由内向外(或者就近原则)查找,假设外部存在这个同名的函数变量,则内部函数会屏蔽外部函数的变量。
提升变量的作用域
function qj(){ var x = 'x'+y; console.log(x); var y = 'y'; }
结果:xundefined
说明:js执行引擎,会自动提升y的声明,但不会提升变量y的赋值(也就是顺序执行!)
这个是在js建立之初就存在的特性
养成规范:所有的变量定义都放在函数头部,不要乱放,便于代码维护!
function qj2(){ var x = 1,y = x + 1, z,i,a; //之后就可以随便用了 }
全局变量
//全局变量 var x = 1; function f(){ console.log(x); } f(): console.log(x);//都可以输出
全局对象:window
var x = 'xxx'; alert(x); alert(window.x);//和上面等效!说明默认所有的全局变量,都会自动绑定在window对象下! alert()这个函数本身也是一个window变量! 我们尝试修改这个函数: var x = 'xxx'; window.alert(x);//正常输出; var old_alert = window.alert;//把函数拿出来 old_alert(x);//发现也可以输出了 //重新定义alert window.alert = function(){ }; alert(x);//发现alert失效了! //恢复 window.alert = old_alert;
总结:js实际上只有一个全局作用域(也就是window!),任何变量(函数也可以视为变量),假设没有在函数作用范围内找到,就会向外查找,如果在全局作用域都没找到,就会报错.
规范
由于我们所有的全局变量都会绑定到我们的window上。如果不同的js文件,使用了相同的全局变量,就会冲突!
解决冲突:
var zyyNamespace = {};//每一个人把变量放在自己的命名空间上 //定义全局变量: //以下语句加上属性和方法! zyyNamespace.name = 'zhangyaoyuan'; zyyNamespace.add = function(){ return a + b; }
jQuery就是一个命名空间!(以后学)
局部作用域let
function aaa(){ for (var i = 0;i < 100;i++){ console.log(i); } console.log(i+1);//还是可以输出出来! }
ES6 let 关键字,解决局部作用域冲突问题!
function aaa(){ for (let i = 0;i < 100;i++){ console.log(i); } console.log(i+1);//报错:I is not defined }
建议都用let
去定义局部作用域的变量
常量 const
在ES6之前,定义常量很不规范:只要用全部大写字母命名的变量就是常量,建议不要修改这样的值(我就修改你也没办法!)
在ES6引入了关键字const
const PI = '3.14';//只读变量 console.log(PI); PI = '123';//报错
3.3、方法
把函数丢到对象中去就变成了方法!
对象只有两个东西:属性和方法
定义方法
var zhangyaoyuan = { name:'zyy', birth:2000, //注意方法的书写格式 age:function(){ //今年减去出生年 var now = new Date().getFullYear(); return now-this.birth; } } //属性: zhangyaoyaun.name; //方法:一定要带() zhangyaoyaun.age();
this代表什么?this很神奇,拆开上面的代码看看!
function getAge(){ //今年减去出生年 var now = new Date().getFullYear(); return now-this.birth; } var zhangyaoyaun = { name:'zyy', birth:2000, age:getAge//这里不要加括号,记住吧,确实有点乱 } zhangyaoyaun.age();//没问题!!因为this是无法指向的,默认指向调用它的那个对象! getAge();//会报错 NaN 原因:this默认指向了window,而window是没有birth属性的!
apply 关键字
在js中可以控制this的指向!并且所有的函数都有这个方法!
apply有两个参数,第一个是要指向的对象,第二个是指向对象的参数,用[]括起来
function getAge(){ //今年减去出生年 var now = new Date().getFullYear(); return now-this.birth; } var zhangyaoyaun = { name:'zyy', birth:2000, age:getAge//这里不要加括号,记住吧,确实有点乱 }; var zhangsan = { name:'zhangsan', birth:2000, age:getAge//这里不要加括号,记住吧,确实有点乱 }; getAge.apply(zhangsan,[]);//这里是空参,这样,this就指向了 zhangsan