JS学习笔记

JS是什么?

JS全称为javascript,他是一门编程语言。
1,js和html,css的对比
相同点:html,css,js代码都可以在浏览器中运行,html,css,js它们的运行环境是浏览器
不同点:html,css不是编程语言,而js是编程语言,js的运行环境也不只浏览器。
2,js可以做什么?
js作为前端开发的语言,主要用于开发网站,app,小程序等,node.js也可以进行后端程序的编写。
3,js写在哪?
1,js可以直接写在html中的script标签中(但一般不这样用,小型的简单界面可以用)
2,js一般都是单独创一个js文件夹,写在相应的js文件夹中,通过import或者link进行引用。
3,js也可以写在开始标签中,当成开始标签的属性(行内写法)

JS的基本语法

以下是js中常用的基本语法
1,JS是区分大小写的 var a=1, var A=1;
2, JS是忽略空格,换行 tab的 var a=1也可以写成下图所示,但最好别这么搞。

var
a
=
1

3 语句分号可加可不加,但有一点就是你要加你就都加,要不加就都不加,我个人觉得是加上最好。
4,//单行注释 /**/多行注释在js中也是可以用的。
5,标识符和关键字,var a=1;其中var为关键字,a为变量名标识符

JS中的变量

说到了变量,那我们就先来说说数据一个软件打开后,界面上有很多的数据,也叫状态,这个状态可以保存在 两个地方,一个是内存,一个是硬盘项目运行起来,只有把数据加载到内存中,才使用使用数据。 内存中的数据,一断电,数据就没了,还有一个地方,也可以保存数据,是硬盘,硬盘上的数据断电是不会丢失的。内存空间地址:就是一块内存空间的地址,可以通过地址操作它对应空间中的数据,使用地址来操作非常不方便,指针。
变量变量就是内存中的一个空间。
变量名内存空间的别名,对变量名的操作就是对内存空间的操作
变量值 存储在内存空间中的状态(数据)

在js定义一个变量

用var定义变量

var a=1;这个就是定义了一个变量,变量的名是a,变量的值为1
var obj={name:“张三”,age:100};这个是定义一个对象,既然提到了对象,那么就来说一个运算吧 in 用来判断一个对象有没有相对应的属性,返回的是boolean值, console.log(“name” in obj);
在计算机中,=叫做赋值运算符,其中就是把1这个number值给a这个变量名所对应的内存空间。
如果在块作用域{}中进行声明-----没有块的概念,可以跨块访问, 不能跨函数访问,有变量提升

用let和const定义变量

1,let声明的变量:没有没有提升(let声明的变量也提升,仅仅是没有初始化)只能在块作用域里访问,不能跨块访问,也不能跨函数访问,无变量提升,不可以重复声明
2,let配合{}也可以形成块级作用域。

if(true){
var a = 110; // 全局变量
let b = 666; // let + {} 形成块级作用域, b只能在当前的{}中被访问到 出了块就访问不了
}
console.log(b); // b is not defined

3,使用let声明的变量不会挂载到GO上
4, 使用let不能重复声明
5, 再进行JS代码编写声明变量时最好用let最好别用var。
6,如果在块作用域{}中进行声明-----只能在块作用域里访问,不能跨块访问,也不能跨函数访问,无变量提升,不可以重复声明。

const与let的使用规范一样,但是有一点不同就是const声明的是一个常量,而且这个常量必须赋值,否则会报错

变量的分类

