目录
复习补充:
BOM浏览器对象模型(细见主页web api(js进阶)/js基础)
window对象:navigator、location、history、screen(屏幕相关属性)、document
window事件:load、DOMContentLoaded、beforeunload、dragover(拖曳)、drop(鼠标放开时触发)
classList:add、remove、toggle、contains
自定义属性:data-xxx
1.1 变量
var定义的变量相当于给window添加属性,函数相当于给window添加方法
一个变量只定义不赋值 undefined
const声明的变量不准改变,称为常量,定义的常量必须初始化赋值,其它与let无区别
未定义直接赋值的变量为全局变量
2.1 作用域
变量的使用范围
全局作用域:函数外面的作用域,
全局变量:在全局作用域下定义的变量,可以在任意地方使用
局部作用域:函数内部的作用域,
局部变量:在局部作用域下定义的变量,只能在当前函数中使用
块级作用域:ES6中 用{}包裹的代码,类似于局部作用域
尽量少使用全局变量,易报错(即变量污染)
ES6中将parseInt,parseFloat归到Number构造函数中
2.2 作用域链
是否声明变量,若当期那作用域没有这个变量,就会去上级作用域查找
由作用域串联起来的链状结构
let num=1;
function f1(){
let num=2
function f2(){
console.log(num) //打印2
}
f2()
}
f1()
let num=1
function f1(){
num=2;
function f2(){
num=3;
}
f2();
}
f1();
console.log(num) //打印3
let num=1;
function f1(){
let num=2;
function f2(){
num=3;
}
f2();
}
f1();
console.log(num) //打印1
2.3 闭包
一个作用域有权访问另一个作用域的局部变量
作用:延伸变量的使用周期,使用范围
缺点:过多使用易造成内存泄漏
function father(){
let num=66;
//闭包
return function(){
console.log(num)
}
}
let o=father();
o();
2.4 预解析
2.41 变量
会把代码中声明的变量,提前解析到当前(变量的提升)作用域最前面,但是只定义不赋值
let定义的变量不存在变量提升
2.42 函数
会把代码中具有名字的函数提前解析,解析到当前作用域最前面,指定义,不调用
console.log(n); //打印undefined
fn(); //打印undefined
var n=3;
function fn(){
console.log(n);
var n=6;
}
//参数默认值
function fn(uname='阿飞',age=22){
//形参没有接受实参,那么形参是undefined
console.log(`我叫${uname}今年${age}岁`);
}
fn('赵云',21);
2.5 动态参数 arguments
arguments用于接受所有实参
function fun(){
for(let i=0;i<arguments.length;i++){
console.log(arguments[i]);
}
}
fun(1,2,3,'a','b','c',4,5,6,7,8,9);
2.6 剩余参数
语法符号:...,置于最末函数形参之前,用于获取多余的实参
function fun(a,b,...c){ //把所有剩余的值给c
console.log(a,b,c);
}
fun(1,2,3,4,5,6)
2.7 箭头函数
2.71 基本形式
let fn=(a,b)=>{
return a+b;
}
let re=fn(1,2);
console.log(re);
2.72 箭头函数的其它形式
//若只有一个参数,可以省略小括号
let fn=a=>{
return a*a;
}
console.log(fn(3));
//若函数体只有一行代码,可以省略大括号
//若大括号省略,会自动返回结果,不需要写return
let fn1=a=>a*a;
console.log(fn1(6));
2.73 箭头函数的使用
window.setInterval(function(){
console.log('函数体');
},1000);
箭头函数不存在预解析,必须先定义再调用
箭头函数中不存在arguments
箭头函数认为不存在this,箭头中的this指向箭头函数所在作用域的this
事件处理函数中有this不要用箭头函数
<input type="button" value="点击">
<script>
let btn=document.querySelector('input');
btn.addEventListener('click',()=>{
btn.style.background='red'
})
</script>
2.8 递归练习
2.81 求6的阶层
function digui(n){
if(n==1){
return 1;
}
return n*digui(n-1);
}
console.log(digui(6))
2.82 求斐波那契数列:兔子序列
1、1、2、3、5、8、13、21...其两个数相加等于第三个数
function fb(n){
if(n==1||n==2){
return 1;
}
return fb(n-1)+fb(n-2);
}
console.log(fb(6));
2.9 结构赋值
2.91 数组解构
//一一对应 变量的顺序对应数组单元值的位置一次进行赋值操作
let [a,b,c,d,e,f]=['张飞','赵云','关羽','张辽']
console.log(a,b,c,d,e,f);
//变量多值少
let [a,b,c,d,e,f,g,h]=['张飞','赵云','关羽','张辽']
console.log(a,b,c,d,e,f,g,h) //剩余的变量e,f,g,h值为undefined
//变量少值多
let [a,b,c]=['张飞','赵云','关羽','张辽']
console.log(a,b,c); //多的值张辽不取
//按需取值
let [,a,b,c]=['张飞','关羽','赵云','张辽']
console.log(a,b,c) //a:关羽,b:赵云,c:张辽
//剩余值
let [,a,b,...c]=['张飞','赵云','关羽','张辽','许褚']
console.log(a,b,c); //a:赵云 b:关羽 c:[张辽,许褚]
//复杂情况
let [,,a,b,[,c,d]]=['张飞','赵云','关羽','张辽',['林冲','鲁智深','武松','宋老板']]
console.log(a,b,c,d); //a:关羽 b:张辽 c:鲁智深 d:武松
2.92 对象解构
//取谁拿谁
let {uname,sex}={
uname:'张三丰',
age:22,
sex:'男',
score:99,
index:6,
}
console.log(uname,sex); //张三丰 男
let不能重复定义同一个变量,若遇到已经定义可用:改值
let uname='阿飞'
//用冒号改值
let {uname:userName,sex}={
uname:'张三丰',
age:22,
sex:'男',
score:99,
index:6,
}
console.log(userName,sex); //张三丰 男
对象里面套对象
let {dog:{uname}}={
uname:'张三丰',
dog:{
uname:'小狗子',
age:1,
},
cat:{
uname:'小猫咪'
},
age:22,
sex:'男',
score:99,
index:6,
}
console.log(uname) //张三丰
function person({uname,age,sex}){
console.log(`我叫${uname}今年${age}岁是${sex}性`)
}
person({uname:'阿飞',age:22,sex:'男'})
3.1 面向对象
面向过程:步骤过程为准,强调事件的流程顺序
面相对象:以对象为核心,强调事件的角色、主体
3.11 字面量创建对象
let obj={
//属性名:属性值
//键值对
//成员
uname:'张三丰',
age:22,
sex:'男',
taiji:function(){
console.log('打太极');
}
}
console.log(obj.uname);
console.log(obj['age'])
obj.taiji();
for(let key in obj){
console.log(obj[key]); //uname age sex taiji函数
}
3.12 构造函数
构造函数一般用于和new搭配使用,创建对象
内置构造函数:Object,创建对象,
let obj=new Object();
//添加东西
obj.uname='阿飞';
obj.age=22;
obj.xiao=function(){
console.log('方法');
};
console.log(obj);
Object.keys(obj); //获取对象的所有键
Object.values(obj); //获取对象的所有值
如果构造函数不需要参数,那么可以省略小括号
let obj=new Object;
obj.uname='张飞';
console.log(obj); //{uname:张飞}
正则构造函数:let reg=new RegExp(/abc/);
Array构造函数
let ary=new Array(1,2,3);
console.log(ary);
任何一个属性都是Array构造函数的实例化对象
常用方法:
concat():用于拼接为新数组
let arr=[1,2,3];
let arr1=['a','b','c'];
let reArr=arr.concat(arr1);
console.log(reArr);
join():用于连接数组的每个元素成为字符串
let arr=['a','b','c'];
let str=arr.join('');
console.log(str); //abc
reverse():翻转数组顺序
indexOf():查找某个元素在数组中首次出现的索引位置,找不到就是返回-1
lastIndexOf():查找某个元素在数组中尾次出现的索引位置,找不到就返回-1
Array.from(伪数组):把伪数组转换为真数组必须有length属性
find():用于查找首次出现满足条件的值,并返回
findIndex():用于查找首次出现的满足条件的值,并返回所在索引值
some():有一个满足返回true
every():全部满足返回true
filter():满足条件的元素放到新数组返回
map():把回调函数结果放到新数组里面
forEach():用于遍历数组
let arr=['a','b','c','d','e'];
arr.forEach(function(item,index,o){
//第一个参数:代表数组的每一项(每个元素)
//第二个参数:代表数组的每一项的索引值
//第三个参数:代表当前数组本身
console.log(item,index,o);
})
arr.forEach(item=>{
console.log(`姓名:${item.uname},年龄${item.age},性别${item.sex}`);
});
sort():排序 isArray():判断一个值是否是数组
//sort:排序
let arr=[3,16,22,66,123,99];
//正序排列:
let re=arr.sort(function(a,b){return a-b;});
//倒序排列
let re1=arr.sort(function(a,b){return b-a;});
console.log(re); //3 16 22 66 99 123
console.log(re1);//123 99 66 22 16 3
3.13 自定义构造函数
function Person(uname,age,sex){
//设置属性
this.uname=uname;
this.age=age;
this.sex=sex;
this.eat=function(){
console.log('吃饭');
}
}
//实例化对象
let o=new Person('张三丰',22,'男');
console.log(o);
3.14 constructor、instanceof
function A(){}
function B(){}
let obj=new B();
//instanceof:用于判断一个对象是否是另一个构造函数的实例对象
//对象 instanseof 构造函数
console.log(obj instanceof B); //true
//constructor:指回构造函数本身
console.log(obj.constructor); //函数B
3.15 静态成员、实例成员
在构造函数身上直接添加的成员,称为静态成员(静态属性静态方法)
静态成员只能由构造函数访问
构造函数内部为实例对象准备的成员,称为实例成员
实例成员只能由实例对象访问
3.16 数据传递
变量传递给另一个变量
值传递:会把数据复制一份传递(简单类型)
引用类型:把数据地址复制一份(引用类型)
3.17 练习题
let n=10;
let m=11;
function fn(a,b){
a=100;
b=200;
}
fn(n,m);
console.log(n,m); //10 11
let o={uname:'张三丰',age:22,sex:'男'};
function fun(obj){
obj.uname='李寻欢';
}
fun(o);
console.log(o); //{uname:'李寻欢',age:22,'男'}
let arr=['a','b','c','d','a']
let newArr=[];
//遍历arr的每一个元素,在newArr中查找,若找不到就把这个值添加进去
for(let i=0;i<arr.length;i++){
if(newArr.indexOf(arr[i])==-1) newArr.push(arr[i]);
}
console.log(newArr);
4.1 字符串
4.11 常用方法
trim:用于去除字符串两端空白 str.trim()
split:分割字符串
toLowerCase:把字母转成小写
toUpperCase:把字母转成大写
indexOf:首次出现的索引值
lastIndexOf:尾次出现的索引值
slice(start,end):从索引值为start的位置截取字符串到end索引位置
如果只有一个参数,会从该参数索引值截取到最后
substring(start,end):从索引值为start的位置截取字符串到end索引位置
4.12 练习
let str='猫猫很可爱,超级喜欢,要有一只属于自己的';
let startIndex=str.indexOf('喜');
let endIndex=str.indexOf('属');
let re=str.substring(startIndex,endIndex+1);
console.log(re);
4.2 公共方法
toString() undefined和null不可使用
let num=123;
console.log(num.toString()); //将123转换为字符串
valueOf:获取原始值
let num=new Number(666);
console.log(num.valueOf());
4.3 原型对象
构造函数的一个属性 :构造函数.prototype
作用:共享方法:节省内存,当实例对象找不到成员的时候会找原型对象上的成员
构造函数.prototype.constructor:用于指回构造函数本身
每一个对象都有一个属性:__proto__
作用:用于指向原型对象
function Person(){}
let obj=new Person()
obj.__proto__=Person.prototype
原型链:由原型构成的链状
4.4 继承
//构造函数
function Person(){
this.head=1;
this.eyes=2;
this.legs=2;
this.say=function(){console.log('say');}
this.eat=function(){console.log('eat');}
}
function Chinese(){
this.language='汉语';
this.skin='yellow';
}
//继承:
//把对象赋值给原型对象
Chinese.prototype=new Person();
//指回构造函数本身
Chinese.prototype.constructor=Chinese;
//实例对象
let c1=new Chinese();
console.log(c1);
5.1 严格模式
js开启严格模式 "use strict"
放在全局开头,全局开启严格模式
放在函数开头,代表这个函数内部严格
1、变量必须先定义再使用
2、普通函数中的this指向undefined
3、函数的形参不准重名
5.2 改变函数中的this值
函数.call(this指向的参数,剩下的参数给函数参数准备)
function fun(a,b){
console.log(this,a,b)//{uname:'张三丰',age:22} 1 2
}
let obj={uname:'张三丰',age:22};
fun.call(obj,1,2)
函数.apply(this指向的参数,[剩下的参数])
function fn(a,b){
console.log(this,a,b); //{uname:'阿飞'} 111 222
}
let obj={uname:'阿飞'};
fn.apply(obj,[111,222]);
let arr=[23,66,33,19,4,7];
let re=Math.max(...arr);
console.log(re);//66
函数.band()只会改变函数指向不会让函数立即执行
let btn=document.querySelector('input');
btn.addEventListener('click',function(){
//禁用按钮
this.disabled=true;
//开启定时器
window.setTimeout(function(){
this.disabled=false;
}.bind(this),5000);
})
5.3 类
5.31 创建类,实例成员和静态成员
class Person{
//实例成员
uname='张三丰';
age=23;
sex='男';
say(){
console.log('方法');
}
hi(){
console.log('hi');
}
}
//实例化
let obj=new Person();
console.log(obj.uname);//张三丰
obj.say();//方法
静态成员添加static
class Person{
//静态成员
static language='汉语';
static skin='yellow';
static eat(){
console.log('吃')
}
}
let obj=new Person();
console.log(obj)
5.32 constructor
类中固定的方法名
方法在实例化时立即执行
接收实例化时传入参数
并非是类中必须要存在的方法
class Person{
constructor(uname,age){
this.uname=uname;
this.age=age;
}
say(){
console.log('说话');
}
}
let obj=new Person('张三丰',22);
console.log(obj); //Person{uname:"张三丰" age:22 __proto__}
5.33 extends
用于类的继承
class Father{
constructor(uname,age){
this.uname=uname;
this.age=age;
}
happy(){
console.log('心情要美');
}
}
//继承
class Son extends Father{}
let obj=new Son('人',2);
console.log(obj); //Son{uname:"人" age:2}
5.34 super
如果子类有自己的constructor,必须通过super才可以调用父类的方法
class Father{
constructor(uname,age){
this.uname=uname;
this.age=age;
}
happy(){
console.log('心情要美');
}
}
//继承
class Son extends Father{
constructor(uname,age,score){
//先调用super,再设定自己的成员
super(uname,age)
this.score=score;
}
happy(){
//就近原则 如果要调用父类里面的方法,用super
super.happy();
console.log('嘻');
}
}
let obj=new Son('人',2,9);
console.log(obj);
//就近原则
obj.happy();
5.35 类的本质
函数
//es6之前
function Person(){}
let obj=new Person();
//es6
class Person{}
let obj=new Person();
5.4 拷贝
5.41 浅拷贝与深拷贝
只拷贝对象外面一层的简单数据,复杂类型无法拷贝
let obj={
uname:'张三丰',
age:22,
sex:'男',
color:['red','blue','yellow'],
message:{
score:99,
index:6,
}
}
let newObj={}
//浅拷贝
//方法一:
Object.assign(newObj,obj);
//遍历
//方法二:
for(let key in obj){
newObj[key]=obj[key]
}
obj.message.index=666;
console.log(obj,newObj);
//深拷贝
function kaobei(newObj,obj){
for(let key in obj){
if(obj[key] instanceof Array){
newObj[key]=[];
kaobei(newObj[key],obj[key]);
}else if(obj[key] instanceof Object){
newObj[key]={};
kaobei(newObj[key],obj[key])
}else{
newObj[key]=obj[key];
}
}
}
kaobei(newObj,obj);
console.log(obj,newObj);