1、 打开dos命令窗口的几种方法:
1) window+ r 或者在搜索里面 输入cmd
2)在资源管理器的当前路径上直接输入cmd
3) 鼠标右键 git bash here
2、常用的dos命令
dos 是linxu 写的,用c开发的,我们先来说下linxu 常用的一些命令
- 打开对应的文件夹:cd 文件夹 (确定当前目录下有改文件夹) 比如:C:\Users\Administrator\Desktop\test>cd a.txt
- 回退到上一级: cd ../
- 查看当前目录下的文件夹:cd + tab
- 返回到根目录:cd + /
- 创建一个文件夹:mkdir + 文件名
- 创建一个文件: copy con 文件名.txt ,然后按回车,键入想要输入的内容“成功的花儿”,结束后回车按ctrl+Z。
- 重命名一个文件或者文件夹: rename b f
- 删除一个文件夹:rd + 文件夹名 (只能删除空的文件夹)
- 删除一个文件夹:rd + /s + 文件夹名 (硬删除,即使里面有内容也能删除)
- 删除一个 文件: del + 文件夹名
- 清空命令行:cls
- 切换磁盘命令:D: /F:/C: 切换到相应的盘符
git版本控制系统
1、git(版本控制系统);到底什么是git,git又是做什么的呢
+ 记录历史版本信息<br /> + 方便团队之间协作开发
2、国内常用的版本控制系统
+ git:分布式管理系统<br /> + svn:集中式版本管理系统<br /> + 分布式和集中式的各自特点
1)svn集中式版本控制系统
2)git 分布式版本控制系统
3、git的安装:
> git官网 [https://git-scm.com/downloads](https://git-scm.com/downloads)<br /> > 安装成功后在桌面右键会出来两个git选项(打开git bash here,然后执行git --version)<br /> > GIT是linux创始人研发的工具,所以GIT中的操作大部分都是linux操作命令
4、git的工作原理(分为三个区)
+ 工作区:我们平时写代码的区域<br /> + 暂存区:用来临时存储代码<br /> + 历史区:生成历史版本
5、 git的使用
- 1、git的全局配置<br /> + git config --global --list:查看全局配置信息<br /> + git config --global user.name 'xxx' <br /> + git config --global user.email 'xxx@xxx'
6、创建本地仓库,完成版本控制
+ 1、创建本地仓库<br /> + git init(会默认生成一个.git文件夹,这里是存放你本地git仓库的信息的,不能删除)<br /> + shift + cmmand + . mac电脑显示隐藏目录
+ 2、在工作区编写代码完成后,提交到暂存区<br /> + git add 文件名(把指定文件提交到暂存区)<br /> + git add A(把工作区所有文件提交到暂存区)<br /> + git add . (把工作区所有修改的和新增的文件提交到暂存区,不包括删除的)<br /> + git status(查看当前文件提交状态)【红色代表在工作区;绿色代表在暂存区;没有文件,并显示clear之类的单词,说明文件已经提交到历史区或者没有任何更改】<br /> clear:清屏<br /> + 3、把文件提交到历史区<br /> + git commit -m'描述' (把文件提交到历史区,并生成此次提交的历史版本)<br /> + git log(查看提交的历史版本信息,不包括回滚)<br /> + git reflog(查看所有的历史版本信息,包括回滚信息)
+ 4、回滚指定历史版本的代码<br /> + git reset --hard 七位历史版本号
7、远程仓库的使用
- 1、介绍远程仓库github<br /> + github是一个开源的代码分享平台;每一个github账户都可以把自己的代码分享到这个平台上,那他就是充当中央服务器的角色,把代码提交到这个平台上之后,你可以在任何一个有网络的地方去下载代码,还可以配置下载的权限
- 2、创建一个远程仓库(点击左上角绿色的按钮 New)<br /> + Repository name:新建仓库的名称<br /> + Description:新建仓库的描述<br /> + Public/Private:新建仓库是公开还是私密的<br /> + Initialize this repository with:为仓库增加初始化文件(暂时不选)<br /> + 绿色按钮 Create repository: 创建新的仓库
- 3、把本地仓库的代码提交到远程仓库<br /> + 1、本地仓库和远程仓库建立连接<br /> + git remote -v(查看本地和远程仓库的连接状态)<br /> + git remote add origin 远程仓库地址(和远程仓库的某个新项目建立连接,origin这个名可以改,但是大家都统一叫这个)<br /> + 2、git pull origin master (拉取远程仓库的代码到本地)<br /> + 3、git push origin master (推送本地的代码到远程仓库)<br /> 【要输入用户名和密码 username password】
- 4、git clone 远程仓库地址 仓库的名字(如果不写默认原仓库名)<br /> + 其真正的开发中,大家都使用这个<br /> + 你们的项目老大把项目骨架搭建好之后你们每一个项目小组成员都去把远程的代码拉取到你们的本地去开发<br /> + git clone
二、作用域:
1)全局作用域:当打开页面的时候,会提供一个供js代码执行的环境,全局作用域,会默认提供一个最大的window对象。
- 【全局变量】:在全局作用域中声明的变量就是全局变量,其中下面的a 和fn 就是全局变量
- 【全局变量和window关系】 在全局作用域中声明的变量:var、function(除去es6的),相当于给window上添加了属性,属性名就是变量名,属性值就是变量值
- 调用window 下的方法时,可以省去window不写:
window.alert("1");
alert("1");
window.Number("1");
Number("1");
var a=3; // a是全局变量
function fn(){ // fn 是全局变量
var num=3;
function f1(){
}
}
console.log(window.a);
console.log(window.fn);
2)私有作用域:当函数执行的时候,会形成一个私有作用域,保护里面的私有变量不受外界的干扰
【私有变量】:
- 形参
- 在私有作用域中声明的变量就是私有变量。
在私有作用域外面,去访问私有变量的话,是访问不到的,但是在私有作用域里面可以访问到外面的变量。
var f1=66;
function fn(){
var x=1;
var y=3;
console.log(f1);
return x+y;
}
console.log(x);// x is not defined
fn();
2)作用域链:
在私有作用域中,在查找变量的时候,先看自己私有作用域中有没有,如果有,就用自己的,如果没有,就会向上一级作用域进行查找,如果也没有,一直向上查找,直到找到window全局作用域为止,如果全局也没有,分两种情况:
1) 如果只是查找,就会报错
2) 如果是赋值,就相当于给window全局作用域添加属性和属性值
function fn(){
console.log(n);// 自己私有作用域没有这个变量,向上级进行查找,上级window 也没有,就报错
}
fn();
function fn(){
n=3; // 自己私有作用域中没有,向上级进行查找,上级作用域也没有,就相当于给window.n=3;
}
fn();
console.log(n);
function fn(){
n=3; // 自己私有作用域中没有,向上级进行查找,上级作用域中有,就是上级作用域的n的值重新改了3
}
var n=2;
fn();
console.log(n);
function fn(){
console.log(n);// 2
}
var n=2;
fn();
console.log(n);
3)堆栈内存
全局作用域形成之后,会有两个虚拟的内存:堆内存和栈内存。
【栈内存作用】:
- 供js执行的环境,
- 存贮基本数据类型的值
【堆内存作用】:
存贮引用数据类型的值:
var a=2;
var b=a;
b=3;
console.log(b)
console.log(fn(1,2)); // 依然是3
function fn(n,m){
return n+m;
}
console.log(fn(1,2));
5)变量提升的特殊性
1)不论判断条件是否成立,都会进行变量提升
在当前作用域下,不管判断条件是否成功,都会进行变量提升: var :还是只声明 function:
- 新版本浏览器中的function 只是声明,不定义
- 在老版本中还是声明和定义(仅限判断语句)
【思考】
console.log(a);
if(1==2){
var a=12;
}
console.log(a);
【答案】
console.log(a);//undefined:不管条件是否成立,都会进行变量提升,var a;
if(1==2){
var a=12;// 条件不成立,所以进不来
}
console.log(a);//undefined
【思考】
console.log(fn);// 在新版本浏览器中,判断条件中的function相当于只是声明(跟var一样),所以undefined
if(1==2){
function fn(){
console.log(1)
}
}
console.log(fn); // undefined 条件不成立,只声明了,没赋值,(新版本浏览器)
【练习题】
console.log(a);
if(a in window){
var a=100;
}
console.log(a);
【360面试题】
f=function(){
return true;
};
g=function(){
return false;
};
~function(){
if(g()&&[]==![]){
f=function(){return false;};
function g(){
return true;
}
}
}();
console.log(f());
console.log(g());
【答案:】
自执行函数在全局作用域下不进行变量提升 题目分析: 1、在全局作用域中,变量提升:无 2、代码开始自上往下执行 f 就是window.f=function(){}, g就是window.g=function(){} 自执行函数,形成私用作用域,变量提升:不管条件是否成立,判断语句里面的代码都会进行变量提升,function g 在新版本浏览器中只声明未定义。 接着走到if语句中,g(),此时的g只声明未定义,相当于undefined(),所以g( )会报类型错误,下面的代码都不会执行Uncaught TypeError: g is not a function
答案:Uncaught TypeError: g is not a function
f=function(){
return true;
};
g=function(){
return false;
};
~function(){
if(g()&&[]==![]){
f=function(){return false;};
function g(){
return true;
}
}
}();
console.log(f());
console.log(g());
条件判断下的变量提升到底有多坑
1)在条件判断语句中,如果条件成立,会把执行体当成私有作用域,再进行变量提升
console.log(fn);
if(1==1){
console.log(fn);
function fn(){
console.log("ok");
}
}
console.log(fn)
【答案】
console.log(fn);// undefined 在新版本浏览器中,不管条件是否成功,都会进行变量提升,function 只声明,
if(1==1){
console.log(fn);// fn 函数:在条件判断语句中,如果条件成立,会把执行体当成私有作用域,再进行变量提升
// 再从上往下执行代码,此时fn 定义完成。
function fn(){
console.log("ok");
}
}
console.log(fn) // 条件成立,给fn进行了赋值,打印出fn函数
2)在条件判断下,如果有function定义的变量,在这个function这个函数后面的更改变量的值,更改的都是私有变量。
var a=0;
if(true){
a=1;
function a(){}
a=21;
console.log(a);
}
console.log(a);
【答案】21 1
var 还是原来理解的变量提升,但是function有改变(在条件语句下)
- 在新版本浏览器中,function 只声明,不定义
- 在老版本浏览器中,function 声明和定义
console.log(num); console.log(fn); if([]){ // 只要进到当前if条件中,会立即对fn进行赋值; fn() var num=100; function fn(){console.log("a")} } console.log(fn);
2)只对等号左边的做变量提升
console.log(fn);
console.log(fn(1,2));
var fn=function (n,m){
return n+m;
}
console.log(fn(3,4));
【思考】
sum();
fn();
var fn=function(){
console.log(1);
};
function sum(){
console.log(2);
}
fn();
sum();
console.log(obj.f1);
var obj={
f1:function(){
console.log(1)
}
}
【分析】:
1、变量提升:var fn (只对等号左边的进行变量提升),function sum
2、自上而下执行代码:
sum() ;//2
fn();// 此时fn undefined undefined() 报类型错误
3) return 下面的代码虽然不能执行,但是可以进行变量提升,return 后面的代码不进行变量提升
function fn(){
console.log(a);
return function f1(){
}
var a=3;
}
fn();
function fn(){
console.log(f2);
return function f1(){
}
function f2(){
console.log("f2")
}
}
fn();
4)如果变量名字重复该如何?
对于var的不会进行重复声明,但是会重新赋值
在变量提升阶段,看到第一行var num ,会声明一个变量num,此时看到第二行还有一个就不用再声明了
var num=2;
var num=3;
console.log(num);
对于function的在变量提升阶段是声明和定义一起完成的,如果遇到重复声明定义的,会进行重新赋值
下面的结果
console.log(fn)
function fn(){
console.log(1);
}
function fn(){
console.log(2);
}
function fn(){
console.log(3);
}
[练习题]
1)
console.log(fn) // 函数(变量提升阶段声明和定义一同完成) var fn 的时候只声明,但是已经有这个变量了。
function fn(){ // 跳过此阶段
console.log(1)
}
var fn=2; // 代码走到这里的时候,重新赋值 fn=2
console.log(fn) //2
2)
console.log(num);
var num = 1;
console.log(num);// 1
var num = 2;
console.log(num);
fn();// 4
function fn(){
console.log(1);
}
function fn(){
console.log(2);
}
fn();// 4
function fn(){
console.log(3);
}
fn=100;
function fn(){
console.log(4);
}
fn();// 报错
5)自执行函数在当前所在的作用域中不进行变量提升(自执行函数自己所形成的私有作用域照常进行)
function f2(){
console.log("f2");
}
// 自执行函数在此处不进行变量提升
(function (){
console.log(a);// undefined, 照常进行变量提升
var a=3;
})();
6)、带var 和不带var的区别
- 带var 的时候就是声明变量,不带var的时候,没有变量提升,
- 带var 声明的变量(是不可配置的),用delete 删除不掉,不带var 的变量 可以删除掉(是可配置的)
在全局作用域下,带var 还是不带var 都是给全局window添加了一个属性,属性名就是此变量,属性值就是变量值
console.log(a); //undefined
var a=3;
b=6;
console.log(window.a);
console.log("a" in window);
delete window.a;
delete window.b;
【思考】:下面的答案是什么?
console.log(a); //undefined
var a=3;
console.log(window.a);
console.log("a" in window);
【 判断一个对象到底有没有一个属性】:用 “属性名” in 对象,如果返回值是false 说明就是不存在,如果是true说明就是存在。
obj={"name":"lili"};
console.log(“name” in obj )// true 说明name就是obj的属性
console.log("age" in obj)//false 说明age 不是obj的属性
7)作用域链扩展练习题
在私有作用域中,如果没有定义这个私有变量,就会向上一级作用域进行查找,如果都没有,继续进行查找,直到查找到window全局作用域为止。如果window里面也没有这个私有变量,就相当于给window添加了这样的一个属性
【思考题】
console.log(b);
function fn(){
b=13;
console.log(b);
}
fn();
console.log(b);
【答案】
console.log(b);//b is not defined
function fn(){
b=13; // 不是私有变量,向上查找,直到window都没有,给window添加一个属性 window.b=13;
console.log(b);//13
}
fn();
console.log(b);// 13
【思考题】
console.log(a,b);// undefined undefined
var a=12,
b=12;
function fn(){
console.log(a,b);// undefined 12
var a=b=13;
console.log(a,b);// 13 13
}
fn();
console.log(a,b);// 12 13
二、es6 中let
1、es6不存在变量提升
console.log(a);//Uncaught ReferenceError: a is not defined
let a=2;
2、阻断了与window的关系
let a=2;
console.log(window.a);// undefined
3、不能重复声明
es6中没有变量提升,但是有一个自我检测的一个机制,在代码自上而下执行前,会先进行检测,看是否有重复声明的变量,如果有的话,就先报错。
let a=2;
console.log(a);
var a=3; // 不能进行重复的声明:Uncaught SyntaxError: Identifier 'a' has already been declared
console.log(3);
let a=2;
console.log(a);// 这里不会输出,在代码执行前先进行语法检测,发现重复声明变量,直接报错。此时代码还没从上而下执行
var a=3;
console.log(3);
【练习题】
let a=10,
b=10;
let fn=function(){
console.log(a);
let a=b=20;
console.log(a,b);
};
fn();
console.log(a,b)
[答案]
报错:a is not defined;
let a=10,
b=10;
let fn=function(){
console.log(a);// 函数执行,形成一个私有作用域,这里没变量提升,但是有自我检测机制,知道用let声明
let a=b=20; // 了一个变量,进行了记录,不存在变量提升,不能在let 之前进行获取变量,所以报错:a is not
// defined
console.log(a,b);
};
fn();
console.log(a,b)
如果将 第五行的注释掉,结果又是什么呢?
let a=10,
b=10;
let fn=function(){
//a 是这里的私有变量,在私有作用域中没有b这个变量,向上级查找,b是全局变量,此时更改的也是全局变量b
let a=b=20;
console.log(a,b);// 20 20
};
fn();
console.log(a,b);// 10 20
4、暂时性死区:
ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
console.log(a);// ReferenceError: a is not defined
let a=2;
对于没有声明过的变量,在es5中 用typeof 变量 结果是“undefined”,这样子的话并不好,按理说应该报错:没有声明过a
typeof a //===>"undefined"
es6中的暂时性死区:用let、const声明一个变量之前,那块区域就是暂时性死区,不能用来访问未定义的变量,如果访问的话,就会报错,这样在理论上更符合,更严谨。
typeof a //===> Uncaught ReferenceError: a is not defined
let a=2;
三、练习题(私有变量和全局变量)
1)
/*
全局变量和私有变量
私有变量:在私有作用域中只要以下两种情况是私有变量:
+ 形参
+ 声明过的变量(var、function、let 等)
剩下的都不是私有变量,需要基于作用域链向上查找
*/
var a=12,b=13,c=14;
function fn(a){
console.log(a,b,c);
var b=c=a=20;
console.log(a,b,c);
}
fn(a);
console.log(a,b,c);
2)
/*
传进来的参数如果是引用数据类型,在函数里面虽然是私有变量,但是更改的还是那个引用地址,所以全局下的变量也会发生变化
*/
var ary=[12,13];
function fn(ary){
console.log(ary);
ary[0]=100;
ary=[100];
ary[0]=0;
console.log(ary);
}
fn(ary);
console.log(ary);
【答案】:
[12,13]
[0]
[100,13]
四、上级作用域:
上级作用域: 当前函数执行,形成一个私有作用域A,这个A的上级作用域是谁,跟它在哪执行无关,跟它在哪定义(创建)有关系,在哪创建,它的上级作用域就是谁
简而言之:上级作用域和函数在哪执行无关,和函数在哪定义有关
var a=2;
function fn(){
console.log(a);
}
fn();
function sum(){
var a=3;
fn();
}
sum();
1、了解arguments.callee 和arguments.callee.caller
- arguments.callee:指的是函数本身
- arguments.callee.caller 指的是函数执行的宿主环境,如果是在函数A中执行,打印出来的就是A,如果是在全局作用域中执行,打印出来的就是null。 ``` function fn(){ console.log(arguments.callee); // 打印出的是fn 函数本身
} fn();
function fn(){ console.log(arguments.callee.caller); }
fn(); // 此时打印出的是 null(在全局作用域中执行)
function fn(){ console.log(arguments.callee.caller); } function A(){ fn(); // 此时打印出的是 A这个函数 } A();
<a name="4C7Yo"></a>
## 2、作用域练习题
var n=10; function fn(){ var n=20; function f(){ n++; console.log(n); } f(); return f; } var x=fn(); x(); x(); console.log(n);
![image.png](https://cdn.nlark.com/yuque/0/2020/png/453629/1585926279645-78affe32-7aae-4d43-8654-693cc9511a7c.png#height=397&id=cEjJD&name=image.png&originHeight=793&originWidth=1790&originalType=binary&ratio=1&size=85738&status=done&style=none&width=895)
【答案】:打印:21、22、23、10
<a name="a43Ge"></a>
## 3、堆栈内存小科普
<a name="pFhUa"></a>
### 1)js中的内存分为:堆内存和栈内存
【堆内存】:只要用来存储引用数据类型的值(对象存的是键值对,函数存的是字符串)<br /> 【栈内存】:供js运行的环境(函数执行),存基本数据类型的值
<a name="quCAD"></a>
### 2) 堆栈内存的释放问题
我们每次给变量存值或者执行函数的时候都会占用内存空间,如果一直这样下去,日积月累,电脑总会装不下的,所以内存是需要释放的。
<a name="ux4FL"></a>
#### 1)堆内存的释放:
常见的浏览器释放方式主要有以下两种:
- 谷歌浏览器是标记方式,每隔一段时间就会检测以下当前作用域中的内存,是否被占用,如果没有被占用,就会释放掉。
- ie和火狐等浏览器是采用计数方法,当前作用域中如果一个空间地址被占用一次,就会累加一,如果减少一次占用就会减1,直到0的时候,说明已经没有被占用了,就释放了。
堆内存释放:让所有引用这个堆内存的变量赋值为null,堆内存地址不在被占用,浏览器在空闲的时候就会把堆内存 释放
var obj={name:”li”,age:45}; var obj2=obj; obj=null; obj2=null;
<a name="ryLoe"></a>
#### 2)栈内存释放:
- 销毁:全局栈内存,只有当页面关闭的时候才会被释放
- 销毁:函数执行完成,一般情况下都会被销毁掉
function fn(x){ return x+3; } fn(1);
- 不销毁:
当前作用域中如果有一个引用数据类型的值被外面的变量占用就不销毁
var function fn(){ var num=2; return function(){ console.log(num); }; }; var f=fn();
var ary=[]; function fn(){ var num=2; ary=function(){ console.log(num); }; }; var f=fn();
- 不立即销毁,(当函数执行完毕之后销毁)
function fn(x){ return function(y){ return x+y; } }
fn(1)(2);
<a name="CwvbO"></a>
# 五、闭包
function fn(i){ return function (n){ console.log(n+(++i)); } } var f=fn(2); f(3); fn(5)(6); fn(7)(8); f(4)
【知识点铺垫】
> ++ i 和 i++,
【++ i】:先自身累加,然后再运算<br />【i++】 :先运算,后累加
var i=1;
console.log(2+(++i),i)===> 4 2
var i=1;
console.log(2+(i++),i)===> 3 2
【答案】6、12、16、8
<a name="MGnHD"></a>
## 2、闭包的作用:
- 【保护】:保护里面的私有变量不受外界的干扰.
- 【保存】:形成不销毁的作用域,可以把里面的变量保存下来,
<a name="8WiD7"></a>
### 1、闭包在实战中的应用
<a name="PhhDv"></a>
#### 【1】闭包之私有变量的保护应用
【jquery】 通过window添加属性暴漏到全局
(function(){ function jquery(){ } //把jquer 这个方法通过window添加属性暴漏到全局 window.jquery=window.$=jquery; })()
在使用的时候: jquery() 或者$()
【zepto】把自执行函数的通过return把返回结果在外面用一个变量进行接收
var zepto=(function(){ return { fn:function(){}, ….. } })()
// 在使用的时候:zepto.fn
<a name="PCHqF"></a>
#### 【2】私有变量之保存机制-选项卡案例再忆
【选项卡案例原版】
<!DOCTYPE html>
- 音乐
- 电视
- 综艺
<a name="OSLHA"></a>
### 2、回忆当初里面的i 为啥是3
<a name="OhVrG"></a>
#### 1、【作用域方式去思考】
当我们触发点击事件的时候,这个函数执行,形成私有作用域, 在这个私有作用域里面,并没有私有变量i,所以就会向上级作用域进行查找,此时上级作用域就是全局作域里面的i,当我们发生点击时间的时候,此时for 循环早已完成,i早就是3
>
> 作用域:
> - window 全局作用域
> - 函数执行形成私有作用域
for (var i = 0; i < lis.length; i++) { lis[i].onclick = function () { // 这里的i为啥会变成3?当我们触发点击事件的时候,这个函数执行,形成私有作用域, // 在这个私有作用域里面,并没有私有变量i,所以就会向上级作用域进行查找,此时上级作用域就是 // 全局作用域里面的i,当我们发生点击时间的时候,此时for 循环早已完成,i早就是3 change(i); } }
<a name="gl3jo"></a>
#### 2、【同步异步事件去思考】
<a name="TEMw4"></a>
##### 【同步事件】:当一件事件做完之后,再继续下一件事情
**【异步事件】:当一件事件还没有做完,不再等待,直接去做下一个事件。所有的事件都是异步编程。**<br />**【举列子】:比如你想吃着泡面去刷剧。你先打开开关去烧水,这个时候我就站在那等,直到水烧好了,把面泡好了,我再去看电视。这个是同步事件 。 我把烧水的开关打开,我就去刷剧了,一边刷剧,一边等着烧水,水烧好了,我再去关掉.... 这个就是异步事件 **
for (var i = 0; i < lis.length; i++) { lis[i].onclick = function () { change(i); } }
for循环是同步事件,执行完i=3;点击事件是异步事件,当我们点击页面上的按钮的时候,这个for循环早已经执行完了。
lis[0].onclick = function () { change(i); }
lis[1].onclick = function () { change(i); } lis[2].onclick = function () { change(i); }
<a name="vPW74"></a>
#### 解决方法:
<a name="IUiYr"></a>
##### 1)自定义属性
<a name="oRsjq"></a>
##### 2)闭包
for (var i = 0; i < lis.length; i++) { // 之前i找到的上级作用域是window,现在我们手动增加一层作用域,用一个闭包的形式,里面把点击事件赋值 //给了外面的元素,被占用,形成不销毁的作用域.n是私有变量,当点击页面上的元素的时候,就会找闭包作用域 //中的私有变量n
(function(n){
lis[n].onclick = function () {
change(n);
}
})(i)
}
for (var i = 0; i < lis.length; i++) {
//每次for循环,就给li绑定一个点击事件,并且点击的事件的值是return里面的小函数,形成了不销毁的作用域
当我们点击li的时候,里面的小函数就会执行,变量i就是自执行函数里面的私有变量
lis[i].onclick=(function(i){
return function(){
change(i);
}
})(i)
}
<a name="slDJV"></a>
##### 3)let
for (let i = 0; i < lis.length; i++) { lis[i].onclick=function(){ change(i); } }
块级作用域:在es6语法中,一般用{} 括起来的都是块级作用域:
- 在块级作用域外面访问不到里面的变量
- 块级作用域也有作用域链(块级作用域也可以进行嵌套)
{ console.log(a);// a is not defined let a=8; console.log(a); } console.log(a); //Uncaught ReferenceError: a is not defined
{ let a=2; { console.log(a);// 在这个块级作用域中没有,就会向上级进行查找 } }
console.log(a); //Uncaught ReferenceError: a is not defined
<a name="hNDNo"></a>
### 6、练习题:
<a name="mvULM"></a>
#### 1、
console.log(a); var a=12; function fn(){ console.log(a); var a=13; } fn(); console.log(a);
// A、undefined 12、13 // B、undefined undefined、12 // C、undefined undefined、13 // D、有程序报错
<a name="OSljw"></a>
#### 2、
console.log(a); var a=12; function fn(){ console.log(a); a=13; } fn(); console.log(a);
// A、undefined 12、13 // B、undefined undefined、12 // C、undefined undefined、13 // D、有程序报错
<a name="C78Ko"></a>
#### 3、
console.log(a); a=12; function fn(){ console.log(a); a=13; } fn(); console.log(a);
// A、undefined 12、13 // B、undefined undefined、12 // C、undefined undefined、13 // D、有程序报错
<a name="GYmri"></a>
#### 4、
var foo=1; function bar(){ if(!foo){ var foo=10; } console.log(foo); } bar();
A 1 B 10 C undefined D 报错
<a name="XLZ6r"></a>
#### 5
var n=0; function a(){ var n=10; function b(){ n++; console.log(n); } b(); return b; } var c=a(); c(); console.log(n);
<a name="AB9Ux"></a>
#### 6、
var a=10,b=11,c=12; function text(a){ a=1; var b=2; c=3;
} text(10); console.log(a); console.log(b); console.log(c);
A 1 11 3 B 10 11 12 C 1 2 3 D 10 11 3
<a name="H5F5j"></a>
#### 7
if(!(“a” in window)){ var a=1;
} console.log(a); A undefined B 1 C 报错 D 以上答案都不对
<a name="zg8i1"></a>
#### 8
var a=4; function b(x,y,a){ console.log(a); arguments[2]=10; console.log(a); } a=b(1,2,3); console.log(a)
<a name="knYlu"></a>
#### 9
var foo=”hello”; (function(foo){ console.log(foo); var foo=foo||”word”; console.log(foo); })(foo); console.log(foo);
A hello hello hello B undefined world hello c hello world world D 以上答案都不正确
<a name="BJg4Q"></a>
##### 逻辑与&& 和逻辑或
1、条件判断中使用<br />2、赋值
var a=1||2 如果第一个值是真,那a的值就是第一个,如果第一个值为假,把第二个值赋值给它 var b=1&&2 如果第一个值的真,那就把第二个值赋值给b,如果第一个值是假的就把第一个值赋值给它
<a name="0qg41"></a>
#### 10、
var a=9; function fn(){ a=0; return function(b){ return b+a++; } } var f=fn(); console.log(f(5)); console.log(fn()(5)); console.log(f(5)); console.log(a);
<a name="4MJxM"></a>
##### 11、
var ary=[1,2,3,4]; function fn(ary){ ary[0]=0; ary=[0]; ary[0]=100; return ary; } var res=fn(ary); console.log(ary); console.log(res);
<a name="GHrGh"></a>
#### 12、
function fn(i){ return function (n){ console.log(n+(++i)); } } var f=fn(10); f(20); fn(20)(40); fn(30)(50); f(30);
<a name="er1fj"></a>
#### 13、
var i=10; function fn(){ return function(n){ console.log(n+(++i)); } } var f=fn(); f(20); fn()(20); fn()(30); f(30);
<a name="b8DUq"></a>
# this关键字
> 函数执行的主体,意思是谁把函数执行的,那么执行主体就是谁。(不是上下文)
> this非常不好理解,但是我们会对此总结几条规律,让你能迅速而准确的找到this是谁。
<a name="gvU0U"></a>
## 1)在全局作用域下,this就是window
console.log(this);
<a name="MIjWM"></a>
## 2)函数执行的时候,看它前面有没有点,如果有,点前面是谁,this就是谁,如果没有,就是window(在非严格模式下),在严格模式下就是undefined
function fn(){ console.log(this) } fn();//这里的this就是window,在严格模式下就是undefined
var obj={ name:”li”, fn:fn, }
obj.fn();//这里的this就是obj
<a name="aSLJ3"></a>
## 3)当给元素绑定事件的时候,在函数执行体中的this就是绑定的元素
ele.onclick=function(){ console.log(this)//===>ele }
<a name="kNygZ"></a>
## 4):自执行函数里面的this是在非严格模式下是window,严格模式下是undefined
(function(){ console.log(this); //window })();
“use strict”; (function(){ console.log(this);// undefined })();
<a name="6BgiM"></a>
## 5):回调函数中的this是window
setTimeout(function (){ console.log(this); }, 1000);
<a name="P0Z3K"></a>
## 6): 构造函数中的this,是当前类的实例(后面讲)
<a name="BSpb5"></a>
## 7):通过bind、call、apply可以改变this的指向(后面讲)
<a name="14vS7"></a>
# 【this 练习题】
<a name="mBAYl"></a>
## 1)
var name=”珠峰培训”; function fn(){ console.log(this.name) } var obj={ name:”你好世界”, fn:fn } obj.fn(); fn();
(function(){ this.fn(); })();
<a name="iKokU"></a>
## 2) 说出里面的this
let obj={ name:”li”, fn:(function(n){ // 这里的this console.log(this); return function(){ // 这里的this console.log(this); } })(10), } obj.fn();
```
function fn(){
// 这里的this
console.log(this);
}
box.onclick=function(){
console.dir(this);
fn()
}
3)
var num=10;
var obj={num:20};
obj.fn=(function(num){
this.num=num*3;
num++;
return function(n){
this.num+=n;
num++;
console.log(num);
}
})(obj.num);
var fn=obj.fn;
fn(5);
obj.fn(10);
console.log(num,obj.num)
面向对象编程:
了解面向对象编程思想,需要先了解对象、类、实例。万物皆对象,一切都可以看成对象,什么是类?比如咱们自然界中有很多的生物,咱们可以把这些生物分为:植物、动物。。。,那植物就是一个类,动物也是类,动物还可进行细分,比如:高级动物、低级动物,都是分类。什么是实例呢?比如说人类是一个分类,那具体的某个人,比如:丽丽就是一个人类中的一个实例,我想研究人类有哪些特点,就具体的拿这个人来研究就行。咱们在学习js的时候,也是按照这个思想去学习。
- 对象:万物皆对象
- 类:对象的具体细分,按照功能或者特征进行分类
- 实例:类中具体的一个事物(拿出具体的一个实例进行研究,当前类下的其它实例也会具有这些特点和特征)
一、单例设计模式:
单例模式:可以把描述一个事物的所有属性放到一个对象中,这样避免了相互的干扰,这种设计模式就是单例设计
在单例设计模式中,obj不仅是对象名,它也被称为“命名空间”(NameSpace)。每个命名空间都是Object这个内置基类的一个实例,每个实例之间都是相互独立,互不干扰,这种设计模式就是“单例设计模式”
var name="wangzhe";
var age=18;
var sex="女";
var name="shuaiyuan";
var age=20;
var sex="男";
var obj1={
name:"wangzhe",
age:18,
sex:"女"
}
var obj2={
name:"shuaiyuan",
age:20,
sex:"男"
}
1、【表现形式】:就是一个对象
var obj={
属性名:属性值,
属性名:属性值
}
2、【高级单例模式】
nameSpace 和自执行函数没有关系,最终是等于自执行函数的返回值,最终是把返回对象的堆内存的地址给了nameSpace。在面试的时候,咱们可以写这个复杂的。
var nameSpace=(function(){
function fn(){},
var a=2;
//... 在这个作用域中还有很多的变量和方法,
return{
// 想要把谁暴露出去,就放到这对象中
fn:fn
}
})();
console.log(nameSpace.fn)
3、【项目实战中单例模式的应用】
- 在公司一般都是团队协作开发,每人都会分配不同的任务,开发自己的模块
- 对于整个项目中,公用的功能,可以提取出来,供大家使用
//员工A:首页模块的开发
var indexModel=(function(){
function fn2(){
}
//...
return {
init:function(){
// 想要调用自己模块里面的方法:
fn2();
},
// 如果 员工B 想要调员工A里面的方法fn2,只用把这个方法暴露出去
fn2:fn2
}
})();
// 想要初始化函数:indexModel.init();
//员工B:详情页的开发
var messageModel=(function(){
function fn(){
}
//...
return {
init:function(){
// 想要调用自己模块里面的方法:
fn();
// 调用A员工模块里面的fn2方法
indexModel.fn2();
}
}
})();
// 想要初始化函数:messageModel.init();
对于公用性模块也可以用单例模式
var utils=(function(){
function fn(){
};
function b(){
};
// ....
return {
fn:fn,
b:b
}
})();
// 想要用这些方法:
utils.fn();
utils.b();
.....
二、工厂设计模式
把实现相同功能的代码进行封装,后期在使用的时候,只用调用这个函数即可,方便后期的“批量生产”。减少了页面中冗余的代码,实现了“高耦合低内聚”。
比如:
var person1={
name:"lili",
age:18
}
var person2={
name:"dava",
age:20
}
//....每次都需要重复的去写,很麻烦,所以就可以用工厂模式
function person(name,age){
return{
name:name,
age:age
}
}
person("lili","18")
person("dava","20")
三、构造函数模式(自定义类)
1、构造函数初步理解
- 把一个普通的函数,在执行的时候加了一个new 那这个函数就是构造函数,当前的函数名称为“类名”比如下面例子中的Fn 就是类,f1,f2 就是实例
- 函数执行的返回结果就是当前构造函数的一个实例,比如f1、f2 就是当前函数的一个实例
- 构造函数一般名字都大写
- f1 和f2 是独立的堆内存,不相等
- 这种构造函数设计模式一般主要用在类库、框架等的封装,在日常的业务逻辑中很少去使用。
function Fn(){ // fn 是类
}
var f1=new Fn(); // f1 是实例
var f2=new Fn(); // f2 是实例
2、【初步感受下构造函数】
在构造函数中,通过this添加的属性,在实例中通通都会有,并且实例和实例是独立分开的,互不影响(不同的堆内存)
function Fn(){
this.name="lili";
this.age=18;
this.fn=function(){console.log(1)}
}
var f1=new Fn(); //Fn {name: "lili", age: 18, fn: ƒ}
var f2=new Fn(); //Fn {name: "lili", age: 18, fn: ƒ}
console.log(f1==f2);//false
function Fn(name,age){
this.name=name;
this.age=age;
}
var f1=new Fn("lili",18); //Fn {name: "lili", age: 18}
var f2=new Fn("dawei",20); //Fn {name: "dawei", age: 18}
3、【构造函数的原理】
【思考题】:
function Fn(name,age){
var n=10;
this.name=name;
this.age=age;
}
var f1=new Fn("lili",18);
var f2=new Fn("dawei",20);
console.log(f1==f2);
console.log(f1.name);
console.log(f1.n);
console.log("name" in f1);
4、构造函数中,如果我们手动的return了一个值,那结果又如何呢?
【总结】:在构造函数中,如果我们手动返回一个基本数据类型的值,没有任何的影响,最终返回的还是浏览器自己创建的那个实例;如果我们手动返回一个引用数据类型的值,最终返回的结果就是我们手动返回的这个引用数据。
所以在构造函数中,我们尽量减少return 的使用,防止覆盖原来的。
// 当返回的是基本数据类型
function Fn(){
this.name="lili";
return 100
}
var f1=new Fn(); //{name: "lili"}
function Fn(){
this.name="lili";
return {
age:30,
fn:1
}
}
var f1=new Fn();
console.log(f1);//{age: 30, fn: 1}
5、【return】
function Fn(name,age){
var n=10;
this.name=name;
this.age=age;
return; // 这里的return 会阻止下面的代码不再运行,但是没有覆盖原来的返回值(浏览器机制创建的空对象)
console.log(1);
}
var f1=new Fn("lili",18);
var f2=new Fn("dawei",20);
6、【instanceof】
判断 某个实例是否隶属于那个类(构造函数)
function Fn(name,age){
var n=10;
this.name=name;
this.age=age;
return;
console.log(1);
}
var f1=new Fn("lili",18);
var f2=new Fn("dawei",20);
console.log(f1 instanceof Fn);// true
console.log(f1 instanceof Array);//false
console.log(f1 instanceof Object);//true 万物皆对象,多有的对象,及实例都是Object这个基类的实例
7、【in】检测当前对象是否存在某个属性
不论是共有属性,还是私有属性,只要是对象的属性,通过in进行检测返回值都是true
function Fn(name,age){
this.name=name;
this.age=age;
}
var f1=new Fn("lili",18);
/*
“name” 是f1 的私有属性,
"toString"是f1的共有属性,
不论私有还是公有,用in检测的结果都是true
*/
console.log("age" in f1);//true
console.log("toString in f1")//true
8、[hasOwnProperty]
检测一个属性是不是这个对象的私有属性,如果是,返回true,如果不是返回false
function Fn(name,age){
this.name=name;
this.age=age;
}
var f1=new Fn("lili",18);
f1.hasOwnProperty("name");// true
f1.hasOwnProperty("toString");//fasle
9、【思考题】
编写一个hasOwnPubProperty方法,检测一个属性是不是公有的
function Fn(name,age){
this.name=name;
this.age=age;
}
var f1=new Fn("lili",18);
//var f2=new Fn("dawei",20);
function hasPubProperty(attr){
//如果是true,说明不论是公有还是私有,起码是
if(attr in this) {
if(!this.hasOwnProperty(attr)){
// 不是私有的说明就是公有的
return true;
}
}
return false;
}
Object.prototype.hasPubProperty=hasPubProperty;
console.log(f1.hasPubProperty("toString"))//true
console.log(f1.hasPubProperty("name"))//false
10、【js创建值的两种方式】
- 字面量方式:var obj={};
- 基于构造函数: var obj2=new Object()
不管是哪种形式创建的,这些对象都是Object的一个实例。
注意:基本数据类型用字面量方式创建的实例,不是标准的实例,所以用instanceof 进行检测的时候不行,但是类的所有方法都可以照常使用
var n1=1;
var n2=new Number(1);
console.log(typeof n1);//"number"
console.log(typeof n2);//"object"
n1.toFixed(2);//"1.00"
n2.toFixed(2);//"1.00"
原型和原型链
思考: var ary=[1,2,3]; 为什么 ary就可以用Array这个类上面的公用方法:push、splice、pop…,甚至还可以用Object这个类上面的方法,比如toString呢?要想知道这个答案,咱们就需要来了解下原型(prototype)和原型链(proto)
1、【原型和原型链知识】
- 所有的函数都有一个属性prototype,这个属性是对象数据类型,浏览器会默认给它开辟一个堆内存
- prototype这个原型上天生自带一个属性:constructor,指的是当前的构造函数
- 所有的对象都天生自带一个属性proto,它指向当前实例所属类的原型
【函数】:普通函数、构造函数
【对象】:普通的对象、数组、实例、prototype(原型)等
2、【画图理解】
function Fn(){
var n=100;
this.A=function(){console.log("私有A")};
this.B=function(){console.log("私有B")}
}
Fn.prototype.A=function(){console.log("公有A")};
var f1=new Fn();
var f2=new Fn();
console.log(f1.A==f2.A);
console.log(f1.__proto__.A==f2.__proto__.A);
console.log(f1.__proto__.A==Fn.prototype.A)
3、【原型链查找机制】:
- 当我们要查找或者操作实例上的某个方法或者属性的时候,我们会先查找实例的私有属性,看看私有上是否有,如果有,停止查找;
- 如果没有,就会基于proto向上查找,如果找到,就是公有属性;
- 如果还没有,继续基于__proto原型链向上查找,直到Object基类,如果都没有,就是操作方法或者属性不存在
一周综合练习题
14、
var num=10;
var obj={num:20};
obj.fn=(function(num){
this.num=num*3;
num++;
return function(n){
this.num+=n;
num++;
console.log(num);
}
})(obj.num);
var fn=obj.fn;
fn(5);
obj.fn(10);
console.log(num,obj.num)
【答案】:22 23 65 30
15
function Fn(){
this.x=100;
this.y=200;
this.getX=function(){
console.log(this.x);
}
}
Fn.prototype.getX=function(){
console.log(this.x);
}
Fn.prototype.getY=function(){
console.log(this.y);
}
var f1=new Fn;
var f2=new Fn;
console.log(f1.getX==f2.getX);
console.log(f1.getY==f2.getY);
console.log(f1.__proto__.getY==Fn.prototype.getY);
console.log(f1.__proto__.getX==f2.getX);
console.log(f1.getX===Fn.prototype.getX);
console.log(f1.constructor);
console.log(Fn.prototype.__proto__.constructor);
f1.getX();
f1.__proto__.getX();
f2.getY();
Fn.prototype.getY();
16、
var fullName="languge";
var obj={
fullName:'javascript',
prop:{
getFullName:function(){
return this.fullName;
}
}
};
console.log(obj.prop.getFullName());
var test=obj.prop.getFullName;
console.log(test());
17
var name="window";
var Tom={
name:"Tom",
show:function(){
console.log(this.name);
},
wait:function(){
var fun=this.show;
fun();
}
};
Tom.wait();
18\
function fun(){
this.a=0;
this.b=function(){
alert(this.a);
}
}
fun.prototype={
b:function(){
this.a=20;
alert(this.a);
},
c:function(){
this.a=30;
alert(this.a)
}
};
var my_fun=new fun();
my_fun.b();
19
var n=2;
var obj={
n:3,
fn:(function(n){
n+=2;
this.n+=2;
var n=5;
return function (m){
this.n*=2;
console.log(m+(++n));
}
})(n)
};
var fn=obj.fn;
fn(3);
obj.fn(3);
console.log(n,obj.n)
【答案:】9 10 8 6