javaScript是世界上最流行的脚本语言
JS诞生与1995年,他的出现主要是用于处理网页中的前端验证
JS由三部分组成:ECMASciript、DOM、BOM
JS的特点:解释型语言、类似于C与JAVA的语法结构、动态语言、基于面向对象的语言
从上到下一行一行执行
alert在浏览器弹出一个警告框
JS代码的编写位置:
1.可以将js标签编写到标签的Onclick属性中,当我们点击的时候,js才会执行
2.可以将js代码写在超链接的herf属性中,这样当点击超链接时,会执行js
(虽然可以写在标签属性中,但是他们属于结构与行为耦合,不方便维护,不推荐使用)
3.JS代码需要编写到scipt标签里面(推荐使用)
可以将js代码写到外部js文件中,然后通过scipt标签引入
script标签一旦用于引用外部文件了,就不能再编写代码了,即使编写代码了浏览器也会忽略,如果需要则可以再创建一个新的scipt标签用于编写内部代码。 script标签是双标签
不用显示丁定义type,也就是默认就是javascript
注释:
多行注释:/*? ? ? ? */
单行注释:? //
基本语法:
1.JS里面严格区分大小写;
2.JS中每一条语句以(;)结尾 如果不加;浏览器会自动添加,但是会消耗一些系统资源,而且有时候,浏览器会加错分号,所以在开发中分号必须写;
3.JS中会忽略多个空格与换行,所以我们可以利用空格和换行对代码进行格式化
字面量与变量:
字面量,都是一些不可改变的量(字面量都是可以直接使用,但是我们一般不会直接使用字面量)
变量:变量可以用来保存字面量,而且变量的值是可以任意改变的
变量更加方便我们使用,所以在开发中都是通过变量去保存一个字面量而很少直接使用字面量
可以用变量对字面量进行描述
声明变量与赋值变量:
var a = 1;
标识符:
在JS中所有的可以由我们自主命名的都可以称为是标识符;
例如:变量名、函数名、属性名都属于标识符
命名遵循以下原则:
1.标识符可以包含字母、数字。-、$;
2.标识符不能以数字开头;
3.标识符不忙是ES中德关键字或保留字;
4.标识符一般采用驼峰命名法(非强制)
首字母小写,每一个单词德开头字母大写,其余字母小写;
JS底层保存标识符实际上是采用的Unicode编码,所以理论上讲,所有的utf-8中含有的内容都剋以作为标识符
数据类型(字面量的类型):
String 字符串
var str = "hello";
在JS里面字符串需要使用引号引起来
使用双引号和单引号都可以,但是不要混用
引号不能嵌套,双引号里面不能放双引号,单引号里面不能放单引号
在字符串里面我们可以使用\进行转义
\"? 表示“
\’? 表示‘
\n? 表示换行
\t? 表示制表符
\\? 表示\
3.多行字符串
var msg = 'hello
world
你好呀
你好'
4.模板字符串
let name = "ziop";
let age = 21;
let msg = '你好呀,${name}'
5.字符串长度:
str.length
6.字符串具有不可变性
7.大小写转换
//注意,这里是方法,不是属性了
student.toUpperCase()
student.toLowerCase()
8.student.indexOf('t')
9.substring
[)
student.substring(1)//从第一个字符串截取到最后一个字符串
student.subtring(1.3)[1.3)
10.trim()? 移除字符串首尾空白
11.
var x = "JohnJohn";? ? ? ? ? ? ? // x 是字符串
y = x.charAt(2); // h
y = x.charCodeAt(2); // 104
y = x.concat(y, y); // JohnJohn104104, x+y+y
y = x.indexOf('h'); // 2, 索引从0开始
y = x.lastIndexOf('h'); // 6
y = x.slice();
stringObject.slice(start,end)
y = x.slice(2,5);? // hnJ
y = x.slice(2);? ? // hnJohn
y = x.split('o'); //J,hnJ,hn
y = x.substr(2); // hnJohn
y = x.substring(2,4) // hn,[2,3]
y = x.toLocaleLowerCase(); // johnjohn,小写
y = x.toLocaleUpperCase(); // JOHNJOHN,大写
y = x.toString(); // 转成Stirng
y = x.toUpperCase(); // JOHNJOHN,大写
y = x.trim(); // JohnJohn,去除两端的空格
y = x.valueOf(); // 返回某个字符串对象的原始值
12.两个数字相加,返回数字相加的和,如果数字与字符串相加,返回字符串
x=5+5;? //10
y="5"+5;? //55(字符串)
z="Hello"+5; //Hello5(字符串)
13.
1、字符串一个很能强大的数据类型;在执行加 + 时,将被加的对象统一处理为字符串。
2、boolean类型在与数字类型进行相加时,视为 0 或者 1 处理。
3、null 类型与数字类型进行累加时,视为 0 处理。
4、boolean类型与 null 类型进行累加时,视为其与整数类型累加处理。
5、undefined 除了与字符串进行累加时有效(undefined 视为字符串"undefined"处理),其他情况皆返回 NaN。
6、求模 % 运算,运算结果只取决于第一个数字的正负。
Number 数值
在JS里面所有的数值都是Number类型,包括整数与浮点数
数字的最大值;Number.MAX-VALUE 1. 7976931348623157e+308
数字的最小值;Number.MIN-VALUE 0以上的最小值 5e-324
如果使用的Number表示的数字超过了最大值,则会返回一个Infinity 表示正无穷,-Infinity表示负无穷
使用typeof检查Infinity也会返回number
NaN 是一个特殊的数字,表示Not a Number
使用typeof检查一个NaN也会返回一个number
须知:
NaN===NaN,这个与所有的的数值都不相等,包括自己
只能通过isNaN(NaN)来判断这个数是否为NaN
在JS中整数的运算基本可以保证精确
如果使用JS进行浮点数运算,可能得到一个不精确的结果,所以千万不要使用JS进行精确度要求高的运算
浮点数问题:
console.log((1/3) === (1-2/3));
尽量避免使用浮点数进行运算,存在精度问题
Math.abs(1/3-(1-2/3))<0,000000001;
Boolean 布尔值
只有两个主要用来做逻辑判断:ture表示真,false表示假
如果布尔对象无初始值或者其值为:
0
-0
null
""
false
undefined
NaN
那么对象的值为 false。否则,其值为 true(即使当变量值为字符串 "false" 时)!
Null 空值
只有一个null,null专门用来表示一个空的对象
使用typeof检查null也会返回object
Undefined 未定义 是所有没有赋值变量的默认值,自动赋值。
只有一个值,就undefined
当声明一个变量,但是并不给变量赋值时,它的值就是undefined
使用typeof检查undefined也会返回undefined
undefined 和 null 的区别
null 和 undefined 的值相等,但类型不等:
typeof undefined? ? ? ? ? ? // undefined
typeof null? ? ? ? ? ? ? ? ? // object
null === undefined? ? ? ? ? // false
null == undefined? ? ? ? ? ? // true
Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。
Object 对象
前6种为基本数据类型,最后一种为引用数据类型
运算符typeof来检查变量的类型
语法:typeof 变量
typeof 用以获取一个变量或者表达式的类型,typeof 一般只能返回如下几个结果:
number,boolean,string,function(函数),object(NULL,数组,对象),undefined
正因为 typeof 遇到 null,数组,对象时都会返回 object 类型,所以当我们要判断一个对象是否是数组时。
判断是否为数组。
<p id="demo"></p>
<script>
var fruits = ["Banana", "Orange", "Apple", "Mango"];
document.getElementById("demo").innerHTML = isArray(fruits);
function isArray(myArray) {
? ? return myArray.constructor.toString().indexOf("Array") > -1;
}
</script>
return myArray.constructor.toString().indexOf("Array") > -1;这句话怎么解释
1、myArray 是函数 isArray 的参数,这里调用函数的时候,会传来数组 fruits。
2、constructor 是一个属性,构造函数属性,不同类型的数据,会得到相应不同的值。因为 myArray 是个数组,这里的 myArray.constructor 的值就是 function Array() { [native code] }。(如果 myArray 是个字符串,myArray.constructor 的值就是function String() { [native code] }。还有 number,boolean,object,等等。)
3、toString() 是个方法,变字符串的方法,这里把 function Array() { [native code] } 变成字符串,为了后面好检索。
4、indexOf("Array") 是个方法,检索字符串,这里看字符串 function Array() { [native code] } 里有没有Array,有就返回首次出现的位置,是一个数值,这里是 9。如果出现在第一个字符,会返回 0。空格参与计数。如果没有找到,就返回 -1。只要 >-1,就说明有 Array,就能判断原来那个函数调用传来的 fruits 是一个数组。如果 myArray.constructor.toString().indexOf("Object")>-1,那么 myArray 就是一个 Object 对象。不过那样地话,这个参数的名字就没取好了,应该叫做 myObject。
或者判断某个变量是否是某个对象的实例则要选择使用另一个关键语法 instanceof
var result = objectName instanceof objectType
更重要的是 instanceof 可以在继承关系中用来判断一个实例是否属于它的父类型。
str = "asd";
if(str instanceof String)//返回false
? document.write("YES");//不会打印YES
str = new String();
if(str instanceof String)//返回true
? document.write("yes");//不会打印yes
数组:
Java的是数值必须是相同类型的对象,js里面不需要这样
var arr = [1,2,3,4,null,true];
//保证代码的可读性,尽量使用[]
取数组下标:如果越界了,就会
undefined
1.长度
arr.length
注意:假如给arr.length赋值,数组大小就会发生变化,如果赋值过小,元素就会丢失
2.indexOf通过元素获得下标索引
arr.indexOf(2)
1
字符串的“1”和数字的1是不同的
3.slice()
截取Array的一部分,返回一个新的数组,类似于String中的substring
4.push(),pop()尾部
push:压入尾部
pop:弹出尾部的一个元素
5.unshift(),shift()头部
unshift:压入头部
shift:弹出头部的一个元素? ?
6.排序sort()
js中 sort排序出错的处理
https://blog.csdn.net/yj6232779/article/details/108493082
arr[] = ["B","C","A"]
arr.sort()
arr[] = ["A","B","C"]
7.元素反转reverse()
arr[] = ["A","B","C"]
arr.reverse()
arr[] = ["C","B","A"]
8.concat()
arr[] = ["C","B","A"]
arr.concat([1,2,3])
["C","B","A",1,2,3]
concat()并没有数组,只是会返回一个新的数组
9.连接符 join
打印拼接述数组,使用特定的字符串连接
arr[] = ["C","B","A"]
arr.join('-')
"C-B-A"
10.多维数组
arr = [[1,2],[3,4],["5","6"]];
arr[1][1]
4
对象
JavaScript 对象是键值对的容器,“键”必须为字符串,“值” 可以是 JavaScript 中包括 null 和 undefined 的任意数据类型。
数组是[],对象是{}
若干个键值对
每一个属性之间使用逗号隔开,最后一个不需要添加
var 对象名 = {
? ? 属性名: 属性值,
? ? 属性名: 属性值,
? ? 属性名: 属性值,
? ? 属性名: 属性值
? ? //最后一个属性不需要加逗号
}
var person = {
name:"ziop",
age:21;
email:"2283280948@?量名则必须用第二种调用方法
? var max = {
? ? ? ? 'birth - month': '6',? //声名时必须要加''或者""
? ? }
? ? alert(max['birth - month']); //调用时必须要使用对象名['属性名']
3、使用一个不存在的对象属性,不会报错!undefined
person.haha
undefined
4、动态的删减属性
delete person.email
true
console.log(person)
VM158:1 {name: 'ziop', age: 21, score:151}
5、动态的添加属性(直接给新的属性添加值即可)
person.haha = "haha"
'haha'
console.log(person)
VM404:1 {name: 'ziop', age: 21, score:151,? haha: 'haha'}
6.判断属性值是否在对象里面xxx in xxx
"age" in person
true
//继承
"toString" in person
true
7.判断一个属性是否是这个对象自身所拥有的 hasOwnProperty()
person.hasOwnProperty("toString")
false
person.hasOwnProperty("age")
true
流程控制
if判断
if (age<21)
{
console.log("不是他");
}
if (age === 21)
{
console.log("是他呀");
}
else
{
console.log("未来是他");
}
while循环,避免出现死循环
while(age<100)
{
age = age+1;
console.log(age);
}
//do-while循环
do
{
age = age+1;
console.log(age);
}
while(age<100)
while遍历数组的例子中,如果数组中有 0,null,false,undefined 或者空字符串等在 js 中被认为等价于 false 的值,会提前结束遍历。改成判断数组长度即可避免该问题
原代码:
while (cars[i])
{
? ? document.write(cars[i] + "<br>");
? ? i++;
}
更改为:
while (i < cars.length)
{
? ? document.write(cars[i] + "<br>");
? ? i++;
}
for循环
for(let i = 21;i<100;i++)
{
console.log(i);
}
遍历数组
let ay = [1,34,5,465,65,654,65,64];
for(let i = 0;i<ay.length;i++)
{
console.log(ay[i]);
}
通过for of 遍历数组
let a = [1,2,3,4];
for(let x of? a)
{
? ? console.log(x);
}
for/in循环不仅可以遍历对象的属性,还可以遍历数组
var person={fname:"Bill",lname:"Gates",age:56};
for (x in person)? // x 为属性名
{
? ? txt=txt + person[x];
}
var x
var nums = [1, 3, 5];
for (x in nums)
{
? ? document.write(nums[x]+ "<br />");? // x 为数组索引
}
for...in 循环会自动跳过那些没被赋值的元素,而 for 循环则不会,它会显示出 undefined。
forEach循环
https://wenku.baidu.com/view/215d919c1937f111f18583d049649b6648d70907.html
break 的作用是跳出代码块, 所以 break 可以使用于循环和 switch 等
continue 的作用是进入下一个迭代, 所以 continue 只能用于循环的代码块。
Map和Set
(ES6出现的新特性)
let map = new Map([['tom',100],['jack',90],['haha',80]]);
let name = map.get('tom');//通过key获得value
map.set('admin',123456);//增加或者修改
map.delete('tom');//删除
set 无序不重复的排列
let set = new Set([1,23,24324,3,1]);
set.add(2);//增加一个元素
set.delete(1);//删除一个元素
console.log(set.has(3));//是否包含某个元素
iterator
遍历数组
利用for of
let a = [1,2,2,3,4];
for(var x of a)
{
console.log(x);
}
遍历Map
let map2 = new Map([['tom',100],['jack',90],['haha',80]]);//注意()
for(let b of map2)
{
console.log(b);
}
遍历Set
let set1 = new Set([1,233,4,4,54,5]);
for(let c of set1)
{
console.log(c);
}
比较运算符:
= 赋值符号
Js中==与===的区别:
1、对于 string、number 等基础类型,== 和 === 是有区别的
a)不同类型间比较,== 之比较 "转化成同一类型后的值" 看 "值" 是否相等,=== 如果类型不同,其结果就是不等。
b)同类型比较,直接进行 "值" 比较,两者结果一样。
2、对于 Array,Object 等高级类型,== 和 === 是没有区别的
进行 "指针地址" 比较
3、基础类型与高级类型,== 和 === 是有区别的
a)对于 ==,将高级转化为基础类型,进行 "值" 比较
b)因为类型不同,=== 结果为 false
'use strict'(注意是单引号)严格检查模式 防止javascipt随意性导致的一些问题
"use strict" 指令只允许出现在脚本或函数的开头。
https://www.runoob.com/js/js-strict.html
局部变量建议都使用let取去定义
强制类型转换:指将一个数据类型转换为其他数据类型
类型转换主要是Number、String、Boolean
将其他数据转换为String
1.调用toString()方法xxx.toString(); 不能用于null、undefined数据类型的转换
该方法不会影响到原变量 ,它会将转换的结果返回
2.调用String函数?
将其他数据转换为Number
方法一 调用Number函数
字符串转换为数字
+ 可用于将变量转换为数字
1如果是纯数字的字符串,则直接转换为数字
2.如果字符串里面有非数字的内容,则直接转换为NaN? ? ? ? ? ? ? ? ? ? ? ? ? ?
3.如果字符串里面有空值或者空格,则转换为0
布尔值转Number
true转成1
false转成0
Null转换为数字是0
undefined转换为数字是NaN
方法二:
调用parseInt()函数把一个字符串中的有效整数去出来,然后转换为Number()
函数以及面向对象
函数
定义函数
//定义方式一
//绝对值函数
function abs(x)
{
if(x >= 0)
{
return x;
}
else{
return -x;
}
}
//测试结果
abs(10)
10
abs(0)
0
abs()
NaN
abs(-1)
1
一旦执行到return代表函数结果,返回结果
如果没有执行return,函数执行完就会返回结果,结果就是undefined
//定义方式二
? ? ? ? var abs1 = function(a)
? ? ? ? {
? ? ? ? ? ? if(a >= 0)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return a;
? ? ? ? ? ? }
? ? ? ? ? ? else{
? ? ? ? ? ? ? ? return -a;
? ? ? ? ? ? }
function(x){...}这是一个匿函数,但是可以把结果赋值给abs1,通过abs就可以调用函数
方式一与方式二等价
调用函数
abs(10)
10
abs(0)
0
abs()
NaN
abs(-1)
1
自调用函数
函数表达式可以 "自调用"。
自调用表达式会自动调用。
如果表达式后面紧跟 () ,则会自动调用。
不能自调用声明的函数。
通过添加括号,来说明它是一个函数表达式:
(function () {
? ? var x = "Hello!!";? ? ? // 我将调用自己
})();
参数问题:JavaScript可以传任意个参数,也可以不传递参数
参数传进来是否存在的问题?
假设不存在参数,如何规避?
? ? ? ? var abs1 = function(a)
? ? ? ? {
? ? ? ? ? ? if(typeof a !== 'number')
? ? ? ? ? ? {
? ? ? ? ? ? ? ? throw 'Not a number';
? ? ? ? ? ? }
? ? ? ? ? ? if(a >= 0)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return a;
? ? ? ? ? ? }
? ? ? ? ? ? else{
? ? ? ? ? ? ? ? return -a;
? ? ? ? ? ? }
? ? ? ? }
arguments
arguments 是一个js免费送的关键字;
代表,传递进来的所有参数,是一个数组!
? ? ? ? var abs1 = function (a) {
? ? ? ? ? ? console.log("a=>" + a);
? ? ? ? ? ? for (var i = 0; i < arguments.length; i++) {
? ? ? ? ? ? ? ? console.log(arguments[i]);
? ? ? ? ? ? }
? ? ? ? ? ? if (a >= 0) {
? ? ? ? ? ? ? ? return a;
? ? ? ? ? ? }
? ? ? ? ? ? else {
? ? ? ? ? ? ? ? return -a;
? ? ? ? ? ? }
? ? ? ? }
问题:arguments包含所有的参数,我们有时候想使用多余的参数来进行附加操作,需要排除已有参数~
rest
ES6引入新特性,获取除了已经定义的参数之外的所有参数
function aaa(a,b,...rest)
{
? ? console.log("a=>"+a);
? ? console.log("b=>"+b);
? ? console.log(rest);
}
rest参数只能写在最后,必须用...标识
变量的作用域
在JavaScript中,var定义变量实际是有作用域的。
函数只有两个作用:1.返回一个值;2.完成一件事
假设在函数体中声明,则在函数体外不可使用(如果很想实现的话,后面可以研究一下闭包)
function yyl()
{
? ? var x = 1;
? ? x = x = 1;
? ? return x;
}
x? = x + 2;
//Uncaught ReferenceError: x is not defined
如果两个函数体使用了相同的变量名,只要在函数内部,就不冲突
function yyl()
{
? ? var x = 1;
? ? x = x + 1;
? ? return x;
}
function yyl1() {
? ? var x = 1;
? ? x 量重名
function qj() {
? ? var x = 1;
? ? function qj1() {
? ? ? ? var x = 'A';
? ? ? ? console.log('inner'+x);
? ? ? ? ? //定义了但是没有调用
? ? }
? ? console.log('outer'+x);
? ? qj1();
}
qj();
假设在JavaScript中函数查找变量从自身函数开始,由内向外查找,假设外部存在这个的函数变量,则内部函数会屏蔽外部函数的变量。
提升变量的作用域
变量提升:
声明提升:函数声明和变量声明总是会被解释器悄悄地被"提升"到方法体的最顶部。
JavaScript 只有声明的变量会提升,初始化的不会。
函数优先,虽然函数声明和变量声明都会被提升,但是函数会首先被提升,然后才是变量。
function ziop() {
? ? var x = "x" + y;
? ? console.log(x);
? ? var y = "y";
}
ziop();
//执行结果:xundefined
说明:js执行引擎,自动提升了y的声明但是不会提升变量y的赋值;
function ziop1() {
? ? var y = "y";
? ? var x = "x" +y;
? ? console.log(x);
}
ziop1();
这个是在javaScript建立之初就存在的特性,养成规范:所有的变量定义在函数的头部,不要乱放,便于代码维护
全局变量
var x = 1;
function ziop2() {
? ? console.log(x);
}
ziop2();
console.log(x);
全局对象window
var z = 'xxx';
alert(z);
alert(window.z);//默认所有的全局变量,都会自动绑定在window对象下
alert()这个函数本身也是一个window变量:
var? a = 'aaa';
window.alert(a);
var old_alert = window.alert;
window.alert = function() {};
//发现alert()失效了
window.alert(123);
//恢复
window.alert = old_alert;
window.alert(456);
JavaScript实际上只有一个全局作用域,任何变量(函数也可以视为变量),假设没有在函数作用范围内找到,就会向外查找,如果在全局作用域都没有找到,就报错RefrenceError
规范
由于我们所有的全局变量都会绑定到我们的window上,如果是不同的js文件,使用了相同的全局变量,如何化解这种冲突?
var ziopApp = {};
//唯一的全局变量
//定义全局变量
ziopApp.name = 'ziop';
ziopApp.age = 21;
ziopApp.add = function (a,b) {
? ? return a + b;
}
把自己的代码全部放在自己定义的唯一空间名字中,降低全局命名冲突的问题
局部作用域 let
function aaa() {
? ? for( var i = 0;i<100;i++)
? ? {
? ? ? ? console.log(i);
? ? }
? ? console.log(i+1);//i出了这个作用域还可以使用
}
aaa();
ES6关键字let,解决局部作用域冲突的问题
function aaa1() {
? ? for( let i = 0;i<100;i++)
? ? {
? ? ? ? console.log(i);
? ? }
? ? console.log(i+1);//Uncaught ReferenceError: i is not defined
}
aaa1();
建议大家都是用let去定义局部作用域的变量
常量const
在ES6之前,怎么定义常量:只有用大写字母命名的变量就是常量,建议不要修改这样的值
var PI = '3.14';
console.log(PI);
PI = '213';//可以改变这个值
console.log(PI);
//打印结果:3.14 213
在ES6里面引入了常量关键字const
const PI = '3.14';
console.log(PI);
PI = '213';
//TypeError: Assignment to constant variable
console.log(PI);
let与var的对比:https://www.runoob.com/js/js-let-const.html
1.let是块级作用域let 声明的变量只在 let 命令所在的代码块 {} 内有效,在 {} 之外不能访问。 var 关键字声明的变量不具备块级作用域的特性,它在 {} 外依然能被访问到。
2.重新定义变量
使用 var 关键字重新声明变量可能会带来问题。
在块中重新声明变量也会重新声明块外的变量:
var x = 10;
// 这里输出 x 为 10
{
? ? var x = 2;
? ? // 这里输出 x 为 2
}
// 这里输出 x 为 2
let 关键字就可以解决这个问题,因为它只在 let 命令所在的代码块 {} 内有效。
var x = 10;
// 这里输出 x 为 10
{
? ? let x = 2;
? ? // 这里输出 x 为 2
}
// 这里输出 x 为 10
3.循环作用域
使用 var 关键字:
var i = 5;
for (var i = 0; i < 10; i++) {
? ? // 一些代码...
}
// 这里输出 i 为 10
使用 let 关键字:
let i = 5;
for (let i = 0; i < 10; i++) {
? ? // 一些代码...
}
// 这里输出 i 为 5
在第一个实例中,使用了 var 关键字,它声明的变量是全局的,包括循环体内与循环体外。
在第二个实例中,使用 let 关键字, 它声明的变量作用域只在循环体内,循环体外的变量不受影响。
4.局部变量
在函数体内使用 var 和 let 关键字声明的变量有点类似。
它们的作用域都是 局部的:
// 使用 var
function myFunction() {
? ? var carName = "Volvo";? // 局部作用域
}
// 使用 let
function myFunction() {
? ? let carName = "Volvo";? //? 局部作用域
}
5.全局变量
在函数体外或代码块外使用 var 和 let 关键字声明的变量也有点类似。
它们的作用域都是 全局的:
// 使用 var
var x = 2;? ? ? // 全局作用域
// 使用 let
let x = 2;? ? ? // 全局作用域
6.使用 var 关键字声明的全局作用域变量属于 window 对象:
var carName = "Volvo";
// 可以使用 window.carName 访问变量
使用 let 关键字声明的全局作用域变量不属于 window 对象:
let carName = "Volvo";
// 不能使用 window.carName 访问变量
7.重置变量
使用 var 关键字声明的变量在任何地方都可以修改:
var x = 2;
// x 为 2
var x = 3;
// 现在 x 为 3
在相同的作用域或块级作用域中,不能使用 let 关键字来重置 var 关键字声明的变量:
var x = 2;? ? ? // 合法
let x = 3;? ? ? // 不合法
{
? ? var x = 4;? // 合法
? ? let x = 5? // 不合法
}
在相同的作用域或块级作用域中,不能使用 let 关键字来重置 let 关键字声明的变量:
let x = 2;? ? ? // 合法
let x = 3;? ? ? // 不合法
{
? ? let x = 4;? // 合法
? ? let x = 5;? // 不合法
}
在相同的作用域或块级作用域中,不能使用 var 关键字来重置 let 关键字声明的变量:
let x = 2;? ? ? // 合法
var x = 3;? ? ? // 不合法
{
? ? let x = 4;? // 合法
? ? var x = 5;? // 不合法
}
let 关键字在不同作用域,或不同块级作用域中是可以重新声明赋值的:
let x = 2;? ? ? // 合法
{
? ? let x = 3;? // 合法
}
{
? ? let x = 4;? // 合法
}
8.var 关键字定义的变量可以在使用后声明,也就是变量可以先使用再声明
let 关键字定义的变量则不可以在使用后声明,也就是变量需要先声明再使用。
const与let、var的对比
const定义常量与使用let 定义的变量相似:
二者都是块级作用域
都不能和它所在作用域内的其他变量或函数拥有相同的名称
两者还有以下两点区别:
const声明的常量必须初始化,而let声明的变量不用
const 定义常量的值不能通过再赋值修改,也不能再次声明。而 let 定义的变量值可以修改。
在相同的作用域或块级作用域中,不能使用 const 关键字来重置 var 和 let关键字声明的变量:
在相同的作用域或块级作用域中,不能使用 const 关键字来重置 const 关键字声明的变量:
const 关键字在不同作用域,或不同块级作用域中是可以重新声明赋值的:
const 关键字定义的变量则不可以在使用后声明,也就是变量需要先声明再使用。
JavaScript this 关键字
面向对象语言中 this 表示当前对象的一个引用。
但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。
在方法中,this 表示该方法所属的对象。
如果单独使用,this 表示全局对象。
在函数中,this 表示全局对象。
在函数中,在严格模式下,this 是未定义的(undefined)。
在事件中,this 表示接收事件的元素。
call() 和 apply() 方法可以将 this 引用到任何对象。
方法
定义方法
方法就是把函数放在对象的里面,对象只有两个东西:属性和方法
var kuangshen ={
? ? name:'秦疆',
? ? birth:2000,
? ? age:function ()kuangshen.age()方法? 方法一定要带()
this.代表什么
function getAge() {
? ? //今年-出生的年
? ? var now = new Date().getFullYear();
? ? return now-this.birth;
}
var kuangshen1 = {
? ? name:'秦疆',
? ? birth:2000,
? ? age:getAge
}
console.log(kuangshen1.age());//可以
console.log(kuangshen1.getAge());
//Uncaught TypeError: kuangshen1.getAge is not a function
this是无法指向的,是默认指向调用它的那个对象
apply? 在js中可以控制this指向!
function getAge() {
? ? //今年-出生的年
? ? var now = new Date().getFullYear();
? ? return now-this.birth;
}
var kuangshen1 = {
? ? name:'秦疆',
? ? birth:2000,
? ? age:getAge
}
//在控制台输入:getAge.apply(kuangshen1,[]);? 打印出22
内部对象
? ? ? ? console.log(typeof 123); //number
? ? ? ? console.log(typeof '123');//string
? ? ? ? console.log(typeof true);//boolean
? ? ? ? console.log(typeof undefined);//undefined
? ? ? ? console.log(typeof NaN);//number
? ? ? ? console.log(typeof {});//object
? ? ? ? console.log(typeof []);//object
? ? ? ? console.log(typeof Math.abs);//function
var now = new Date();
now.getFullYear();//年
2022
now.getMonth();//月 0~11 代表月
5
now.getDate();//日
13
now.getDay();//星期几
1
now.getHours();//时
15
now.getMinutes();//分
30
now.getSeconds();//秒
3
now.getTime();//时间戳 全世界统一 1970 1.1 0:00:00 毫秒数
1655105403952
console.log(new Date(1655105403952));
//时间戳转换为时间
// Mon Jun 13 2022 15:30:03 GMT+0800 (中国标准时间)
注意:调用的都是方法不是属性,都需要加括号()
转换
now = new Date(1655105403952);
//Mon Jun 13 2022 15:30:03 GMT+0800 (中国标准时间)
now.toLocaleString()
//'2022/6/13 15:30:03'
now.toGMTString();
//'Mon, 13 Jun 2022 07:30:03 GMT'
JSON
json 是什么
早期,所有的数据传输习惯使用XML 文件
JSON (JavaScript Object Notation,JS 对象简谱)是一种轻量级的数据交换格式
简洁和清晰的层次结构使得JSON 成为理想的数据交换语言
易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率
在 JavaScript 一切皆为对象,任何js支持的类型都可以用JSON 来表示
格式:
对象都用 {}
数组都用 []
所有的键值对都使用 key:value
JSON 字符串和 JS对象的转化
// 在JavaScript 一切皆对象,任何js 支持的类型都可以用json 来表示;number,String? ....
//JSON 有且只有两个方法
//JSON 字符串和 JS 对象的转化
var user={
? name:"tt",
? age:3,
? sex:'女'
}
// 上面的是对象
//对象转化为 json 字符串? ? ?
输出结果? {"name":"tt","age":3,"sex":"女"}? ? 没有前面的箭头了不能展开
var jsonUser=JSON.stringify(user);
//console.log(jsonUser)
// {"name":"tt","age":3,"sex":"女"}? 输出效果
//json 字符串转化为对象,参数为json 字符串
var obj=JSON.parse('{"name":"tt","age":3,"sex":"女"}');
//注意要用单引号包裹起来
var obj={a:'hello',b:'hellob'};
var json='{'a':'hello','b':'hellob'}'?
//它本身就是一个字符串,而不是一个对象? 里面的单引号和双引号尽量保持一致
Ajax
原生的js写法 xhr 异步请求
jQuey 封装好的方法 $("#name").ajax("")
axios 请求
面向对象的编程
原型对象? 重要
什么是面向对象
JavaScript ,java c#....都有面向对象的特性 但是 JavaScript 有些区别
类:模板? ? 在 js 中被叫做原型对象
对象:具体的实例
在JavaScript 这个需要大家换一下思维方式
var Student={
? name:"ttt",
? age:3,
? run:function(){
? ? console.log(this.name+"run......");
? }
};
var xiaoming={
? name:"xiaoming"
};
//原型对象
xiaoming1.__proto__=student;
//注意是__两条)
var Bird={
? fly:function(){
console.log(this.name+"fly");
? }
};
//小明的原型对象是 student
xiaoming.__proto__=Bird;
给已有的函数对象增加属性或者方法
格式:构造函数名.prototype.新属性或者新方法
补充:JavaScript 函数
JavaScript 函数是被设计为执行代码特定任务的代码块
JavaScript 函数会在某代码调用它时被执行
JavaScript 函数通过 function? 关键字进行定义,其后是函数名和括号()
函数名 可包括字母,数字,下划线和美元符号(规则与变量名相同)
function name(参数1,参数2, 参数3){
要执行的代码
}
function Student(name){
this.name=name;
}
//给student 新增一个原型对象? ? prototype 原型对象
student.prototype.hello=function(){
alert('hello')
}
//以前定义一个类的方法 不作为参考对象 比较旧
class 关键字
class student{
? // 当new一个实例时,默认有一个constructor构造方法,默认返回实例对象(this)
? constructor(name){
? ? // this`关键字则代表实例对象
? ? this.name=name;
? }
? //进行了调用
? hello(){
? ? alert('hello')
? }
}
var xiaoming=new student("xiaoming");
var xiaohong=new Student("xiaohong");
xiaoming.hello()
继承 extends
class student{
? // 当new一个实例时,默认有一个constructor构造方法,默认返回实例对象(this)
? constructor(name){
? ? // this`关键字则代表实例对象
? ? this.name=name;
? }
? //进行了调用
? hello(){
? ? alert('hello')
? }
}
class XiaoStudent extends Student{
? constructor(name,age){
? ? super(name);
? ? this.grade=grade;
? }
? myGrade(){
? ? alert('我是一名小学生')
? }
}
var xiaoming=new student("xiaoming");
var xiaohong=new Student("xiaohong",1);
本质:查看对象原型
原型链
__proto__
七.操作BOM对象 (重点)
浏览器介绍
JavaScript 和浏览器关系 ?
// JavaScript 诞生就是为了能够让他在浏览器中运行
BOM :浏览器对象模型
BOM :浏览对象模型
IE 6~11
Chrome
Safari
Firefox
Opera
三方:
QQ 浏览器
360 浏览器
//window 代表 浏览器 窗口? 浏览器的一些常用方法
window.alert(1)
undefined
window.innerHeight
461
window.innerWidth
1880
window.outerWidth
1880
//封装了 浏览器的信息
Navigator? 封装了浏览器的信息? (不建议使用)
window.Navigator.length
0
navigator.appVersion
'5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Mobile Safari/537.36'
navigator.appName
'Netscape'
navigator.userAgent
'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Mobile Safari/537.36'
navigator.platform
'Win32'
大多数时候不会使用 navigator对象 (首字母大写是类)因为会被人人为修改
不建议使用这些属性来判断和编写代码
screen? //代表屏幕尺寸
screen.width
screen.width
1880px
screen.height
461px
location (重要)
location 代表当前页面的 URL 信息
host: "cn.bing.com"? host 代表主机
href: "https://cn.bing.com/?FORM=Z9FD1"? 当前指向的位置 href 可以跳转链接
protocol: "https:"? 协议
reload: ? reload()? 方法
reload:f reload()? // 刷新网页
location.assign('https://blog.kuangstudy.com/')? //设置新的定位
document 代表当前的页面,HTML DOM 文档树? ? ? ? ? (内容 :DOM 里面会重点 讲解)
document.title
"百度一下,你就知道"? //在百度的页面获得它的标题
document.title='狂神说' //可以改变 标题
能够获取动态的文档树节点,就可以动态的增加和删除节点
document.cookie 可以获得 cookie
cookie 客户端的一些本地信息
history.back()? //前进
history.forward()? //后退? history代表浏览器的历史纪录
八,操作 DOM (重点)
DOM :文档对象类型
浏览器网页就是一个Dom树形结构
DOM EventListener
addEventListener() 方法用于向指定元素添加事件句柄。
addEventListener() 方法添加的事件句柄不会覆盖已存在的事件句柄。
你可以向一个元素添加多个事件句柄。
你可以向同个元素添加多个同类型的事件句柄,如:两个 "click" 事件。
你可以向任何 DOM 对象添加事件监听,不仅仅是 HTML 元素。如: window 对象。
addEventListener() 方法可以更简单的控制事件(冒泡与捕获)。
你可以使用 removeEventListener() 方法来移除事件的监听。
element.addEventListener(event, function, useCapture);
第一个参数是事件的类型 (如 "click" 或 "mousedown").
第二个参数是事件触发后调用的函数。
第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。
默认值为 false, 即冒泡传递,当值为 true 时, 事件使用捕获传递。
事件冒泡或事件捕获?
事件传递有两种方式:冒泡与捕获。
事件传递定义了元素事件触发的顺序。 如果你将 <p> 元素插入到 <div> 元素中,用户点击 <p> 元素, 哪个元素的 "click" 事件先被触发呢?
在 冒泡 中,内部元素的事件会先被触发,然后再触发外部元素,即: <p> 元素的点击事件先触发,然后会触发 <div> 元素的点击事件。
在 捕获 中,外部元素的事件会先被触发,然后才会触发内部元素的事件,即: <div> 元素的点击事件先触发 ,然后再触发 <p> 元素的点击事件。
removeEventListener() 方法
removeEventListener() 方法移除由 addEventListener() 方法添加的事件句柄:
更新:更新 Dom 节点
遍历dom 节点:得到 dom 节点
删除:删除一个Dom 节点
添加:添加一个新的 dom 节点
要操作一个 Dom 节点 就必须要先获得这个 Dom 节点
获得 Dom 节点
<body>
? ? <div id="father">
? ? ? ? <h1>标题一</h1>
? ? ? ? <p id="p1">p1</p>
? ? ? ? <p class="p2">p2</p>
? ? </div>
? ? <script>
? ? ? ? var a1 = document.getElementsByTagName('a1');
? ? ? ? //标签选择器
? ? ? ? var p1 = document.getElementById('p1');
? ? ? ? //id选择器
? ? ? ? var p2 = document.getElementsByClassName('p2');
? ? ? ? //class选择器
? ? ? ? var father = document.getElementById('father');
? ? ? ? var childrens = father.children;
? ? ? ? </script>
</body>
? ? //获取一个元素
? ? var se = document.querySelector('#p1')
? ? //获取全部的元素
? ? var p2 = document.querySelectorAll("#father .p2")
更新节点
<body>
? ? <div id="father">
? ? ? ? <h1>标题一</h1>
? ? ? ? <p id="p1">p1</p>
? ? ? ? <p class="p2">p2</p>
? ? </div>
? ? <script>
? ? //其他选择器并不唯一,是一个数组,所以要采用数组下标的形式
? ? ? var a1 = document.getElementsByTagName('h1');
? ? ? ? a1[0].innerText = "456";
? ? ? ? var p2 = document.getElementsByClassName('p2');
? ? ? ? p2[0].innerText = "123";
? ? ? ? var p1 = document.getElementById('p1');
? ? ? ? //只有id选择器是唯一的,可以直接修改
? ? ? ? p1.innerText = "456";
? ? ? ? //可以解析HTML 文本标签
? ? ? ? p1.innerHTML ='<strong>123</strong>';
? ? ? ? </script>
? ? ? </body>
删除节点
删除节点的步骤:? 先获取父节点 通过父节点删除自己
? ? <div id="father">
? ? ? ? <h1>标题一</h1>
? ? ? ? <p id="p1">p1</p>
? ? ? ? <p class="p2">p2</p>
? ? </div>
? ? ? ? <script>
? ? ? ? //方法一,通过父节点删除
? ? ? ? var self = document.getElementById('p1');
? ? ? ? var father = self.parentElement;
? ? ? ? father.removeChild(self);
? ? ? ? //方法二
? ? ? ? var self = document.getElementById('p1');
? ? ? ? self.remove();
? ? ? //删除是一个动态的过程
? ? ? father.removeChild(father.children[0]);
? ? ? father.removeChild(father.children[0]);
//注意: 删除多个节点的时候,children 是在时刻变化的,删除节点的时候一定要注意~
//以下代码是已知要查找的子元素,然后查找其父元素,再删除这个子元素(删除节点必须知道父节点):
? ? var child = document.getElementById("p1");
? ? child.parentNode.removeChild(child);
? ? </script>
? ?
插入节点
我们获得了某个 DOM 节点,假设这个 Dom 节点是空的,我们通过 inner HTML 就可以增加一个元素了,但是这个 Dom 节点已经存在元素了,就会进行覆盖(所以我们就不能通过inner HTML 进行增加节点了
? <div id="father">
? ? ? ? <h1>标题一</h1>
? ? ? ? <p id="p1">p1</p>
? ? ? ? <p class="p2">p2</p>
? ? </div>
? ? <script>
? ? var p3 = document.createElement("p");
? ? let fa = document.querySelector("#father");
? ? p3.innerHTML = "<hr>"
? ? fa.appendChild(p3) //子元素后边添加元素
? ? fa.children[0].before(p3)? //子元素前面添加标签
? ? </script>
创建新的 HTML 元素 (节点) - appendChild() 它用于添加新元素到尾部。
<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另外一个段落。</p>
</div>
<script>
var para = document.createElement("p");
var node = document.createTextNode("这是一个新的段落。");
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
</script>
如果我们需要将新元素添加到开始位置,可以使用 insertBefore() 方法:
<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另外一个段落。</p>
</div>
<script>
var para = document.createElement("p");
var node = document.createTextNode("这是一个新的段落。");
para.appendChild(node);
var element = document.getElementById("div1");
var child = document.getElementById("p1");
element.insertBefore(para, child);
</script>
替换 HTML 元素 - replaceChild()
<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另外一个段落。</p>
</div>
<script>
var para = document.createElement("p");
var node = document.createTextNode("这是一个新的段落。");
para.appendChild(node);
var parent = document.getElementById("div1");
var child = document.getElementById("p1");
parent.replaceChild(para, child);
</script>
HTMLCollection 与 NodeList 的区别
HTMLCollection 是 HTML 元素的集合。getElementsByTagName() 方法返回 HTMLCollection 对象。动态
NodeList 是一个文档节点的集合。大部分浏览器的 querySelectorAll() 返回 NodeList 对象 静态
NodeList 与 HTMLCollection 有很多类似的地方。
NodeList 与 HTMLCollection 都与数组对象有点类似,可以使用索引 (0, 1, 2, 3, 4, ...) 来获取元素。
NodeList 与 HTMLCollection 都有 length 属性。
HTMLCollection 元素可以通过 name,id 或索引来获取。
NodeList 只能通过索引来获取。
只有 NodeList 对象有包含属性节点和文本节点。 方法用于向指定元素添加事件句柄。
HTML 元素。如: window 对象。