变量分为全局变量和局部变量,怎么区分什么是全局变量和局部变量呢?在js中就看定义的变量是否在函数中,那什么又是函数呢? function f() { var m = 111; // 局部变量 } 这个f()就是函数,在js中函数必须是用function定义的,如果没有用function定义那么他就不是函数,如for(var a=1; a<2; a++){ var b=a}这里for就不是函数,b为全局变量。

全局变量和局部变量的特点

1,全局变量可以在函数内部都能访问到
2,局部变量只能在函数内部访问到

JS的预编译

JS代码在执行是分为两个阶段:1,预编译 2,代码执行。
什么是预编译呢? 预编译就是js代码执行前的操作,比如说你定义了一个变量 var a=1;定义=声明变量+给变量赋值。声明变量就是定义一个变量。如果你这个变量是全局变量,那么他就会在预编译的时候 最先执行声明变量,如果是局部变量就在其函数中最先执行声明变量。来吧直接上代码

console.log(a);
var a=100;
function f(){
console.log(b)
var b=10;
}
console.log(a);

在这个代码中 a 和b 都在代码执行之前进行了预编译,使其声明提前,所以现在console.(a)和console.(b) 都不会报错,但是预编译也仅仅是提升了变量的声明,其赋值还是得按照从上到下的顺序一步步执行,所以此时console.(a)和console.(b) 的输出均为undefined。

执行上下文

执行上下文(Execute Context)简称EC
EC的作用:给代码提供数据,代码分为两类分别为全局代码和函数代码
全局代码
函数外面的代码叫全局代码
函数代码
一个函数就是一个局部代码
全局执行上下文
全局代码在执行时,就会产生全局的EC。EG(G)
局部执行上下文
函数代码在执行时,就会产生局部的EC。调用一个函数就产生一个EC,调用100个函数,就产生100个EC。
EC栈
可以把栈比作一个盒子,每产生一个EC就放到盒子里,栈的特点是先进后出。
ECStack
执行上下文

JS中的AO,VO,GO和Scope,ScopeChain

AO:全称activation object 活动对象,当函数被激活时,一个AO就会被创建并且分配给执行上下文。活动对象由特殊对象arguments初始化而成。随后,他被当作VO用于初始化变量。存储局部的加var 或 加function的局部数据
VO: 全称(variable object)变量对象,每一个执行上下文都会分配一个EC而每一个EC都会分配一个VO,变量对象的属性由 变量(variable) 和 函数声明(function declaration) 构成。在函数上下文情况下,参数列表(parameter list)也会被加入到变量对象(variable object)中作为属性。变量对象与当前作用域息息相关。不同作用域的变量对象互不相同,它保存了当前作用域的所有函数和变量。 存储的全局的加var 或 加function如果一个变量存在于VO中同时也存在于GO中,那么 当VO中该数据被修改时,GO中的数据也会被修改。
如果定义一个变量 a=10;那么其只会存在GO中,并不会存入VO中
**GO:**其实就是一个全局对象,只要是一个全局变量或者全局函数都会挂载到window上。 默认情况下,里面就存储了很多东西全局的数据,加Var的全局数据,加functon的全局数据,不加var的变量都会存储到GO中的如果一个变量存在于VO中同时也存在于GO中,那么 当GO中该数据被修改时,VO中的数据也会被修改。
如果用 window.a =10; 定义一个变量,那么其只会存在GO中 如果 var a =10,delete window.a 那么 VO中的a并不会被删除。
Scope作用域。
ScopeChain作用域链。作用域链其实就是所有内部上下文的变量对象的列表。用于变量查询。作用链也可以说是数据的查找机制,找一个数据,先在自己的EC中找,找不到, 去父函数所在的EC中找,如果还找不到,就去父函数的父函数EC中找,直到找到全局EC,如果还找不到,就报错了。
下面写一些相关的例子。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

加var的变量和没有加var的变量的区别

1,加var的变量如果在函数中是局部变量,如果不在函数中为全局变量 ,而不加var的必定也只能是全局变量。
2,加var的变量在进行缓加载时会将声明的变量提升,就是声明的全局变量最先执行(并没有值,只是声明有这个变量,在执行定义代码之前如果使用这个变量不会报没有定义的错,仅仅是没有值。局部变量就是提升声明到函数内最先执行)而不加var的变量就不会有提升
3,加var的局部变量,不会作为window的属性。

JS中的函数

1,函数是任何编程语言都有的概念。
2,在JS中定义函数有两种形式。为函数定义和函数表达式。
3,函数定义 f叫函数名 ()是函数特有的标识 {} 叫函数体。

function f() {
     console.log("hello")
    }

4,函数调用f(); 调用函数时,就会把函数体中的代码都执行了。
5,函数的返回值function f() {return 666;}函数的返回值是返回到了函数调用处。
6,var a = f();函数调console.log(a);console.log(f()); f()得到的就是函数的返回值。
7,一个函数如果没有返回值,默认返回undefiend例如function f(){}console.log(f()); // undefined。
8, 给函数传递数据
function f(a,b) { // a b叫形式参数 形参
// 形参就是函数内部的局部变量
return a+b;
}
// 1 2叫实际参数 实参
var r = f(1,2); // 函数调用的过程就是实参向形参赋值的过程
console.log®;

9,如果JS中定义的一个函数没有返回值,那么默认的返回值为undefined
10,JS中如果调用一个带有形式参数的函数,那么在执行的时候参数会先挂载到他的AO中
11,JS中代码进行缓加载时函数会被提升,这里他提升的是自己的结构体
12,在一段代码中如果同时对一个方法进行多次定义,那么在缓加载的时候,这个方法只进行一次提升,但是其结构体会进行覆盖,定义=声明+结构体(赋值)
13,如果将函数赋给一个变量时,是把函数的地址赋给变量,函数的结构体存在堆中。
14,如果定义的全局函数在一个含有判断代码中那么该函数在预加载的时候只会进行提升,并不会将结构体的地址赋给函数,函数的默认值为undefined整个例子如下图所示
在这里插入图片描述

JS中的数据类型

数据类型的作用:为了更加合理的使用内存(栈内存,和堆内存)
1,基本数据类型(数据存储在栈区)
number var n = 123; 内存空间中就存储了一个数据 console.log(n)
string var str = “hello”; console.log(str);
boolean var f = false; console.log(f)
如果不是布尔值类型的数据需要进行布尔值的判断操作,那么会发生隐式转换,
number类型:只有 0为false,其余的为true(负数也为true)。
string类型:如果为" "那么其布尔值为false,其余的为true。
undefined类型:其布尔值为false。
undefined:undefined既是数据类型,也是值。
null
2,引用数据类型 (数据存储在堆区)
object var obj = {name:“wc”,age:123} conosle.log(obj.name)
array var arr = [“a”,“b”,“c”] console.log(arr[0])
function var f = function (){ var i=0; var j=1;} 这个堆区存储的是函数体。

JS中的闭包(closure)

定义:(官方的定义)在JS中的一个函数内部嵌套了另一个函数,并且这个里面嵌套的函数中引用了父函数的数据,那么这里面的函数就可以叫作闭包,其特点是,当父函数执行完代码出栈后并不会被销毁,如果掉用子函数时,子函数还会调用父函数中的数据。来直接整个例子。
(通俗的说)一个不能被销毁执行上下文就是一个闭包,它有两大作用:
A)保护 位于闭包的数据 外界是不能访问
B)保存 EC出栈了 数据是没有销毁 数据的生命周期延长
缺点:造成内存空间的泄露   合理使用闭包

