JS笔记(含ES6)
面向对象
特征:封装性、继承性、多态性。
优点:易维护、易复用、易扩展等。可设计出低耦合系统,更灵活、更易于维护。
缺点:性能比面向过程低。
————————
ES5
1.类和对象
面向对象的思维特点:1.抽取(抽象)对象共用的属性和行为组织(封装)成一个类(模板)。
2.对类进行实例化、获取类的对象。
对象:一组无序的相关属性和方法的集合,所有事物都是对象。
对象是由属性和方法组成的:属性:事物的特征,在对象中用属性来表示(常用名词)
方法:事物的行为,在对象中用方法来表示(常用动词)
类:可以用class关键字声明一个类,之后以这个类来实例化对象。
类抽象了对象的公共部分,泛指某一大类(class)
对象特指某一个,通过实例化一个具体的对象。
创建类:
class classname{ }
创建实例:
var xx=new classname(uname);
类constructor构造函数,只要有new就自动调用这个函数,构造函数不需加function
class classname{
constructor(uname){
this.uname=uname;
}
}
类中添加方法
class classname{
constructor(uname){
this.uname=uname;
}//全都不要逗号分隔
f(){//类中函数也不需要加function
//函数内容
}
}
类的继承
父类
calss Father{
constructor(){
特征:封装性、继承性、多态性。
优点:易维护、易复用、易扩展等。可设计出低耦合系统,更灵活、更易于维护。
缺点:性能比面向过程低。
————————
ES5
1.类和对象
面向对象的思维特点:1.抽取(抽象)对象共用的属性和行为组织(封装)成一个类(模板)。
2.对类进行实例化、获取类的对象。
对象:一组无序的相关属性和方法的集合,所有事物都是对象。
对象是由属性和方法组成的:属性:事物的特征,在对象中用属性来表示(常用名词)
方法:事物的行为,在对象中用方法来表示(常用动词)
类:可以用class关键字声明一个类,之后以这个类来实例化对象。
类抽象了对象的公共部分,泛指某一大类(class)
对象特指某一个,通过实例化一个具体的对象。
创建类:
class classname{ }
创建实例:
var xx=new classname(uname);
类constructor构造函数,只要有new就自动调用这个函数,构造函数不需加function
class classname{
constructor(uname){
this.uname=uname;
}
}
类中添加方法
class classname{
constructor(uname){
this.uname=uname;
}//全都不要逗号分隔
f(){//类中函数也不需要加function
//函数内容
}
}
类的继承
父类
calss Father{
constructor(){
}
money(){
money(){
}
}
子类
class Son extends Father{
}
子类
class Son extends Father{
}
子类继承了父类的方法
var son=new Son();
son.money();
*子类继承父类带参数的方法
父类
calss Father{
constructor(x,y){
this.x=x;
this.y=y;
}
sum(){
console.log(this.x+this.y);
}
}
子类
class Son extends Father{
constructor(x,y){
super(x,y);//调用父类中的构造函数
}
}
子类继承了父类的方法
var son=new Son(1,2);
son.sum();
就近原则:子类中有该方法就调用该方法,若无才去父类中查找该方法
class Father{
say(){
//1
}
}
class Son extends Father{
say(){
//2
若该种情况子类想调用父类方法,可在此处:super.say();
}
}//子类调用的是自己的函数
super必须放在this前
class Father{
constructor(x,y){
this.x=x;
this.y=y;
}
}
class Son extends Father{
constructor(x,y){
super(x,y);//注意
this.x=x;
this.y=y;
}
}
*先有类才能实例化对象,且在类中其他的方法中调用construtor函数参数记得要加this,
同样的,在construtor中调用类中其他方法,也得加this。
类中this的指向
constructor里面的this指向的是创建的实例对象
方法中的this指向的是实例对象(即谁调用指向谁)
2.追加元素
appendChild不支持追加字符串的子元素,insertAdjacentHTML支持追加字符串的元素。
var str='追加元素的HTML语句';
被追加.insertAdjacentHTML(追加的位置,str);
阻止冒泡:e.stopPropagetion();
手动调用点击事件,不需要鼠标触发:.click();其他事件也可。
小技巧:a&&b,a为真,执行b。
双击禁止选定文字:window.getSelection?window.getSelection().removeAllRanges():document.selection.empty();
表单失去焦点事件:onblur();
3.构造函数和原型
构造函数+原型实现面向对象,特点:
1.构造函数有原型对象prototype
2.构造函数原型对象prototype里有construtor指向构造函数本身
3.构造函数可以通过原型对象添加方法
4.构造函数创建的实例对象有__proto__原型指向构造函数的原型对象
创建对象的三种方式:
利用new Object()创建对象:var obj1=new Object();
利用对象字面量创建对象:var obj2={};
利用构造函数创建对象:
function Star(uname,age){//一般首字母大写
this.uname=uname;
this.age=age;
this.sing(){}
}
var obj3=new Star(name,age);//创建对象,实例化
new在执行时会做的四件事情:
1.在内存中创建一个新的空对象
2.让this指向这个新的对象
3.执行构造函数里面的代码,给这个新对象添加属性和方法
4.返回这个新对象(因此构造函数里不需要return)
实例成员:构造函数内部通过this添加的成员就是实例成员,只能通过实例化的对象来访问
静态成员:在构造函数本身上添加的成员。Star.sex='女';只能通过构造函数来访问obj3.sex;//错 Star.sex;//对
4.构造函数的问题:存在浪费内存的问题。每实例一个对象就会开辟一个内存空间去存放同一个函数,如上面的sing()函数。
5.构造函数原型:prototype
每一个构造函数都有一个prototype属性。
把共享的函数放到原型对象prototype中,解决浪费内存问题。
修改上面的函数如下:
function Star(uname,age){//一般首字母大写
this.uname=uname;
this.age=age;
//this.sing(){}
}
Star.prototype.sing=function(){}
另一种写法://会把construtor()覆盖掉
Star.prototype={
constructor:Star, //手动再去指向Star
sing:function(){},
say:function(){}
}
原型的主要作用是:共享方法。
因此,一般情况下,我们的公共属性定义到构造函数里面,公共的方法放到原型对象上面。
6.对象原型:__proto__
对象身上系统自己添加一个__proto__指向构造函数的原型对象prototype。
obj3.__proto__===Star.prototype;//true
7.构造函数、实例、原型对象三者之间的关系:
Star构造函数————通过Star.prototype指向——>Star原型对象prototype
Star原型对象prototype————通过Star.prototype.constructor指向——>Star构造函数
Star构造函数——>obj3对象实例————通过obj3.__proto__指向——>Star原型对象prototype
obj3对象实例又可以通过obj3.__proto__.constructor指回Star构造函数
子类继承了父类的方法
var son=new Son();
son.money();
*子类继承父类带参数的方法
父类
calss Father{
constructor(x,y){
this.x=x;
this.y=y;
}
sum(){
console.log(this.x+this.y);
}
}
子类
class Son extends Father{
constructor(x,y){
super(x,y);//调用父类中的构造函数
}
}
子类继承了父类的方法
var son=new Son(1,2);
son.sum();
就近原则:子类中有该方法就调用该方法,若无才去父类中查找该方法
class Father{
say(){
//1
}
}
class Son extends Father{
say(){
//2
若该种情况子类想调用父类方法,可在此处:super.say();
}
}//子类调用的是自己的函数
super必须放在this前
class Father{
constructor(x,y){
this.x=x;
this.y=y;
}
}
class Son extends Father{
constructor(x,y){
super(x,y);//注意
this.x=x;
this.y=y;
}
}
*先有类才能实例化对象,且在类中其他的方法中调用construtor函数参数记得要加this,
同样的,在construtor中调用类中其他方法,也得加this。
类中this的指向
constructor里面的this指向的是创建的实例对象
方法中的this指向的是实例对象(即谁调用指向谁)
2.追加元素
appendChild不支持追加字符串的子元素,insertAdjacentHTML支持追加字符串的元素。
var str='追加元素的HTML语句';
被追加.insertAdjacentHTML(追加的位置,str);
阻止冒泡:e.stopPropagetion();
手动调用点击事件,不需要鼠标触发:.click();其他事件也可。
小技巧:a&&b,a为真,执行b。
双击禁止选定文字:window.getSelection?window.getSelection().removeAllRanges():document.selection.empty();
表单失去焦点事件:onblur();
3.构造函数和原型
构造函数+原型实现面向对象,特点:
1.构造函数有原型对象prototype
2.构造函数原型对象prototype里有construtor指向构造函数本身
3.构造函数可以通过原型对象添加方法
4.构造函数创建的实例对象有__proto__原型指向构造函数的原型对象
创建对象的三种方式:
利用new Object()创建对象:var obj1=new Object();
利用对象字面量创建对象:var obj2={};
利用构造函数创建对象:
function Star(uname,age){//一般首字母大写
this.uname=uname;
this.age=age;
this.sing(){}
}
var obj3=new Star(name,age);//创建对象,实例化
new在执行时会做的四件事情:
1.在内存中创建一个新的空对象
2.让this指向这个新的对象
3.执行构造函数里面的代码,给这个新对象添加属性和方法
4.返回这个新对象(因此构造函数里不需要return)
实例成员:构造函数内部通过this添加的成员就是实例成员,只能通过实例化的对象来访问
静态成员:在构造函数本身上添加的成员。Star.sex='女';只能通过构造函数来访问obj3.sex;//错 Star.sex;//对
4.构造函数的问题:存在浪费内存的问题。每实例一个对象就会开辟一个内存空间去存放同一个函数,如上面的sing()函数。
5.构造函数原型:prototype
每一个构造函数都有一个prototype属性。
把共享的函数放到原型对象prototype中,解决浪费内存问题。
修改上面的函数如下:
function Star(uname,age){//一般首字母大写
this.uname=uname;
this.age=age;
//this.sing(){}
}
Star.prototype.sing=function(){}
另一种写法://会把construtor()覆盖掉
Star.prototype={
constructor:Star, //手动再去指向Star
sing:function(){},
say:function(){}
}
原型的主要作用是:共享方法。
因此,一般情况下,我们的公共属性定义到构造函数里面,公共的方法放到原型对象上面。
6.对象原型:__proto__
对象身上系统自己添加一个__proto__指向构造函数的原型对象prototype。
obj3.__proto__===Star.prototype;//true
7.构造函数、实例、原型对象三者之间的关系:
Star构造函数————通过Star.prototype指向——>Star原型对象prototype
Star原型对象prototype————通过Star.prototype.constructor指向——>Star构造函数
Star构造函数——>obj3对象实例————通过obj3.__proto__指向——>Star原型对象prototype
obj3对象实例又可以通过obj3.__proto__.constructor指回Star构造函数
![](https://img2020.cnblogs.com/blog/1427801/202008/1427801-20200815135014900-726084128.png)
8.原型链
![](https://img2020.cnblogs.com/blog/1427801/202008/1427801-20200815141009088-665411912.png)
对象成员查找规则--就近原则
1.当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
2.如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)。
3.如果还没有就查找原型对象的原型(Object的原型对象—)。
4.依此类推一直找到Object为止(null)。
5.__proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
9.this的指向
在构造函数中,里面的this指向的是对象实例obj3。
原型对象函数里面的this指向的是实例对象obj3。
10.利用原型函数扩展内置对象
可以通过原型对象,对原来的内置对象进行扩展自定义的方法,比如给数组增加自定义求偶数和的功能。
给数组加个自定义方法:
Array.prototype.sum=function(){
var sum=0;
for(var i=0;i<this.length;i++){
sum+=this[i];
}
return sum;
}
var arr=[1,2,3];
console.log(arr.sum());
console.log(Array.prototype);
var arr1=Array(1,2,3,4);
console.log(arr1.sum());
console.log(arr.concat(arr1));
11.继承
call方法:改变this的指向
function fn(x,y){
console.log('哦');
console.log(this);
console.log(x+y);
}
var o={
name:'哎呀'
};
fn();
fn.call();
fn.call(o);//改变函数指向,指向o这个对象
fn.call(o,1,2);
1.当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
2.如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)。
3.如果还没有就查找原型对象的原型(Object的原型对象—)。
4.依此类推一直找到Object为止(null)。
5.__proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
9.this的指向
在构造函数中,里面的this指向的是对象实例obj3。
原型对象函数里面的this指向的是实例对象obj3。
10.利用原型函数扩展内置对象
可以通过原型对象,对原来的内置对象进行扩展自定义的方法,比如给数组增加自定义求偶数和的功能。
给数组加个自定义方法:
Array.prototype.sum=function(){
var sum=0;
for(var i=0;i<this.length;i++){
sum+=this[i];
}
return sum;
}
var arr=[1,2,3];
console.log(arr.sum());
console.log(Array.prototype);
var arr1=Array(1,2,3,4);
console.log(arr1.sum());
console.log(arr.concat(arr1));
11.继承
call方法:改变this的指向
function fn(x,y){
console.log('哦');
console.log(this);
console.log(x+y);
}
var o={
name:'哎呀'
};
fn();
fn.call();
fn.call(o);//改变函数指向,指向o这个对象
fn.call(o,1,2);
借用父构造函数继承属性
function Father(uname,age){
this.uname=uname;
this.age=age;
}
Father.prototype.money=function(){
console.log(10000);
}
function Son(uname,age,score){
Father.call(this,uname,age);//该this指向Son
this.score=score;
}
Son.prototype=new Father();//先
Son.prototype.constructor=Son;//再
//就可以使用父类的money方法
Son.prototype.exam=function(){
console.log('考试');
}
var pp=new Son('彭彭',18,100);
console.log(pp);
console.log(Father.prototype);
12.类的本质
class的本质其实还是function--构造函数的另外一种写法。
其有构造函数的特点:
1.类有原型对象prototype
2.类原型对象prototype里有construtor指向类本身
3.类可以通过原型对象添加方法
4.类创建的实例对象有__proto__原型指向类的原型对象
类其实是语法糖。--两种方法都可实现功能,简单的那种方法就是语法糖。
13.ES6新增的方法
数组方法
迭代(遍历)方法:forEach(),map(),filter(),some(),every();
1.arr.forEach(function(currentValue,index,arr){})
currentValue:数组当前项的值
index:数组当前项的索引
arr:数组对象本身
var arr=[1,2,3];
arr.forEach(function(value,index,array){
console.log(value);
console.log(index);
console.log(array);
})
2.arr.filter(function(currentValue,index,arr)())
主要用于筛选,返回一个新数组
var arr=[1,23,24,55];
var newArr=arr.filter(function(value,index){
return value>=20;//value值->数组
//return value%2==0;
})
console.log(newArr);
3.arr.some(function(currentValue,index,arr){})
查找数组中是否有满足条件的元素,有返回true,否则false
var arr=[1,23,24,5,6];
var flag=arr.some(function(value){
return value%2==0;//布尔值
//找到了第一个符合的元素则结束循环
});
console.log(flag);
4.every()类似some()
14.some和forEach的区别
forEach中return true了也不会结束迭代循环。
some中return true了就结束迭代循环,效率更高。
15.字符串方法
trim();去除字串两侧空格,字串中间空格保留,返回一个新字符串。
var newStr=str.trim();
16.Object.defineProperty()
定义对象中新属性或修改原有的属性
Object.defineProperty(obj,prop,descriptor);
obj:必需,目标对象
prop:必需,需定义或修改的属性的名字
descriptor:必需,目标属性所拥有的特性
descriptor:{}
value:设置属性的值,默认为undefined
writable:值是否可以重写,true/false,默认false
enumerable:目标属性是否可以被枚举,true/false,默认为false
configurable:目标属性是否可以被删除或是否可以再次修改特性true/false,默认false
var obj={
id:1,
name:'redmi',
price:1999
}
//定义/修改对象属性
Object.defineProperty(obj,'num',{//原先没有的属性则添加
value:1000
});
Object.defineProperty(obj,'id',{
writable:false//这样id就不可修改
});
Object.defineProperty(obj,'address',{
value:'中国广东',
writable:false,//
enumerable:false,//这样就不能被遍历出来
configurable:false//这样就不允许被删除了,也不能再修改descriptor里的特性了了
function Father(uname,age){
this.uname=uname;
this.age=age;
}
Father.prototype.money=function(){
console.log(10000);
}
function Son(uname,age,score){
Father.call(this,uname,age);//该this指向Son
this.score=score;
}
Son.prototype=new Father();//先
Son.prototype.constructor=Son;//再
//就可以使用父类的money方法
Son.prototype.exam=function(){
console.log('考试');
}
var pp=new Son('彭彭',18,100);
console.log(pp);
console.log(Father.prototype);
12.类的本质
class的本质其实还是function--构造函数的另外一种写法。
其有构造函数的特点:
1.类有原型对象prototype
2.类原型对象prototype里有construtor指向类本身
3.类可以通过原型对象添加方法
4.类创建的实例对象有__proto__原型指向类的原型对象
类其实是语法糖。--两种方法都可实现功能,简单的那种方法就是语法糖。
13.ES6新增的方法
数组方法
迭代(遍历)方法:forEach(),map(),filter(),some(),every();
1.arr.forEach(function(currentValue,index,arr){})
currentValue:数组当前项的值
index:数组当前项的索引
arr:数组对象本身
var arr=[1,2,3];
arr.forEach(function(value,index,array){
console.log(value);
console.log(index);
console.log(array);
})
2.arr.filter(function(currentValue,index,arr)())
主要用于筛选,返回一个新数组
var arr=[1,23,24,55];
var newArr=arr.filter(function(value,index){
return value>=20;//value值->数组
//return value%2==0;
})
console.log(newArr);
3.arr.some(function(currentValue,index,arr){})
查找数组中是否有满足条件的元素,有返回true,否则false
var arr=[1,23,24,5,6];
var flag=arr.some(function(value){
return value%2==0;//布尔值
//找到了第一个符合的元素则结束循环
});
console.log(flag);
4.every()类似some()
14.some和forEach的区别
forEach中return true了也不会结束迭代循环。
some中return true了就结束迭代循环,效率更高。
15.字符串方法
trim();去除字串两侧空格,字串中间空格保留,返回一个新字符串。
var newStr=str.trim();
16.Object.defineProperty()
定义对象中新属性或修改原有的属性
Object.defineProperty(obj,prop,descriptor);
obj:必需,目标对象
prop:必需,需定义或修改的属性的名字
descriptor:必需,目标属性所拥有的特性
descriptor:{}
value:设置属性的值,默认为undefined
writable:值是否可以重写,true/false,默认false
enumerable:目标属性是否可以被枚举,true/false,默认为false
configurable:目标属性是否可以被删除或是否可以再次修改特性true/false,默认false
var obj={
id:1,
name:'redmi',
price:1999
}
//定义/修改对象属性
Object.defineProperty(obj,'num',{//原先没有的属性则添加
value:1000
});
Object.defineProperty(obj,'id',{
writable:false//这样id就不可修改
});
Object.defineProperty(obj,'address',{
value:'中国广东',
writable:false,//
enumerable:false,//这样就不能被遍历出来
configurable:false//这样就不允许被删除了,也不能再修改descriptor里的特性了了
});
Object.defineProperty(obj,'address',{
value:'中国广东',
writable:true,
enumerable:true,
configurable:true//这样是不允许的
Object.defineProperty(obj,'address',{
value:'中国广东',
writable:true,
enumerable:true,
configurable:true//这样是不允许的
});
delete obj.address;
console.log(obj);
17.函数
函数的定义方式
1.自定义函数(命名函数)
function fn(){};
2.函数表达式(匿名函数)
var fun=function(){};
3.利用new Function('参数1','参数2','函数体');--比较少用,麻烦,效率低
var f=new Function('a','b','console.log(a+b)');
f(1,2);
所有函数都是Function的实例(对象)。
函数也属于对象。
函数的调用方式
1.普通函数
fn();/fn.call();
2.对象函数
o.say();
3.构造函数
new Star();
4.绑定事件函数
btn.onclick=function(){};
5.定时器函数
setInterval(function(){},1000);//定时一秒钟调用一次
6.立即执行函数
(function(){})();//自动调用
函数内this的指向
1.普通函数
fn();/fn.call();-->window
2.对象函数
o.say();-->o
3.构造函数--原型对象里的this也指向f
var f=new Star();-->f
4.绑定事件函数
btn.onclick=function(){};-->btn
5.定时器函数
setInterval(function(){},1000);-->window
6.立即执行函数
(function(){})();-->window
18.this
改变this的指向call(),apply(),bind();
call(指向的对象,...参数);
var o={name:'ooo'}
function f(a,b){};
f.call(o,1,2);-->o
call的主要作用是实现继承
function Father(uname,age){
this.uname=uname;
this.age=age;
}
function Son(uname,age){
Father.call(this,uname,age,sex);
}
apply(指向的对象,[...参数]);
与call()类似,但参数需以数组(伪数组)形式传入
apply()d的主要作用,可以利用apply借助数组内置对象求最大值
var arr=[2,33,1,66];
var max=Math.max.apply(Math,arr);
console.log(max);
bind(指向对象,...参数);--最常用
不调用(对象后面加()调用或函数再调用一次),有返回值。
当函数不需要立即调用但是又想改变函数内部的this指向,此时用bind();
btn.onclick=function(){
this.disabled=true;//this指向btn
setTimeout(function(){
this.disabled=false;//this指向window-->修改后指向了btn
}.bind(this),3000)//让this指向btn这个对象
}
三者相同点
都可以改变函数内部的this指向
区别点
1.call和apply会调用函数并且改变函数内部this指向
2.call和apply传递的参数不一样,call传递参数1,2...形式,apply必须数组形式
3.bind不会调用函数,可以改变函数内部this指向
主要应用场景
1.call经常用于继承
2.apply经常跟数组有关系,比如借助于数学对象实现数组的最大最小值
3.bind不调用函数但还是改变this的指向,比如改变定时器内部的this指向
19.严格模式
'use strict';
为整个脚本开启严格模式
<script>
'use strict';
</script>
<script>
(function(){
'use strict';
})()
</script>
为某个函数开启严格模式
function f(){
'use strict';
}
严格模式下:
变量:
1.变量必须先声明再使用
2.不能随意删除已经声明好的变量(delete)
this:
3.全局作用域中函数中this是undefined
4.如果构造函数不加new调用,this会报错
5.定时器this还是指向window
6.事件、对象还是指向调用者
函数:
7.函数里面的参数不允许有重名
8.if/for内不允许声明函数
20.高阶函数
是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。
1.函数作为参数传递
回调函数
function f(a,b,callback){
console.log(a+b);
callback&&callback();
}
f(1,2,function(){
console.log('我是最后调用的');
})
2.函数作为返回值输出
function f(){
return function(){}
}
f();
21.闭包
指有权访问另一个函数作用域中变量的函数。
即一个作用域可以访问另一个函数作用域中变量的函数。
作用:延伸了变量的作用范围。
缺点:有可能会造成内存泄漏。
function f(){//被访问变量所在的函数就是闭包
var name='哦呀';
function fn(){
console.log(name);
}
fn();
}//f()就是闭包
或:
function f(){//被访问变量所在的函数就是闭包
var name='哦呀';
return function(){
console.log(name);
}
}
f();
f外面的作用域可以访问f内部的局部变量
var f1=f();相当于:
var f1=function fn(){
console.log(name);
}
f1();//访问到了局部变量name
22.递归
函数内部自己调用自己,这个函数就是递归函数
缺点:可能造成栈溢出,所以必须有return 退出函数
利用递归遍历数据:
var data=[
{id:1,
name:'家电',
goods:[
{
id:11,
gname:'冰箱',
},
{
id:12,
gname:'洗衣机'
}
]},
{
id:2,
name:'服饰'
}
];
1.forEach遍历每一个对象
function getId(json,id){
json.forEach(function(item){
//console.log(item);
if(item.id==id){
console.log(item);
//获取里层的数据
delete obj.address;
console.log(obj);
17.函数
函数的定义方式
1.自定义函数(命名函数)
function fn(){};
2.函数表达式(匿名函数)
var fun=function(){};
3.利用new Function('参数1','参数2','函数体');--比较少用,麻烦,效率低
var f=new Function('a','b','console.log(a+b)');
f(1,2);
所有函数都是Function的实例(对象)。
函数也属于对象。
函数的调用方式
1.普通函数
fn();/fn.call();
2.对象函数
o.say();
3.构造函数
new Star();
4.绑定事件函数
btn.onclick=function(){};
5.定时器函数
setInterval(function(){},1000);//定时一秒钟调用一次
6.立即执行函数
(function(){})();//自动调用
函数内this的指向
1.普通函数
fn();/fn.call();-->window
2.对象函数
o.say();-->o
3.构造函数--原型对象里的this也指向f
var f=new Star();-->f
4.绑定事件函数
btn.onclick=function(){};-->btn
5.定时器函数
setInterval(function(){},1000);-->window
6.立即执行函数
(function(){})();-->window
18.this
改变this的指向call(),apply(),bind();
call(指向的对象,...参数);
var o={name:'ooo'}
function f(a,b){};
f.call(o,1,2);-->o
call的主要作用是实现继承
function Father(uname,age){
this.uname=uname;
this.age=age;
}
function Son(uname,age){
Father.call(this,uname,age,sex);
}
apply(指向的对象,[...参数]);
与call()类似,但参数需以数组(伪数组)形式传入
apply()d的主要作用,可以利用apply借助数组内置对象求最大值
var arr=[2,33,1,66];
var max=Math.max.apply(Math,arr);
console.log(max);
bind(指向对象,...参数);--最常用
不调用(对象后面加()调用或函数再调用一次),有返回值。
当函数不需要立即调用但是又想改变函数内部的this指向,此时用bind();
btn.onclick=function(){
this.disabled=true;//this指向btn
setTimeout(function(){
this.disabled=false;//this指向window-->修改后指向了btn
}.bind(this),3000)//让this指向btn这个对象
}
三者相同点
都可以改变函数内部的this指向
区别点
1.call和apply会调用函数并且改变函数内部this指向
2.call和apply传递的参数不一样,call传递参数1,2...形式,apply必须数组形式
3.bind不会调用函数,可以改变函数内部this指向
主要应用场景
1.call经常用于继承
2.apply经常跟数组有关系,比如借助于数学对象实现数组的最大最小值
3.bind不调用函数但还是改变this的指向,比如改变定时器内部的this指向
19.严格模式
'use strict';
为整个脚本开启严格模式
<script>
'use strict';
</script>
<script>
(function(){
'use strict';
})()
</script>
为某个函数开启严格模式
function f(){
'use strict';
}
严格模式下:
变量:
1.变量必须先声明再使用
2.不能随意删除已经声明好的变量(delete)
this:
3.全局作用域中函数中this是undefined
4.如果构造函数不加new调用,this会报错
5.定时器this还是指向window
6.事件、对象还是指向调用者
函数:
7.函数里面的参数不允许有重名
8.if/for内不允许声明函数
20.高阶函数
是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。
1.函数作为参数传递
回调函数
function f(a,b,callback){
console.log(a+b);
callback&&callback();
}
f(1,2,function(){
console.log('我是最后调用的');
})
2.函数作为返回值输出
function f(){
return function(){}
}
f();
21.闭包
指有权访问另一个函数作用域中变量的函数。
即一个作用域可以访问另一个函数作用域中变量的函数。
作用:延伸了变量的作用范围。
缺点:有可能会造成内存泄漏。
function f(){//被访问变量所在的函数就是闭包
var name='哦呀';
function fn(){
console.log(name);
}
fn();
}//f()就是闭包
或:
function f(){//被访问变量所在的函数就是闭包
var name='哦呀';
return function(){
console.log(name);
}
}
f();
f外面的作用域可以访问f内部的局部变量
var f1=f();相当于:
var f1=function fn(){
console.log(name);
}
f1();//访问到了局部变量name
22.递归
函数内部自己调用自己,这个函数就是递归函数
缺点:可能造成栈溢出,所以必须有return 退出函数
利用递归遍历数据:
var data=[
{id:1,
name:'家电',
goods:[
{
id:11,
gname:'冰箱',
},
{
id:12,
gname:'洗衣机'
}
]},
{
id:2,
name:'服饰'
}
];
1.forEach遍历每一个对象
function getId(json,id){
json.forEach(function(item){
//console.log(item);
if(item.id==id){
console.log(item);
//获取里层的数据
}else if(item.goods&&item.goods.length>0){
getId(item.goods,id);
}
})
}
console.log(getId(data,1));
console.log(getId(data,11));
2.遍历后保存
function getId(json,id){
var o={};
json.forEach(function(item){
//console.log(item);
if(item.id==id){
o=item;
//console.log(item);
//获取里层的数据
}else if(item.goods&&item.goods.length>0){
o=getId(item.goods,id);
}
})
return o;
}
console.log(getId(data,1));
console.log(getId(data,11));
23.递归浅拷贝和深拷贝
浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用。
深拷贝拷贝多层,每一级别的数据都会拷贝。
浅拷贝--同一个内存空间
var obj={//浅拷贝
id:1,
name:'oo',
msg:'200'
};
//var o={};
//for(var k in obj){
// o[k]=obj[k];
//}
//console.log(o);
//o.msg='201';//obj中msg也被改变,浅拷贝特点
浅拷贝语法糖:
Object.assign(o,obj);
深拷贝--新开辟多了一块内存空间
var obj={
id:1,
name:'oo',
msg:{
age:18
},
color:['pink','red']
};
var o={};
function deepCopy(newobj,oldobj){
for(var k in oldobj){
var item=oldobj[k];
//判断是否是数组
if(item instanceof Array){//数组也是Object,所以数组应该先筛选
newobj[k]=[];
deepCopy(newobj[k],item);
}
//判断是否是对象
else if(item instanceof Object){
newobj[k]={};
deepCopy(newobj[k],item);
}
//属于简单数据类型
else{
newobj[k]=item;
}
}
}
deepCopy(o,obj);
console.log(o);
//深拷贝修改o不会改变obj
24.正则表达式
用于匹配字符串中字符组合的模式。
作用:
1.验证表单(匹配)
2.过滤页面中一些敏感词(替换)
3.从字符串中获取想要的特定部分(提取)
特点:
1.灵活性、逻辑性和功能性非常强。
2.迅速用简单的方式达到字符串的复杂控制。
创建正则表达式
1.利用RegExp对象来创建
var regexp=new Regexp(/123/);
2.利用对象字面量创建
var rg=/123/;
测试正则表达式:
test():正则对象方法,用于检测字符串是否符合该规则,该对象返回true/false,其参数是测试字符串。
regexpObj.text()
var rg=/123/;//只要包含123的字符串
console.log(rg.test(123));
特殊字符
--元字符
边界符:
^:以谁开始
$:以谁结束
var rg=/^123/;//以123开头的字符串
var rg=/^123$/;//只有123字符串符合条件
字符类:
[]:表示有一系列字符可供选择,只要匹配其中一个就可以。
var rg=/[123]/;//只要字符串包含1/2/3就符合条件,返回true。
var rg=/^[123]$/;//123只能3选1才返回true。
var rg=/^[a-b]$/;//26个小写字母只能任选一个,“-”表示范围。
字符组合:
var rg=/^[a-zA-Z0-9_-]$/;//所有范围任选一个字符
var rg=/^[^a-zA-Z0-9_-]$/;//取反,有该范围的字符返回false.
量词符:
用来设定某个模式出现的次数
*:>=0
var reg=/^a*$/;a可以出现0次或以上次数
+:>=1
var reg=/^a+$/;a可以出现1次或以上次数
?:1||0
var reg=/^a?$/;a可以出现1次或0次
{3}:3次
var reg=/^a{3}$/;a只能出现3次
{3,}:大于等于3
var reg=/^a{3,}$/;
{3,16}:大于等于3并且小于等于16
var reg=/^a{3,16}$/;
组合:
var reg=/^[a-zA-Z0-9_-]{6,16}$/;//在范围内必须输入6-16位的字符串。
括号的总结:
[]:字符集合,匹配方括号中的任意字符。
{}:量词符,表示重复次数
var reg=/^abc{3}$/;c需重复3次(abccc),没有优先级
():优先级
var reg=/^(abc){3}$/;abc需重复3次(abcabcabc)
预定义类:
\d:数字0-9
\D:0-9除外,非数字
\w:[a-zA-Z0-9_]
\W:[^a-zA-Z0-9_]
\s:匹配空格,相当于[\t\r\n\v\f]
\S:匹配非空字符,相当于[^\t\r\n\v\f]
正则中的或者符号:|
例子:3-8或4-7电话号码:
1./^\d{3}-\d{8}|\d{4}-\d{7}$/
2./^\d{3,4}-\d{7,8}$/貌似有bug
中文字符:[\u4e00-\u9fa5]
正则表达式的替换
replace()方法实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式。
stringObject.replace(regexp/substr,replacement)
第一个参数:被替换的字符串或者正则表达式
第二个参数:替换为的字符串
返回值是一个替换完毕的新字符串
var str='abc和def';
var news1=str.replace('abc','ghi');
var news2=str.replace(/\w{3}/,'jkl');
console.log(news1);
console.log(news2);
正则表达式参数:/表达式/[switch]
switch值:
g:全局匹配
i:忽略大小写
gi:全局匹配加忽略大小写
var news2=str.replace(/\w{3}/g,'jkl');
//所有符合正则表达式的子串都被替换
25.ES6
let可以防止循环变量变为全局变量。
结构赋值
ES6允许从数组中提取值,按照对应位置,对变量赋值。对象也可以实现结构。
数组结构
let [a,b,c,d]=[1,2,3];
a=1;b=2;c=3;d=undefined;
对象结构
let person={name:'jenny',age:18,sex:'女'};
let {name,age,sex}=person;
let {name:myName,age:myAge,sex:mySex}=person;
console.log(myName);
26.箭头函数()=>{}
定义
const fn=()=>{
console.log(1);
};fn();
函数体只有一句代码且代码执行结果就是函数返回值,函数体{}可以省略。
const sum=(n1,n2)=>n1+n2;
sum(2,3);
形参只有一个,形参外()可以省略。
const fn=n=>console.log(n);
fn(5);
箭头函数定义在哪,this就指向哪。
function fn(){//函数有作用域,对象没有,this只会指向作用域中的属性
console.log(this);
return ()=>{
console.log(this);
}
}//两个this都指向了obj
const obj={name:'jenny'};
const reFn=fn.call(obj);
reFn();
27.Array的扩展方法
扩展运算符(...)
1.可以将数组或者对象转为用逗号分隔的参数序列。
let ary=[1,2,3];
//...ary;
console.log(...ary);
2.可以应用于数组合并
方法1:
let ary1=[1,3,2];
let ary2=['a',3,'h'];
let ary3=[...ary1,...ary2];
方法2:
ary1.push(...ary2);
console.log(ary1);
3.将类数组或可遍历对象转换为真正的数组
--之后可调用数组拥有的方法
构造函数方法:Array.from()
可接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。
var arrayLike={
"0":"1",
"1":"2",
"length":2
}//伪数组
var arr=Array.from(arrayLike,item=>item*2);
console.log(arr);
实例方法:find()
用于找出第一个符合条件的数组成员,如果没找到返回undefined;
var arr=[{
id:1,
name:'andy'
},{
id:2,
name:'jenny'
}];
let target=arr.find(item=>item.id==2);
console.log(target);
实例方法:findIndex()
用于找出第一个符合条件的数组成员的位置,如果没找到返回-1
let arr=[10,20,30];
let n=arr.findIndex(item=>item>15);
console.log(n);
实例方法:includes()
表示某个数组是否包含给定的值,返回布尔值。
[2,1,2,24].includes(24);//true
28.String的扩展方法
模板字符串
换行、空字符串会保留。
let arr=`这是一个模板字符串`;
let name='jenny';
let arr2=`我的名字是${name}`;//调用属性
console.log(arr2);
const fn=()=>{
return '我是fn函数';
}
let arr3=`我是模板字符串 ${fn()}`;//调用函数
console.log(arr3);
实例方法:startsWith()和endsWith()
表示参数字符串是否在源字符串的头/尾部,返回布尔值。
let arr='Hello world';
arr.startsWith('Hello');//true
实例方法:repeat()
表示将原字符串重复n次,返回一个新字符串。
let arr='x'.repeat(3);//xxx
29.Set数据结构
类似数组,成员唯一,没有重复值,会自动过滤重复值。
const s1=new Set();
console.log(s1.size);//s1长度为0
const s2=new Set(["a","b"]);
console.log(s2.size);//s2长度为2
实例方法:
add(value):添加某个值,返回Set结构本身
delete(value):删除某个值,返回一个布尔值,表示删除是否成功
has(value):返回一个布尔值,表示该值是否为Set的成员
clear():清除所有成员,没有返回值
const s=new Set();
s.add(1).add(2).add(3).add(3);
s.delete(2);
s.has(2);
console.log(s.size);
遍历:
const s=new Set(['a','b','c']);
s.forEach(value=>{
console.log(value);
})
getId(item.goods,id);
}
})
}
console.log(getId(data,1));
console.log(getId(data,11));
2.遍历后保存
function getId(json,id){
var o={};
json.forEach(function(item){
//console.log(item);
if(item.id==id){
o=item;
//console.log(item);
//获取里层的数据
}else if(item.goods&&item.goods.length>0){
o=getId(item.goods,id);
}
})
return o;
}
console.log(getId(data,1));
console.log(getId(data,11));
23.递归浅拷贝和深拷贝
浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用。
深拷贝拷贝多层,每一级别的数据都会拷贝。
浅拷贝--同一个内存空间
var obj={//浅拷贝
id:1,
name:'oo',
msg:'200'
};
//var o={};
//for(var k in obj){
// o[k]=obj[k];
//}
//console.log(o);
//o.msg='201';//obj中msg也被改变,浅拷贝特点
浅拷贝语法糖:
Object.assign(o,obj);
深拷贝--新开辟多了一块内存空间
var obj={
id:1,
name:'oo',
msg:{
age:18
},
color:['pink','red']
};
var o={};
function deepCopy(newobj,oldobj){
for(var k in oldobj){
var item=oldobj[k];
//判断是否是数组
if(item instanceof Array){//数组也是Object,所以数组应该先筛选
newobj[k]=[];
deepCopy(newobj[k],item);
}
//判断是否是对象
else if(item instanceof Object){
newobj[k]={};
deepCopy(newobj[k],item);
}
//属于简单数据类型
else{
newobj[k]=item;
}
}
}
deepCopy(o,obj);
console.log(o);
//深拷贝修改o不会改变obj
24.正则表达式
用于匹配字符串中字符组合的模式。
作用:
1.验证表单(匹配)
2.过滤页面中一些敏感词(替换)
3.从字符串中获取想要的特定部分(提取)
特点:
1.灵活性、逻辑性和功能性非常强。
2.迅速用简单的方式达到字符串的复杂控制。
创建正则表达式
1.利用RegExp对象来创建
var regexp=new Regexp(/123/);
2.利用对象字面量创建
var rg=/123/;
测试正则表达式:
test():正则对象方法,用于检测字符串是否符合该规则,该对象返回true/false,其参数是测试字符串。
regexpObj.text()
var rg=/123/;//只要包含123的字符串
console.log(rg.test(123));
特殊字符
--元字符
边界符:
^:以谁开始
$:以谁结束
var rg=/^123/;//以123开头的字符串
var rg=/^123$/;//只有123字符串符合条件
字符类:
[]:表示有一系列字符可供选择,只要匹配其中一个就可以。
var rg=/[123]/;//只要字符串包含1/2/3就符合条件,返回true。
var rg=/^[123]$/;//123只能3选1才返回true。
var rg=/^[a-b]$/;//26个小写字母只能任选一个,“-”表示范围。
字符组合:
var rg=/^[a-zA-Z0-9_-]$/;//所有范围任选一个字符
var rg=/^[^a-zA-Z0-9_-]$/;//取反,有该范围的字符返回false.
量词符:
用来设定某个模式出现的次数
*:>=0
var reg=/^a*$/;a可以出现0次或以上次数
+:>=1
var reg=/^a+$/;a可以出现1次或以上次数
?:1||0
var reg=/^a?$/;a可以出现1次或0次
{3}:3次
var reg=/^a{3}$/;a只能出现3次
{3,}:大于等于3
var reg=/^a{3,}$/;
{3,16}:大于等于3并且小于等于16
var reg=/^a{3,16}$/;
组合:
var reg=/^[a-zA-Z0-9_-]{6,16}$/;//在范围内必须输入6-16位的字符串。
括号的总结:
[]:字符集合,匹配方括号中的任意字符。
{}:量词符,表示重复次数
var reg=/^abc{3}$/;c需重复3次(abccc),没有优先级
():优先级
var reg=/^(abc){3}$/;abc需重复3次(abcabcabc)
预定义类:
\d:数字0-9
\D:0-9除外,非数字
\w:[a-zA-Z0-9_]
\W:[^a-zA-Z0-9_]
\s:匹配空格,相当于[\t\r\n\v\f]
\S:匹配非空字符,相当于[^\t\r\n\v\f]
正则中的或者符号:|
例子:3-8或4-7电话号码:
1./^\d{3}-\d{8}|\d{4}-\d{7}$/
2./^\d{3,4}-\d{7,8}$/貌似有bug
中文字符:[\u4e00-\u9fa5]
正则表达式的替换
replace()方法实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式。
stringObject.replace(regexp/substr,replacement)
第一个参数:被替换的字符串或者正则表达式
第二个参数:替换为的字符串
返回值是一个替换完毕的新字符串
var str='abc和def';
var news1=str.replace('abc','ghi');
var news2=str.replace(/\w{3}/,'jkl');
console.log(news1);
console.log(news2);
正则表达式参数:/表达式/[switch]
switch值:
g:全局匹配
i:忽略大小写
gi:全局匹配加忽略大小写
var news2=str.replace(/\w{3}/g,'jkl');
//所有符合正则表达式的子串都被替换
25.ES6
let可以防止循环变量变为全局变量。
结构赋值
ES6允许从数组中提取值,按照对应位置,对变量赋值。对象也可以实现结构。
数组结构
let [a,b,c,d]=[1,2,3];
a=1;b=2;c=3;d=undefined;
对象结构
let person={name:'jenny',age:18,sex:'女'};
let {name,age,sex}=person;
let {name:myName,age:myAge,sex:mySex}=person;
console.log(myName);
26.箭头函数()=>{}
定义
const fn=()=>{
console.log(1);
};fn();
函数体只有一句代码且代码执行结果就是函数返回值,函数体{}可以省略。
const sum=(n1,n2)=>n1+n2;
sum(2,3);
形参只有一个,形参外()可以省略。
const fn=n=>console.log(n);
fn(5);
箭头函数定义在哪,this就指向哪。
function fn(){//函数有作用域,对象没有,this只会指向作用域中的属性
console.log(this);
return ()=>{
console.log(this);
}
}//两个this都指向了obj
const obj={name:'jenny'};
const reFn=fn.call(obj);
reFn();
27.Array的扩展方法
扩展运算符(...)
1.可以将数组或者对象转为用逗号分隔的参数序列。
let ary=[1,2,3];
//...ary;
console.log(...ary);
2.可以应用于数组合并
方法1:
let ary1=[1,3,2];
let ary2=['a',3,'h'];
let ary3=[...ary1,...ary2];
方法2:
ary1.push(...ary2);
console.log(ary1);
3.将类数组或可遍历对象转换为真正的数组
--之后可调用数组拥有的方法
构造函数方法:Array.from()
可接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。
var arrayLike={
"0":"1",
"1":"2",
"length":2
}//伪数组
var arr=Array.from(arrayLike,item=>item*2);
console.log(arr);
实例方法:find()
用于找出第一个符合条件的数组成员,如果没找到返回undefined;
var arr=[{
id:1,
name:'andy'
},{
id:2,
name:'jenny'
}];
let target=arr.find(item=>item.id==2);
console.log(target);
实例方法:findIndex()
用于找出第一个符合条件的数组成员的位置,如果没找到返回-1
let arr=[10,20,30];
let n=arr.findIndex(item=>item>15);
console.log(n);
实例方法:includes()
表示某个数组是否包含给定的值,返回布尔值。
[2,1,2,24].includes(24);//true
28.String的扩展方法
模板字符串
换行、空字符串会保留。
let arr=`这是一个模板字符串`;
let name='jenny';
let arr2=`我的名字是${name}`;//调用属性
console.log(arr2);
const fn=()=>{
return '我是fn函数';
}
let arr3=`我是模板字符串 ${fn()}`;//调用函数
console.log(arr3);
实例方法:startsWith()和endsWith()
表示参数字符串是否在源字符串的头/尾部,返回布尔值。
let arr='Hello world';
arr.startsWith('Hello');//true
实例方法:repeat()
表示将原字符串重复n次,返回一个新字符串。
let arr='x'.repeat(3);//xxx
29.Set数据结构
类似数组,成员唯一,没有重复值,会自动过滤重复值。
const s1=new Set();
console.log(s1.size);//s1长度为0
const s2=new Set(["a","b"]);
console.log(s2.size);//s2长度为2
实例方法:
add(value):添加某个值,返回Set结构本身
delete(value):删除某个值,返回一个布尔值,表示删除是否成功
has(value):返回一个布尔值,表示该值是否为Set的成员
clear():清除所有成员,没有返回值
const s=new Set();
s.add(1).add(2).add(3).add(3);
s.delete(2);
s.has(2);
console.log(s.size);
遍历:
const s=new Set(['a','b','c']);
s.forEach(value=>{
console.log(value);
})
————学习笔记