b站js基础视频教程: 尚硅谷JavaScript基础
课程相关资料: 链接:https://pan.baidu.com/s/15e8Ebq1P3D1ZsfSOsj4rSw 提取码:abtf
p46-p50 对象的简介
js的数据类型
String 字符串
Number 数值
Boolean 布尔值
Null 空值
Undefined 未定义
以上这五种类型属于基本数据类型,以后我们看到的值只要不是上边的5种,全都是对象 Object 对象
对象的简介
基本数据类型都是单一的值eg:”hello” 123 true。值和值之间没有任何的联系。对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性。
对象的分类:
* 1.内建对象
* 由ES标准中定义的对象,在任何的ES的实现中都可以使用
* 比如:Math String Number Boolean Function Object....
*
* 2.宿主对象
* 由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象
* 比如 BOM DOM
*
* 3.自定义对象
* 由开发人员自己创建的对象
对象的创建
使用new关键字调用的函数,是构造函数constructor
构造函数是专门用来创建对象的函数
使用typeof检查一个对象时,会返回object
var obj = new Object()
console.log(typeof obj) //object
对象的属性的基本操作
在对象中保存的值称为属性
- 添加或修改属性:
语法:对象.属性名 = 属性值
- 读取属性
语法:对象.属性名
注意:如果读取对象中没有的属性,不会报错而是会返回undefined
- 删除属性
语法:delete 对象.属性名
【对象案例】
//创建对象
var obj = new Object()
//添加属性
obj.name = 'tom'
obj.age = 18
//obj.name = 'jerry' //修改属性
//删除属性
//delete obj.name
//console.log(typeof obj) //object
console.log(obj.name)
属性名和属性值
属性名
对象的属性名不强制要求遵守标识符的规范(什么乱七八糟的名字都可以使用).尽量按照标识符的规范去做
特殊的属性名要用[]。在[]中可以直接传递一个
变量
,这样变量值是多少就会读取那个属性
语法:对象["属性名"] = 属性值
【demo】
var obj = new Object()
//属性名可以随意
obj.val = 123
console.log(obj.val)
//特殊的属性名要用[]
//obj.123 = 123 // Uncaught SyntaxError: Unexpected number
obj['123'] = 123
console.log(obj['123'])
var nihao = 'nihao'
obj[nihao] = '你好'
console.log(obj[nihao])
属性值
JS对象的属性值,可以是任意的数据类型,甚至也可以是一个对象和函数
//属性值
var obj = new Object()
obj.test = null
obj.test = undefined
obj.test = true
obj.test = function(){}
obj.test = new Object()
in运算符
通过该运算符可以检查一个对象中是否含有指定的属性,如果有则返回true,没有则返回false
语法:"属性名" in 对象
var obj = new Object()
obj.name = 'tom'
console.log("name" in obj) //true
console.log("age" in obj) //false
基本数据类型和引用数据类型
基本数据类型:String Number Boolean Null Undefined
引用数据类型:Object
* JS中的变量都是保存到栈内存中的,
* 基本数据类型的值直接在栈内存中存储,
* 值与值之间是独立存在,修改一个变量不会影响其他的变量
*
* 对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间,
* 而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用,
* 当一个通过一个变量修改属性时,另一个也会受到影响
当比较两个基本数据类型的值时,就是比较值。
而比较两个引用数据类型时,它是比较的对象的内存地址,【引用类型demo3】
如果两个对象是一摸一样的,但是地址不同,它也会返回false
【基本数据类型demo】
var a = 123;
var b = a;
a++;
【引用类型demo1】
var obj = new Object()
obj.name = 'swk'
var obj2 = obj
obj2.name = 'zbj'
console.log(obj) //zbj
console.log(obj2) //zbj
【引用类型demo2】 通过null切断引用
var obj = new Object()
obj.name = 'swk'
var obj2 = obj
obj2.name = 'zbj'
obj2 = null
console.log(obj) //zbj
console.log(obj2) //null
【引用类型demo3】
var obj3 = new Object();
var obj4 = new Object();
obj3.name = "shs";
obj4.name = "shs";
console.log(obj3 == obj4) //false
对象字面量
就是 { } 来创建对象,有点像json
使用对象字面量,可以在创建对象时,直接指定对象中的属性
* 语法:{属性名:属性值,属性名:属性值....}
* 对象字面量的属性名可以加引号也可以不加,建议不加,
* 如果要使用一些特殊的名字,则必须加引号
*
* 属性名和属性值是一组一组的名值对结构,
* 名和值之间使用:连接,多个名值对之间使用,隔开
* 如果一个属性之后没有其他的属性了,就不要写,
【对象字面量案例】
//使用对象字面量创建对象,属性为空
var obj = {}
obj.name = 'jerry'//赋值和前面的一样
console.log(obj) //{name: 'jerry'}
console.log(typeof obj)//object
//使用对象字面量创建对象并初始化属性值
var obj2 = {
name: 'tom',
age: 18,
gender: '男',
dog: {name: '旺财',age: 3}
}
console.log(obj2)
p51-p65 函数
创建和调用函数
- 函数创建的三种方式
第一种:使用构造函数
创建(不推荐)
var func = new Function('语句...')
第二种:使用 函数声明
来创建一个函数
语法:
function 函数名([形参1,形参2...形参N]){
语句...
}
第三种:函数表达式
创建函数
var 函数名 = function([形参1,形参2...形参N]){
语句....
}
- 函数的调用
封装到函数中的代码不会立即执行
函数中的代码会在函数调用的时候执行
调用函数 语法:函数对象()
当调用函数时,函数中封装的代码会按照顺序执行
【函数的创建和调用案例】
//1.通过构造函数创建函数对象(不常用)
var func = new Function('console.log("通过构造函数创建函数对象")')
func() //调用函数
console.log(typeof func) //function
//2.通过函数声明来创建函数
function func2(){
console.log("通过函数声明创建函数对象")
}
func2() //调用函数
//3.通过函数表达式创建函数对象
var func3 = function(){
console.log("通过函数表达式创建函数对象")
}
func3() //调用函数
函数的参数
函数的参数可以是任意类型,声明的时候不需要写类型。
函数调用时,解析器不会去检查参数的类型和数量,多余实参不会被赋值,
如果实参的数量少于形参的数量,则没有对应实参的形参将是undefined。
【函数的参数案例】
function sum(a,b){
console.log(a+b)
}
//参数类型任意
sum(1,2) //3
sum(1,"2") //12
sum(true,false) //1 true为1 false为0
sum(true,1) //2
//参数个数任意
sum(1) //NaN
sum(1,2,3) //3 自动忽略第三个参数
函数的返回值
可以使用 return 来设置函数的返回值
* 语法:
* return 值
*
* return后的值将会会作为函数的执行结果返回,
* 可以定义一个变量,来接收该结果
*
* 在函数中return后的语句都不会执行
*
* 如果return语句后不跟任何值就相当于返回一个undefined,
* 如果函数中不写return,则也会返回undefined
*
* return后可以跟任意类型的值
【返回值案例】
function sum(a,b){
//可以返回任意类型
//return //不写变量或者不写return返回的是undefined
//return a + b
return {
name: 'tom',
age : 18
}
//console.log('我不会执行')
}
var rs = sum(1,2) //定义变量接收返回值
console.log(rs)
函数的实参
实参可以是任意的数据类型,也可以是一个对象
当我们的参数过多时,可以将参数封装到一个对象中,然后通过对象传递
function sayHello(o){
console.log("我是"+o.name+","+o.age+"岁了,"+""+o.gender+"人"+",我在"+o.address);
return o
}
var obj = {
name:"孙悟空",
age:18,
address:"花果山",
gender:"男"
}
sayHello(obj)
//注意下面的区别
function fun(a){
console.log(a)
}
fun(1)
fun(sayHello)
fun(sayHello(obj))
* sayHello(obj)
* 调用函数
* 相当于使用的函数的返回值
*
* sayHello
* 函数对象
* 相当于直接使用函数对象
函数内部嵌套函数
函数内部可以声明函数,可以无限嵌套
function fun1(){
function fun2(){
console.log('我是 fun2')
}
return fun2
}
var a = fun1()
//console.log(a)
//a()
fun1()() //注意一下这种写法
立即执行函数
页面加载后会立即执行.用一个括号把匿名函数包起来,然后再像函数调用那样加个括号运行。
里面定义的变量是局部变量,不会影响全局的作用域
//立即执行函数-不带参数
(function(){
console.log('立即运行')
})();
//立即执行函数-带参数
(function(a,b){
console.log(a+b)
})(123,456)
方法(了解)
函数也可以称为对象的属性,如果一个函数作为一个对象的属性保存,那么我们称这个函数时这个对象的方法.调用这个函数就说调用对象的方法(method) 但是它只是名称上的区别没有其他的区别
var obj = {
name: '孙悟空',
age: 18,
sayName: function(){
console.log(obj.name)
}
}
function fun(){
console.log('func')
}
fun() //调函数
obj.sayName() //调方法
枚举对象属性
把对象中所有的属性和值取出来
枚举对象中的属性
使用for ... in 语句
* 语法:
* for(var 变量 in 对象){
*
* }
for...in语句 对象中有几个属性,循环体就会执行几次
每次执行时,会将对象中的一个属性的名字赋值给变量
【枚举对象属性案例】
var obj = {
name: 'swk',
age: 18,
sayName: function(){
console.log(obj.name)
}
}
for(var key in obj){
console.log(key,":",obj[key])
}
全局作用域
作用域指一个变量的作用的范围
全局作用域
* 【直接编写在script标签中的JS代码,都在全局作用域】
* 全局作用域在页面打开时创建,在页面关闭时销毁
* 在全局作用域中有一个全局对象【window】,
* 它代表的是一个浏览器的窗口,它由浏览器创建我们可以直接使用
* 在全局作用域中:
* 【创建的变量都会作为window对象的属性保存】
* 【创建的函数都会作为window对象的方法保存】
* 全局作用域中的变量都是全局变量,
* 【在页面的任意的部分都可以访问的到】
【案例】
<script>
var c = 345
</script>
<script>
var a = 123
function fun(){
console.log('func')
}
console.log(window.a)
window.fun()
window.alert('xxx')
console.log(c)
</script>
声明提前
* 变量的声明提前
* 使用【var关键字声明的变量】,会在所有的代码执行之前被声明(但是不会赋值),
* 但是如果声明变量时不是用var关键字,则变量不会被声明提前
*
* 函数的声明提前
* 使用【函数声明形式】创建的函数 function 函数(){}
* 它会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数
* 使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
【声明提前案例如下】
//--------1.var声明的变量提前 相当于把var a 提取到代码最前面
console.log(a) //undefined
var a = 123
//--------2.没用var声明的变量不提前,所以报错------------------
//console.log(b) //报错 Uncaught ReferenceError: b is not defined
//b = 456
//--------3.函数声明提前-----------
fun() //fun
function fun(){
console.log('fun')
}
//-------4.函数表达式,不会被提前创建
//fun1() //Uncaught TypeError: fun1 is not a function
var fun1 = function(){
console.log('fun1')
}
函数作用域
* 函数作用域
* 调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁
* 每调用一次函数就会创建一个新的函数作用域,他们之间是【互相独立】的
* 在函数作用域中可以访问到全局作用域的变量
* 在全局作用域中无法访问到函数作用域的变量
* 【当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用
* 如果没有则向上一级作用域中寻找,直到找到全局作用域,
* 如果全局作用域中依然没有找到,则会报错ReferenceError】
* 【在函数中要访问全局变量可以使用window对象】
【在函数作用域也有声明提前的特性】
【定义形参就相当于在函数作用域中声明了变量】
【在函数中,不用var声明的变量都会成为全局变量】
【函数作用域案例】
//1.函数作用域入门
var a = 123
function fun1(){
var a = 456
console.log(a) //456
console.log(window.a) //123 通过window可以找全局的
}
fun1()
//2.一层层往上找,全局还找不到就报错
var b = 'b'
function fun2(){
var b = 'b2'
function fun3(){
//var b = 'b3'
console.log(b)
}
return fun3
}
fun2()()
//3.函数作用域内部方法声明提前
function fun3(){
//内部方法声明提前
fun4()
function fun4(){
console.log('fun4')
}
}
fun3()
//4.函数内部变量声明提前
function fun5(){
console.log(c) //undefined
var c = 10
d = 100 //函数内部不用var声明的变量将放入到全局作用域
}
fun5()
console.log(d) //100
//5.定义形参就相当于定义了变量(注意这个很容易出错)
var e= 'eee'
function fun6(e){
console.log(e) //undefined
}
fun6()
debug
谷歌浏览器为例,其它类似 首先用f12打开调试模式
给某个变量加上监听,右键变量 add selected text to watches
this
* 解析器在调用函数每次都会向函数内部传递进一个隐含的参数,
* 这个隐含的参数就是this,this指向的是一个对象,
* 这个对象我们称为函数执行的 上下文对象,
* 根据函数的调用方式的不同,this会指向不同的对象
* 【1.以函数的形式调用时,this永远都是window】
* 【2.以方法的形式调用时,this就是调用方法的那个对象】
【this案例】
var name ='全局的name'
function fun(){
console.log(this)
console.log(this.name)
}
//fun() //以函数的形式调用 this是window
var obj = {
name: 'tom',
sayName: fun
}
obj.sayName() //以方法的形式调用 this是调用方法的对象
console.log(obj.sayName == fun) //true
使用工厂函数创建对象
创建工厂函数,函数中new Object并给属性赋值.
//创建对象的的工厂方法
function createPeople(name,age,gender){
var obj = new Object()
obj.name = name
obj.age = age
obj.gender = gender
return obj
}
var luban = createPeople('鲁班',6,'男')
console.log(typeof luban,luban)
var aql = createPeople('安其拉',8,'女')
console.log(typeof aql,aql)
//存在缺陷,类型都是object的,后面的构造函数可以解决这个问题
构造函数
* 构造函数就是一个普通的函数,创建方式和普通函数没有区别,
* 不同的是构造函数习惯上【首字母大写】
*
* 构造函数和普通函数的区别就是调用方式的不同
* 普通函数是直接调用,而构造函数需要使用【new关键字来调用】
*
* 构造函数的执行流程:
* 1.立刻创建一个新的对象
* 【2.将新建的对象设置为函数中this,在构造函数中可以使用this来引用新建的对象】
* 3.逐行执行函数中的代码
* 4.将新建的对象作为返回值返回
*
* 使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类。
* 我们将通过一个构造函数创建的对象,称为是该类的实例
*
* this的情况:
* 1.当以函数的形式调用时,this是window
* 2.当以方法的形式调用时,谁调用方法this就是谁
* 3.当以构造函数的形式调用时,this就是新创建的那个对象
* 使用【instanceof】可以检查一个对象是否是一个类的实例
语法:对象 instanceof 构造函数
如果是,则返回true,否则返回false
【构造函数案例】
function Person(name,age){
console.log('构造方法执行了')
this.name = name
this.age = age
this.sayName = function(){
console.log(this.name)
}
}
//console.log(Person())//undefined
console.log(new Person('嫦娥',18))
console.log(new Person('猪八戒',18))
function Dog(name,age){
this.name = name
this.age = age
this.sayName = function(){
console.log(this.name)
}
}
console.log(new Dog('旺财',18))
//可以看到打印的类型不同: 一个是Person一个Dog
//使用【instanceof】可以检查一个对象是否是一个类的实例
console.log(new Dog('旺财',18) instanceof Dog) //true
console.log(new Person('猪八戒',18) instanceof Dog)// false
console.log(new Person('猪八戒',18) instanceof Object)// true Object是所有类的父类
【构造函数优化】
/*
* 将函数定义在全局作用域,污染了全局作用域的命名空间
* 而且定义在全局作用域中也很不安全
*/
function fun(){
console.log(this.name)
}
function Person(name,age){
console.log('构造方法执行了')
this.name = name
this.age = age
//改成引用的方式,提高性能,但是fun声明在全局中,也不是特别合适,后面可以声明到原型中
this.sayName = fun
}
var per = new Person('tom',18)
per.sayName()
p66-p67原型
* 原型 prototype
*
* 【创建的每一个函数,解析器都会向函数中添加一个属性prototype】
* 这个属性对应着一个对象,这个对象就是所谓的原型对象
* 如果函数作为普通函数调用prototype没有任何作用
* 当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,
* 指向该构造函数的原型对象,我们可以【通过__proto__来访问该属性】
*
* 【原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,
* 我们可以将对象中共有的内容,统一设置到原型对象中。】
*
* 【当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,
* 如果没有则会去原型对象中寻找,如果找到则直接使用】
*
* 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,
* 这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
【原型案例1】
function Person(){
}
//console.log(Person.prototype)
var per = new Person()
var per2 = new Person()
console.log(Person.prototype == per.__proto__) //true
console.log(Person.prototype == per2.__proto__) //true
console.log(per.__proto__ == per2.__proto__) //true
//向原型中加入属性
per.__proto__.a = 'aa'
Person.prototype.b = 'bb'
console.log(Person.prototype.a,Person.prototype.b) //aa bb
console.log(per.a,per.b) //aa bb
//向原型中加入方法
Person.prototype.sayHello = function(){
console.log('hello')
}
per.sayHello()
//给per添加属性a
per.a = 'per中的a'
console.log(per.a) //先到自己中找,没有再到原型中找
【原型案例2:通过原型来优化之前的构造函数问题】
//之前将方法放在全局中不优化,现在通过原型来优化构造函数中的方法
Person.prototype.sayName = function fun(){
console.log('大家好,我是',this.name)
}
function Person(name,age){
//console.log('构造方法执行了')
this.name = name
this.age = age
}
var per1 = new Person('tom',18)
var per2 = new Person('jerry',18)
per1.sayName()
per2.sayName()
【原型案例3:原型的其它方法和特性】
var name = '全局的name'
function MyClass(){
}
MyClass.prototype.name = name
var m1 = new MyClass()
//m1.name = 'tom'
//1.使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true
console.log('name' in m1)
//2.【可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性】
//使用该方法只有当对象自身中含有属性时,才会返回true
console.log(m1.hasOwnProperty('name'))
/*
* 3.原型对象也是对象,所以它也有原型,
* 当我们使用一个对象的属性或方法时,会现在自身中寻找,
* 自身中如果有,则直接使用,
* 如果没有则去原型对象中寻找,如果原型对象中有,则使用,
* 如果没有则去原型的原型中寻找,直到找到Object对象的原型,
* Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined
*/
console.log(m1.hasOwnProperty('hasOwnProperty')) //false
console.log(m1.__proto__.hasOwnProperty('hasOwnProperty')) //false
console.log(m1.__proto__.__proto__.hasOwnProperty('hasOwnProperty'))//true
console.log(m1.__proto__.__proto__)
p68 toString
直接在页面中打印一个对象时,事实上是输出的对象的toString()方法的返回值
如果我们希望在输出对象时不输出[object Object],可以为对象添加一个toString()方法
function Person(name,age){
this.name = name
this.age = age
}
//修改Person原型的toString
Person.prototype.toString = function(){
return "Person[name="+this.name+",age="+this.age+"]";
};
var per = new Person('tom',18)
console.log(per.toString())
p69 垃圾回收(了解)
* 当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,
* 此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,
* 所以这种垃圾必须进行清理。
* 在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,
* 我们不需要也不能进行垃圾回收的操作
* 我们需要做的只是要【将不再使用的对象设置null即可】
p70-78 数组
* 数组(Array)
* 数组也是一个对象
* 它和我们普通对象功能类似,也是用来存储一些值的
* 不同的是普通对象是使用字符串作为属性名的,
* 而【数组使用数字来作为索引操作元素】
* 索引:
* 从0开始的整数就是索引
* 【数组的存储性能比普通对象要好,在开发中我们经常使用数组来存储一些数据】
数组的创建、取值、赋值
创建方式:通过new Array或者 字面量[]创建
var arr1 = new Array() //创建长度为0的数组
console.log(arr1)
var arr2 = new Array(1,2,3) //创建数组并放入三个元素
console.log(arr2)
var arr3 = new Array(10) //创建长度为10的数组,注意当长度为1时不是加入元素,而是初始化长度
console.log(arr3)
var arr4 = [1,2,3] //通过字面量创建数组
console.log(arr4)
修改或添加的语法:数组[索引] = 值
取值:数组[索引] 如果读取不存在的索引,他不会报错而是返回undefined
注意: 数组中的元素可以是任意的数据类型
数组的长度
* 可以使用length属性来获取数组的长度(元素的个数)
* 语法:数组.length
*
* 对于连续的数组,使用length可以获取到数组的长度(元素的个数)
* 对于非连续的数组,使用length会获取到数组的最大的索引+1
* 尽量不要创建非连续的数组
* 修改length
* 如果修改的length大于原长度,则多出部分会空出来
* 如果修改的length小于原长度,则多出的元素会被删除
* 向数组的最后一个位置添加元素
* 语法:数组[数组.length] = 值;
【数组demo】
//创建数组
var arr = new Array()
console.log(typeof arr) //object
console.log(Array.isArray(arr)) //true
//往数组中加元素
arr[0] = 1
arr[1] = 2
arr[2] = 1
console.log(arr)
//获取数组的值
console.log(arr[0]) //1
console.log(arr[3]) //undefined
//获取数组的长度
console.log(arr.length)
//修改lengh
//arr.length = 10
//向数组最后位置添加元素
arr[arr.length] = 3
arr[arr.length] = 4
arr[arr.length] = 5
console.log(arr,arr.length)
数组的方法
push
* 该方法可以向数组的末尾添加一个或多个元素,并[返回数组的新的长度]
* 可以将要添加的元素作为方法的参数传递,这样这些元素将会自动添加到数组的末尾
* 该方法会将数组新的长度作为返回值返回
【案例】
var arr = [1,2,3]
var rs = arr.push(4,5,6)
console.log(arr) //[1,2,3,4,5,6]
console.log(rs) //6
pop
该方法可以删除数组的最后一个元素,并将被删除的元素作为返回值返回
var arr = [1,2,3]
var rs = arr.pop()
console.log(arr) //[1,2]
console.log(rs) //3
unshift
* 向数组开头添加一个或多个元素,并返回新的数组长度
* 向前边插入元素以后,其他的元素索引会依次调整
【案例】
var arr = [1,2,3]
var rs = arr.unshift('a')
console.log(arr)// ['a', 1, 2, 3]
console.log(rs)//4
shift
删除数组的第一个元素,并将被删除的元素作为返回值返回
var arr = [1,2,3]
var rs = arr.shift()
console.log(arr)// [ 2, 3]
console.log(rs)//1
slice
* 可以用来从数组提取指定元素
* 【该方法不会改变元素数组,而是将截取到的元素封装到一个新数组中返回】
* 参数:
* 1.截取开始的位置的索引,包含开始索引
* 2.截取结束的位置的索引,不包含结束索引
* 第二个参数可以省略不写,此时会截取从开始索引往后的所有元素
* 索引可以传递一个负值,如果传递一个负值,则从后往前计算
* 1 倒数第一个
* 2 倒数第二个
【案例】
var arr = [1,2,3,4,5,6]
//var rs = arr.slice(1,3)//[2,3]
//var rs = arr.slice(1)
var rs = arr.slice(1,-2) //1指的是索引为1的 -2代表倒数第二个 所以结果是2,3,4
console.log(arr)
console.log(rs)
splice
* 可以用于删除数组中的指定元素
* 【使用splice()会影响到原数组,会将指定元素从原数组中删除】
* 并将被删除的元素作为返回值返回
* 参数:
* 第一个,表示开始位置的索引
* 第二个,表示删除的数量
* 第三个及以后。。
* 可以传递一些新的元素,这些元素将会自动插入到开始位置索引前边
【案例】
var arr = [1,2,3,4,5,6]
//var rs = arr.splice(0,3)
var rs = arr.splice(0,3,7,8,9)
console.log(arr)
console.log(rs)
concat
可以连接两个或多个数组,并将新的数组返回。该方法不会对原数组产生影响
参数:除了写数组也可以是元素
var arr = ["孙悟空","猪八戒","沙和尚"];
var arr2 = ["白骨精","玉兔精","蜘蛛精"];
var arr3 = ["二郎神","太上老君","玉皇大帝"];
var rs = arr.concat(arr2,arr3,'唐僧','哪吒')
console.log(arr)
console.log(rs)
join
* 该方法可以将数组转换为一个字符串
* 【该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回】
* 在join()中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符
* 如果不指定连接符,则默认使用,作为连接符
【案例】
var arr = ["孙悟空","猪八戒","沙和尚"];
//var rs = arr.join()
var rs = arr.join("-")
console.log(arr)
console.log(rs)
reverse
* 该方法用来反转数组(前边的去后边,后边的去前边),返回翻转之后的新数组
* 该方法会直接修改原数组
【案例】
var arr = ["孙悟空","猪八戒","沙和尚"];
var rs = arr.reverse()
console.log(arr == rs) //true
console.log(arr) //['沙和尚', '猪八戒', '孙悟空']
sort
* 可以用来对数组中的元素进行排序
* 也会影响原数组,默认会按照Unicode编码进行排序
* 即使对于纯数字的数组,使用sort()排序时,也会按照Unicode编码来排序,
* 所以对数字进排序时,可能会得到错误的结果。
*
* 我们可以自己来指定排序的规则
* 我们可以在sort()添加一个回调函数,来指定排序规则,
* 回调函数中需要定义两个形参,
* 浏览器将会分别使用数组中的元素作为实参去调用回调函数
* 使用哪个元素调用不确定,但是肯定的是在数组中a一定在b前边
* 浏览器会根据回调函数的返回值来决定元素的顺序,
* 如果返回一个大于0的值,则元素会交换位置
* 如果返回一个小于0的值,则元素位置不变
* 如果返回一个0,则认为两个元素相等,也不交换位置
*
* 如果需要升序排列,则返回 a-b
* 如果需要降序排列,则返回b-a
【案例】
var arr = [5,4,2,1,1,3,6,8,7];
//var rs = arr.sort() //升序
var rs = arr.sort(function(a,b){
return b-a
}) //降序
console.log(arr == rs) //true
console.log(arr)
数组的遍历
所谓的遍历数组,就是将数组中所有的元素都取出来
* 一般我们都是使用for循环去遍历数组,
* JS中还为我们提供了一个方法,用来遍历数组
* forEach()
* 这个方法只支持IE8以上的浏览器
* IE8及以下的浏览器均不支持该方法,所以如果需要兼容IE8,则不要使用forEach
* 还是使用for循环来遍历
* forEach()方法需要一个函数作为参数
* 像这种函数,由我们创建但是不由我们调用的,我们称为回调函数
* 数组中有几个元素函数就会执行几次,每次执行时,浏览器会将遍历到的元素
* 以实参的形式传递进来,我们可以来定义形参,来读取这些内容
* 浏览器会在回调函数中传递三个参数:
* 第一个参数,就是当前正在遍历的元素
* 第二个参数,就是当前正在遍历的元素的索引
* 第三个参数,就是正在遍历的数组
【例如】
var arr = [1,2,3,4,5]
for(var i=0;i<arr.length;i++){
console.log(arr[i])
}
console.log('----------')
arr.forEach(function(v,i,arr){
console.log(i,v,arr)
})
p79 call和apply
* call()和apply()
* 这两个方法都是函数对象的方法,需要通过函数对象来调用
* 当对函数调用call()和apply()都会调用函数执行
* 在调用call()和apply()可以将一个对象指定为第一个参数
* 此时这个对象将会成为函数执行时的this
* call()方法可以将实参在对象之后依次传递
* apply()方法需要将实参封装到一个数组中统一传递
*
* this的情况:
* 1.以函数形式调用时,this永远都是window
* 2.以方法的形式调用时,this是调用方法的对象
* 3.以构造函数的形式调用时,this是新创建的那个对象
* 4.使用call和apply调用时,this是指定的那个对象
【案例】
function fun(a,b) {
console.log("a = "+a);
console.log("b = "+b);
console.log(this);
}
var obj = {
name: "我是obj",
sayName:function(){
console.log(this.name);
}
};
//fun() //以函数调用 this指window
//obj.sayName() //以方法调用this指调用方法的对象
//fun.call() //this指window
//fun.call(obj) //this指obj
//fun.apply()//this指window
//fun.apply(obj)//this指obj
//call和apply的不同点: apply的参数需要放到数组中
//fun.call(obj,1,2) //1,2为参数
//fun.apply(obj,[3,4]) //3,4为参数
p80 arguments
* 在调用函数时,浏览器每次都会传递进两个隐含的参数:
* 1.函数的上下文对象 this
* 2.封装实参的对象 arguments
* arguments是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度
* 在调用函数时,我们所传递的实参都会在arguments中保存
* arguments.length可以用来获取实参的长度
* 我们即使不定义形参,也可以通过arguments来使用实参,
* 只不过比较麻烦
* arguments[0] 表示第一个实参
* arguments[1] 表示第二个实参 。。。
* 它里边有一个属性叫做callee,
* 这个属性对应一个函数对象,就是当前正在指向的函数的对象
【案例】
function fun(){
console.log(arguments.callee == fun) //true
console.log(Array.isArray(arguments))//false
console.log(arguments.length)//3
console.log(arguments[1])//2
}
fun(1,2,3)
p81 Date对象
在JS中使用Date对象来表示一个时间
创建Date对象的方式
var d = new Date();//默认为当前时间
var d2 = new Date("2/18/2011 11:10:30"); //日期的格式 月份/日/年 时:分:秒
var d3 = new Date(1655436727888) //通过时间戳创建
Date对象的一些方法
* getFullYear()
* 获取当前日期对象的年份
* getMonth()
* 获取当前时间对象的月份
* 会返回一个0-11的值
* 0 表示1月
* 1 表示2月
* 11 表示12月
* getDate()
* 获取当前日期对象是几日
* getDay()
* 获取当前日期对象时周几
* 会返回一个0-6的值
* 0 表示周日
* 1表示周一
* 。。。
* getTime()
* 获取当前日期对象的时间戳
* 时间戳,指的是从格林威治标准时间的1970年1月1日,0时0分0秒
* 到当前日期所花费的毫秒数(1秒 = 1000毫秒)
* 计算机底层在保存时间时使用都是时间戳
【案例】
var d = new Date()
var year = d.getFullYear()
var month = d.getMonth()+1
var date = d.getDate()
var day = d.getDay()==0?'日':d.getDay()
var hours = d.getHours()
var minutes = d.getMinutes()
var seconds = d.getSeconds()
console.log(year+"-"+month+"-"+date+"-星期"+day+" "+hours+":"+minutes+":"+seconds)
//获取时间戳
var t = d.getTime()
console.log(t)
//获取当前时间的时间戳
console.log(Date.now())
p82 Math
Math和其他的对象不同,它不是一个构造函数,
* 它属于一个工具类不用创建对象,它里边封装了数学运算相关的属性和方法
* 比如
* Math.PI 表示的圆周率
* Math.abs()可以用来计算一个数的绝对值
* Math.ceil()
* 可以对一个数进行向上取整,小数位只有有值就自动进1
* Math.floor()
* 可以对一个数进行向下取整,小数部分会被舍掉
* Math.round()
* 可以对一个数进行四舍五入取整
* Math.random()
* 可以用来生成一个0-1之间的随机数
* 生成一个0-10的随机数
* 生成一个0-x之间的随机数
* Math.round(Math.random()*x)
* 生成一个1-10 Math.round(Math.random()*9)+1
* 生成一个x-y之间的随机数
* Math.round(Math.random()*(y-x)+x)
* Math.max() 可以获取多个数中的最大值
* Math.min() 可以获取多个数中的最小值
* Math.pow(x,y)
* 返回x的y次幂
* Math.sqrt()
* 用于对一个数进行开方运算
【案例】
console.log(Math.PI) //圆周率
console.log(Math.abs(-1))//绝对值
console.log(Math.ceil(1.2))//向上取整
console.log(Math.floor(1.2))//向下取整
console.log(Math.round(1.5))//四舍五入
console.log(Math.round(Math.random()*9+1)) //获取1-10的随机数
console.log(Math.max(10,45,30,100))//最大值
console.log(Math.min(10,45,30,100))//最小值
p83 包装类
* 基本数据类型
* String Number Boolean Null Undefined
* 引用数据类型
* Object
*
* 在JS中为我们提供了三个包装类,通过这三个包装类可以将基本数据类型的数据转换为对象
* String()
* 可以将基本数据类型字符串转换为String对象
* Number()
* 可以将基本数据类型的数字转换为Number对象
* Boolean()
* 可以将基本数据类型的布尔值转换为Boolean对象
* 但是注意:我们在【实际应用中不会使用基本数据类型的对象】,
* 如果使用基本数据类型的对象,在做一些比较时可能会带来一些不可预期的结果
方法和属性只能添加给对象,不能添加给基本数据类型
* 当我们对一些基本数据类型的值去调用属性和方法时,
* 浏览器会临时使用包装类将其转换为对象,然后在调用对象的属性和方法
* 调用完以后,在将其转换为基本数据类型
【案例】
var num = new Number(1)
console.log(num == 1) //true
var bool = new Boolean(false)
console.log(bool) //boolean对象
if(bool){//非空就是真,会运行
console.log('我运行了')
}
var str = new String('abc')
str.hello = 'def'
console.log(str.hello)//def
var s = '123'
s.hello = '456'
console.log(s.hello) //undefined
p84 String类
* 在底层字符串是以字符数组的形式保存的
* length属性
* 可以用来获取字符串的长度
* charAt()
* 可以返回字符串中指定位置的字符
* 根据索引获取指定的字符
* concat()
* 可以用来连接两个或多个字符串
* 作用和+一样
* indexof()
* 该方法可以检索一个字符串中是否含有指定内容
* 如果字符串中含有该内容,则会返回其第一次出现的索引
* 如果没有找到指定的内容,则返回-1
* 可以指定一个第二个参数,指定开始查找的位置
*
* lastIndexOf();
* 该方法的用法和indexOf()一样,
* 不同的是indexOf是从前往后找,
* 而lastIndexOf是从后往前找
* 也可以指定开始查找的位置
* slice()
* 可以从字符串中截取指定的内容
* 【不会影响原字符串,而是将截取到内容返回】
* 参数:
* 第一个,开始位置的索引(包括开始位置)
* 第二个,结束位置的索引(不包括结束位置)
* 【如果省略第二个参数,则会截取到后边所有的】
* 也可以传递一个负数作为参数,负数的话将会从后边计算
* substring()
* 可以用来截取一个字符串,和数组的slice()类似
* 参数:
* 第一个:开始截取位置的索引(包括开始位置)
* 第二个:结束位置的索引(不包括结束位置)
* 不同的是这个方法不能接受负值作为参数,
* 如果传递了一个负值,则默认使用0
* 而且他还自动调整参数的位置,如果第二个参数小于第一个,则自动交换
* substr()
* 用来截取字符串,和数组的splice类似
* 参数:
* 1.截取开始位置的索引
* 2.截取的长度
* split()
* 可以将一个字符串拆分为一个数组
* 参数:
* 需要一个字符串作为参数,将会根据该字符串去拆分数组
* 【如果传递一个空串作为参数,则会将每个字符都拆分为数组中的一个元素】
* toUpperCase()
* 将一个字符串转换为大写并返回
* toLowerCase()
* 将一个字符串转换为小写并返回
【案例】
var str = 'a,b,c'
//var rs = str.concat('def','ghi')
//var rs = str.slice(0,2)
//var rs = str.substring(2,-1)
var rs = str.substr(0,3)
//var rs = str.split(",")
console.log(rs)
p85-p90 正则
了解一下,要用的时候再来看就行
* 正则表达式用于定义一些字符串的规则,
* 计算机可以根据正则表达式,来检查一个字符串是否符合规则,
* 获取将字符串中符合规则的内容提取出来
* 创建正则表达式的对象
* 语法:
* var 变量 = new RegExp("正则表达式","匹配模式");
* 使用typeof检查正则对象,会返回object
* var reg = new RegExp("a"); 这个正则表达式可以来检查一个字符串中是否含有a
* 在构造函数中可以传递一个匹配模式作为第二个参数,
* 可以是
* i 忽略大小写
* g 全局匹配模式
* 正则表达式的方法:
* test()
* 使用这个方法可以用来检查一个字符串是否符合正则表达式的规则,
* 如果符合则返回true,否则返回false
* 使用字面量来创建正则表达式
* 语法:var 变量 = /正则表达式/匹配模式
* 使用字面量的方式创建更加简单
* 使用构造函数创建更加灵活
* 使用 | 表示或者的意思
* []里的内容也是或的关系
* [ab] == a|b
* [a-z] 任意小写字母
* [A-Z] 任意大写字母
* [A-z] 任意字母
* [0-9] 任意数字
* 量词
* 通过量词可以设置一个内容出现的次数
* 量词只对它前边的一个内容起作用
* {n} 正好出现n次
* {m,n} 出现m-n次
* {m,} m次以上
* + 至少一个,相当于{1,}
* * 0个或多个,相当于{0,}
* ? 0个或1个,相当于{0,1}
* ^ 表示开头
* $ 表示结尾
* 【如果在正则表达式中同时使用^ $则要求字符串必须完全符合正则表达式】
* 检查一个字符串中是否含有 .
* . 表示任意字符
* 在正则表达式中使用\作为转义字符
* \. 来表示.
* \\ 表示\
*
* 注意:使用构造函数时,由于它的参数是一个字符串,而\是字符串中转义字符,
* 如果要使用\则需要使用\\来代替
* \w
* 任意字母、数字、_ [A-z0-9_]
* \W
* 除了字母、数字、_ [^A-z0-9_]
* \d
* 任意的数字 [0-9]
* \D
* 除了数字 [^0-9]
* \s
* 空格
* \S
* 除了空格
* \b
* 单词边界
* \B
* 除了单词边界
* 字符串的split()
* 可以将一个字符串拆分为一个数组
* 方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串
* 这个方法即使不指定全局匹配,也会全都插分
* 字符串的search()
* 可以搜索字符串中是否含有指定内容
* 如果搜索到指定内容,则会返回第一次出现的索引,如果没有搜索到返回-1
* 它可以接受一个正则表达式作为参数,然后会根据正则表达式去检索字符串
* 【search()只会查找第一个,即使设置全局匹配也没用】
* 字符串的match()
* 可以根据正则表达式,从一个字符串中将符合条件的内容提取出来
* 默认情况下我们的match只会找到第一个符合要求的内容,找到以后就停止检索
* 我们可以设置正则表达式为全局匹配模式,这样就会匹配到所有的内容
* 可以为一个正则表达式设置多个匹配模式,且顺序无所谓
* match()会将匹配到的内容封装到一个数组中返回,即使只查询到一个结果
* 字符串的replace()
* 可以将字符串中指定内容替换为新的内容
* 参数:
* 1.被替换的内容,可以接受一个正则表达式作为参数
* 2.新的内容
* 默认只会替换第一个
【入门案例】
//var reg = new RegExp('a')
//检查是否包含a,忽略大小写
//var reg = new RegExp('a','i')
//使用字面量来创建正则
//var reg = /a/i
//检查是否包含a或b,忽略大小写
//var reg = /a|b/i
// var reg = /[ab]/i
// console.log(reg.test('ac'))
//console.log(typeof reg)
//a{3}b
var reg = /^a{3}ab$/
console.log(reg.test('aaaab'))
p91-140
dom
DOM,全称Document Object Model文档对象模型。文档表示的就是整个的HTML网页文档
dom查询
- 获取整个文档: document
- 获取body: document.body
- 根据id获取节点: document.getElementById()
- 根据标签名获取:document.getElementsByTagName
- 根据类名获取: document.getElementsByClassName
- 使用H5新增选择器查询,返回第一个:document.querySelector()
- 使用H5新增选择器查询,返回所有结果:document.querySelectorAll()
bom
* BOM
* 浏览器对象模型
* BOM可以使我们通过JS来操作浏览器
* 在BOM中为我们提供了一组对象,用来完成对浏览器的操作
* BOM对象
* Window
* 代表的是整个浏览器的窗口,同时window也是网页中的全局对象
* Navigator
* 代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器
* Location
* 代表当前浏览器的地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面
* History
* 代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录
* 由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页
* 而且该操作只在当次访问时有效
* Screen
* 代表用户的屏幕的信息,通过该对象可以获取到用户的显示器的相关的信息
*
*
* 这些【BOM对象在浏览器中都是作为window对象的属性保存的】,
* 可以通过window对象来使用,也可以直接使用
navigator
* Navigator
* 代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器
* 由于历史原因,Navigator对象中的大部分属性都已经不能帮助我们识别浏览器了
* 【一般我们只会使用userAgent来判断浏览器的信息】,
* userAgent是一个字符串,这个字符串中包含有用来描述浏览器信息的内容,
* 不同的浏览器会有不同的userAgent
例如:
var ua = navigator.userAgent;
console.log(ua);
if(/firefox/i.test(ua)){
alert("你是火狐!!!");
}else if(/chrome/i.test(ua)){
alert("你是Chrome");
}else if(/msie/i.test(ua)){
alert("你是IE浏览器~~~");
}else if("ActiveXObject" in window){
alert("你是IE11,枪毙了你~~~");
}
history
/*
* length
* 属性,可以获取到当成访问的链接数量
*/
//alert(history.length);
/*
* back()
* 可以用来回退到上一个页面,作用和浏览器的回退按钮一样
*/
//history.back();
/*
* forward()
* 可以跳转下一个页面,作用和浏览器的前进按钮一样
*/
//history.forward();
/*
* go() 推荐这个
* 可以用来跳转到指定的页面
* 它需要一个整数作为参数
* 1:表示向前跳转一个页面 相当于forward()
* 2:表示向前跳转两个页面
* 1:表示向后跳转一个页面
* 2:表示向后跳转两个页面
*/
history.go(-2);
location
该对象中封装了浏览器的地址栏的信息
//如果直接打印location,则可以获取到地址栏的信息(当前页面的完整路径)
//alert(location);
/*
* 如果直接将location属性修改为一个完整的路径,或相对路径
* 则我们页面会自动跳转到该路径,并且会生成相应的历史记录
*/
//location = "http://www.baidu.com";
//location = "01.BOM.html";
/*
* assign()
* 用来跳转到其他的页面,作用和直接修改location一样
*/
//location.assign("http://www.baidu.com");
/*
* reload()
* 用于重新加载当前页面,作用和刷新按钮一样
* 如果在方法中传递一个true,作为参数,则会强制清空缓存刷新页面
*/
//location.reload(true);
/*
* replace()
* 可以使用一个新的页面替换当前页面,调用完毕也会跳转页面
* 不会生成历史记录,不能使用回退按钮回退
*/
location.replace("01.BOM.html");
事件
事件的冒泡
* 所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
* 在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡
事件的委派
* 我们希望,只绑定一次事件,即可应用到多个的元素上,即使元素是后添加的
* 我们可以尝试将其绑定给元素的共同的祖先元素
*
* 事件的委派
* 指【将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素
* 从而通过祖先元素的响应函数来处理事件。】
* 事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
* target
* event中的target表示的触发事件的对象,比如按钮或链接
事件的传播
* 事件的传播
* 关于事件的传播网景公司和微软公司有不同的理解
* 微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,
* 然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行。
* 网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,
* 然后在向内传播给后代元素
* W3C综合了两个公司的方案,将事件传播分成了三个阶段
* 1.捕获阶段
* 在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
* 2.目标阶段
* 事件捕获到目标元素,捕获结束开始在目标元素上触发事件
* 3.冒泡阶段
* 事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件
*
* 如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true
* 一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false
*
* IE8及以下的浏览器中没有捕获阶段
事件的绑定
* 使用 对象.事件 = 函数 的形式绑定响应函数,
* 它只能同时为一个元素的一个事件绑定一个响应函数,
* 不能绑定多个,如果绑定了多个,则后边会覆盖掉前边的
* addEventListener()
* 通过这个方法也可以为元素绑定响应函数
* 参数:
* 1.事件的字符串,不要on
* 2.回调函数,当事件触发时该函数会被调用
* 3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false
*
* 使用addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数,
* 这样当事件被触发时,响应函数将会按照函数的绑定顺序执行
*
* 这个方法不支持IE8及以下的浏览器
json
* JSON
* JS中的对象只有JS自己认识,其他的语言都不认识
* JSON就是一个特殊格式的字符串,这个字符串可以被任意的语言所识别,
* 并且可以转换为任意语言中的对象,JSON在开发中主要用来数据的交互
* JSON
* JavaScript Object Notation JS对象表示法
* JSON和JS对象的格式一样,只不过【JSON字符串中的属性名必须加双引号】
* 其他的和JS语法一致
* JSON分类:
* 1.对象 {}
* 2.数组 []
*
* JSON中允许的值:
* 1.字符串
* 2.数值
* 3.布尔值
* 4.null
* 5.对象
* 6.数组
* 将JSON字符串转换为JS中的对象
* 在JS中,为我们提供了一个工具类,就叫JSON
* 这个对象可以帮助我们将一个JSON转换为JS对象,也可以将一个JS对象转换为JSON
* json --> js对象
* JSON.parse()
* 可以将以JSON字符串转换为js对象
* 它需要一个JSON字符串作为参数,会将该字符串转换为JS对象并返回
* JS对象 ---> JSON
* JSON.stringify()
* 可以将一个JS对象转换为JSON字符串
* 需要一个js对象作为参数,会返回一个JSON字符串
* eval()
* 这个函数可以用来执行一段字符串形式的JS代码,并将执行结果返回
* 如果使用eval()执行的字符串中含有{},它会将{}当成是代码块
* 如果不希望将其当成代码块解析,则需要在字符串前后各加一个()
*
* eval()这个函数的功能很强大,可以直接执行一个字符串中的js代码,
* 但是在开发中尽量不要使用,首先它的执行性能比较差,然后它还具有安全隐患