var i = 5;
    function fn(i) {
        return function (n) {
            console.log(n+(++i));
        }
    }
    var f = fn(1);
    f(2);
    fn(3)(4);
    f(7);
    console.log(i);

这个代码中f()就是一个闭包,因为其中引用了父函数fn(i)中的i,在执行var f=fn(1)时,父函数将f()函数的地址赋给f,正常情况下如果父函数执行完代码,那么其AO中的数据和生成的堆都会被销毁。但因为该函数时闭包,所引用的数据i是父函数中的i,故此时父函数并不会被销毁,还能接着被调用。
来就以这段代码为例 咱来说说流程
首先进行预加载
将i=undefined,fn(i)=fn(i)的结构体的地址,f=undefined,存入EC(G)的VO中,和window的PG中。
执行代码
var i=5
将5赋值给i,此时VO和GO中的i有undefined变为5,接下来执行
var f=fn(1)
先执行fn(1),此时生成一个执行上下文,咱们这里就叫EC(fn(1))把,此时先将参数 i=1,存入其AO中,然后将f()的结构体地址赋值给变量f,此时要注意代码console.log(n+(++i))中的i引用的是父函数中的i也就是说此时的f就成了一个闭包,所以EC(fn(1))执行完出栈后其数据并不会被销毁,
f(2)
此时生成一个执行上下文,咱们这里把他叫EC(f(2)),先将参数n=2,存入其AO中,接下来执行 console.log(n+(++i));而i引用的是EC(fn(1))中的i,故此时输出为4,并且将EC(fn(1))中的i变为2。因为没有闭包函数的引用,所以EC(f(2))执行完后其数据被销毁。
fn(3)(4)
此时生成一个执行上下文,咱们这里把他叫EC(fn(3)),
此时将i=3存入其AO中,并将新的f(n)的函数体地址返回(需要注意的是这里返回的函数体地址是新的地址,与前面fn(1)返回的地址并不一样),此时执行f(4),生成EC(fn(3)(4)),将n=4,存入其AO中,然后执行console.log(n+(++i));这里的i就是EC(fn(3))中的i故其输出为8.
f(7)
此时生成一个执行上下文,咱们这里就EC(fn(7)),
将n=7存入其AO中,执行console.log(n+(++i));因为f是闭包,所以这里的i还是之前EC(fn(1))中的i,所以这里为输出7+(++2)输出的是10.
** console.log(i)**
这里输出的i为VO中的i,输出的为5.
在谷歌浏览器中也可以找到闭包如下图
在这里插入图片描述
其中closur中的值就为闭包中所调用的值。
在整个例子
在这里插入图片描述
在这里插入图片描述
作用域链的基本流程:
在这里插入图片描述

JS中++i与i++的区别

这两个都是自增1,但是区别就是一个是先增加在输出,另一个是先输出再增加。不多bb直接上代码,直观的看他们俩的区别
在这里插入图片描述
很直观,在JS执行代码是i++在输出后进行自增。++i是在输出前进行自增。

JS中的逻辑&&(与)、||(或)

&&的特点
1,具有左结合性,举个例子
var c = a&&b&&c相当于 (a&&b)&& c
2,有一个操作数为假那么整体的结果就是假。
var c=0&&7&&8,结果为0(false)。
||的特点
1,具有右结合性,举个例子
var c = a||b||c相当于 a||(b||c)
2,有一个操作数真那么整体的结果就是真。
var c =0||7||8,其结果为7(true)。
&&与||的优先级
&&的优先级高于|| 举个例子
var c=1||2&&3||4&&5||6;
其执行顺序为
=1||(2&&3)||(4&&5)||6
=1||3||(5||6)
=1||3
结果为 1(true);

JS中的异常处理机制

首先是常见的基本的try…catch语句
其结构为

try{
//这里是可能会发生异常的代码
}catch(error){
//发生错误时所执行的代码。它里面包含了错误信息。通过查看error,可以知道它到底出了什么错误
} 来吧直接整个例子
try{
console.log(a); // 放可能出错的代码
}catch (error) {
console.log(“console: 报错”,);
}

这个就是JS中最基本最常见的异常处理机制的结构,

特点:如果try中的代码报错(注意:在try中,报错的那行代码后的代码都不会执行),那么就会直接进入catch中,发送错误信息。然后代码继续执行代码。并不会因为代码发生异常而导致整个程序无法正常运行,这也是异常处理机制存在的意义。

还有一个是基本上不用的try…catch…finally的结构
这个结构基本上没人用,但有时后你看有些代码中会有这样的代码。
try…catch…finally与try。。catch结构的区别

1,在try…catch结构中,如果try中的代码正常运行,那么就不会执行catch中的代码,但是在try…catch…finally中,无论你try中的代码对不对,都会执行finally语句。我所了解的暂时就这一点区别,所以显得finally比较鸡肋,故而基本上没人用。

JS中的同步和异步代码

同步:代码的执行顺序和代码的书写顺序一致,由上到下依次执行。

异步:代码中执行顺序和代码的书写顺序不一致。

在JS中,异步代码仅仅是个别:
1,事件绑定
2,定时器
3,ajax
。。。
整一个异步的例子

var btns =document.getElementsByTagName(“button”); // 数组容器
// 同步代码
for (var i=0; i<btns.length; i++){
// 事件绑定 异步代码 浏览器在执行时直接忽略掉
btns[i].onclick = (function (i) {
return function g() {
console.log(i)
}
})(i);
}

JS中块级作用域

定义

JS中作用域有:全局作用域、函数作用域。没有块作用域的概念。ECMAScript 6(简称ES6)中新增了块级作用域。
块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。

用let配合{}可以形成块级作用域。
特点:只能在块作用域里访问,不能跨块访问,也不能跨函数访问,无变量提升,不可以重复声明
整个例子:

var btns = document.getElementsByTagName(“button”);
for (let i=0; i<btns.length; i++){
btns[i].onclick = function () {
console.log(i)
}
}
for(b=0;b<3;b++){
console.log(btns(b).onclick()) // 0 1 2
}
console.log(i) //报错Uncaught ReferenceError: i is not defined

需要注意的是这里每进行一次for循环,就会执行一次上下文,这里每一次执行所的function就相当于一个闭包

如果用var声明,重新执行上面的例子

var btns = document.getElementsByTagName(“button”);
for (var i=0; i<btns.length; i++){
btns[i].onclick = function () {
console.log(i)
}
}
for(b=0;b<3;b++){
console.log(btns(b).onclick()) // 3 3 3
}
console.log(i) //3

结果显而易见,每次调用的函数中的i调用的是VO中的i。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值