JavaScript从入门到放弃 第一步
一. 走进javaScript黑洞
1. 注释与执行符
单行注释
console.log(1); // 未注释,控制台打印1
// console.log(1); 注释之后控制台不会输出,就是让此行代码无效
多行注释
/*
* console.log(1);
* console.log(2);
**/
每段代码后要加【;】分号,要不然,代码压缩的时候,所有代码在一行显示,会报错,平时写代码要养成良好习惯,要加分号
2. 变量声明相关知识
1. 使用var声明
// 必须以字母、下划线或美元符号开头,后面可以跟字母、下划线、美元符号和数字
var myName = 'zcy';
var myName = 'zcy';
var _myName = 'zcy';
$name = 'zcy';
2. 错误的变量声明
var 6name; // 开头不能用数字
var %sum; // 开头不能用除(- $)外特殊符号,如(% + /等)
var sum+num; // 开头中间不能使用除(_ $)外特殊符号,如(% + /等)
注意: jqury使用的$符号,所以我们尽量不要用单独的$作为变量
3. 一次声明多个变量,使用逗号隔开最后一个用分号结束
var a = 1,
b = 2,
c = 3;
4. 多个变量赋值为相同的值
var a = b = c = d = 1;
5. 特殊的name属性
我们没有声明name属性,但直接打印name属性是有值的,name指的是窗口的名字,所以使用name属性要注意些
console.log(name); // ''
console.log(window.name); // 是一样的 ''
3. js解析过程(预解析)与变量提升
当我们使用关键字进行声明的时候,会报错 如下图所示
var if = 1;

// 我们来看这个例子,js执行顺序是从上往下执行,那么是不是先打印变量a,在报错呢,我们验证一下猜想
var a = 1;
console.log(a);
var if = 1;

// 我们的验证是错误的,并没有打印变量a,直接报错,这是为什么呢?
// 原来是因为执行js代码前,解析器会分析我们的代码(也叫预解析),在这个分析过程中就执行了变量提升;
我们看个例子,我们先打印个没有声明过的变量
console.log(zbc);

我们不难发现直接打印一个未声明的变量会报错
那么我们看下面这个例子,大家是否觉得。还是会报错呢?
console.log(lan); // 别问我为什么是lan(澜)
var lan = 'A';

结果是没报错,打印变量lan为undefined,这是为什么呢?大家心里一定想js执行代码,不是从上往下执行么,为什么在打印语句,后面声明lan变量不会报错呢?
我们之前说过执行js代码前,解析器会分析我们的代码(也叫预解析),在这个分析过程中(预解析)就执行了变量提升。
那么什么是变量提升?
console.log(lan); // undefined
var lan = 'A';
// 上面的声明变量的语句,原来做了两件事
1. var lan;
2. lan = 'A';
所以说执行js代码前,解析器会分析我们的代码,把第一步提到前面了,上面的代码就变为下面代码,这就是变量提升
var lan;
console.log(lan); // 如果一个变量只声明,未赋值那么值未undefined
lan = 'A';
4. let与const暂时性死区
我们上面说到变量提升是不好的,一般推荐是,先声明在使用,当有变量提升之后是可以先用,后声明这样是不好的,所以我们引用let,const解决这种变量提升的问题,暂时性死区就是必须先声明在使用,在声明之前都是死区,使用这个变量会报错
// 我们使用let代替var声明试试
console.log(a);
let a = 1;
// 这时候会报错提示【a is not defined】与var不同,let没有变量提升,这样就做到了先声明在使用的原则
看下面几个例子
1.
function run (a = b, b = 1) {
} // 会报错, b没有声明,但是已经使用了,函数形参相当于使用let进行了声明
run();
2.
let a = 1;
function run () {
console.log(a);
let a = 1;
}
// 会报错,如果函数内部有使用这个变量并且还发现了这个变量的声明语句,就不会沿着作用域向外查找变量这时候属于先使用后声明,所以会报错
run();
5. let,const,var共同点
看个例子
1.
// var a = 1;
// let a = 1;
const a = 1;
function show() {
console.log(a); // 1
}
show();
// 函数中可以访问外部全局的变量的,这是这三个的共同点
2.
var a = 1;
function show() {
var a = 2;
console.log(a); // 2
}
console.log(a); // 1
show();
其实不难理解,函数就相当于你的私有空间,外部(全局)不能访问,但你可以访问外部(全局,公共的)的变量
6. 可怕的全局污染
function show () {
a = 1; // 如果函数内部不使用var, let,const 等关键字声明会污染全局,也就是会变为全局变量
}
show();
console.log(a);
"use strict" // 使用严格模式,不使用关键字声明会报错
lan = 'lan';
console.log(lan); // 这时候会报错
使用var声明会自动添加到window()全局作用域中里去,window有个属性innerHeight
window.innerHeight // 782根据电脑不同显示不同
var innerHeight = 100;
window.innerHeight // 100
但是我们使用let/const就不会添加到全局作用域中
let zcy = 'handsome';
window.zcy
=> undefined
7. 块级作用域
我们首先看个例子
for(var i = 0; i < 5; i++) {
console.log(i);
}
// 打印出的i为0, 1, 2, 3, 4
在看下面这个例子,在全局声明一个变量
var i = 66;
for(var i = 0; i < 5; i++) {}
console.log(i); // 5 这时候的i会改变全局变量的i
var i = 66;
for(let i = 0; i < 5; i++) {} // 使用let声明不会改变全局的变量,只会改变块级作用域的变量
console.log(i); // 66 这时候的i就是全局变量的i,
块级作用域使用let,const声明会自动生成块级作用域
{
let a = 1;
}
cosole.log(a); // 这时候是访问不到的
但是使用var
{
var b = 1;
}
console.log(b); // 1是可以访问到的,var是没有块级作用域的
上面使用var声明相当于
var b = 1;
1、var 在循环中声明,没有块级作用域,属于全局变量,循坏外也可获取var声明的变量
2、let 声明属于块级作用域,循环外无法获取let定义的的变量,每一次执行循环都会重新声明一个块级作用域
场景:循环中,使用定时器打印变量,let声明和var声明,返回结果不一样,可以区分中两者的不同特性
1. // 有块级作用域每次循环执行都会重新开辟一个内存空间来执行,因为定时器中还用到了i,所以没有执行完立即销毁,还是会保留作用域中声明的变量
for(let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
},1000)
}
// 0 1 2 3 4
2.// 没有块级作用域,每次循环都是在同一个作用域(全局作用域)中重新改变i的值
for(var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
},1000)
}
// 5 5 5 5 5
3. // 利用闭包来执行类似let声明的,解释同一
for(var i = 0; i < 5; i++) {
(function(a) {
setTimeout(() => {
console.log(a);
},1000)
})(i)
}
// 0 1 2 3 4
8. const常量声明
const与let区别
1.const与let都是可以声明块级作用域的
2.使用let声明的变量是可以改变的
3.使用const声明的变量是不可以改变的(同一作用域下),不可以改变的变量就是常量,所以const主要是用来声明常量(一般大写,也可小写)
4.在同一作用域不能重复声明
// 使用const声明的常量在同一作用域不可以修改,let声明的变量是可以修改的
{
const NAME = 'lan';
NAME = 'ZCY'; // 这样是会报错的
}
{
let name = 1;
name = 2; // 这样是不会报错的
}
// 使用let/const不同作用域可以重复声明,同一作用域不能重复声明
1. // 不会报错
{
const NAME = 'lan';
}
{
const NAME = 'ZCY';
}
2. // 不会报错
const NAME = 'ZCY';
function show() {
const NAME = 'lan';
}
show();
3. // 会报错
{
const NAME = 'ZCY';
const NAME = 'lan';
}
# 以上两个都不会报错,因为在不同作用域
// 但是还需要注意
const声明引用类型,只要不改变内存和地址,都是可以改的。
因为const声明基本类型,会改变引用地址,所以会报错,但是修改引用类型,不改变地址,可以修改的
const CONFIG = {};
CONFIG.name = 'xm';// 我们只是在引用地址内进行修改了内容,并没有改变引用地址
const CONFIG = null; // 我们改变引用地址这样就不行了会报错
小节:
使用let声明的基本类型的时候 值可以改
使用const声明的基本类型的时候 值不可以改会报错
使用let声明的引用类型的时候 值可以改
使用const声明的引用类型的时候 不能改变 引用类型的地址的情况下是可以修改的
在同一作用域下 使用let声明的变量 可以重复使用let声明 但不能使用let声明的变量之后再用const重复声明同一变量 会报错
9. Object.freeze()冻结变量
const obj = {
name: 'zcy',
age: 18,
isHandsome: true
}
Object.freeze(obj); // 我们使用Object.freeze()冻结对象
obj.name = 'xm'; // 这时候在修改对象是修改不了的
console.log(obj);
# 注意但是用户不知道是否修改成功,如果给用户提示的话使用严格模式
"use strict"
const obj = {
name: 'zcy',
age: 18,
isHandsome: true
}
Object.freeze(obj); // 我们使用Object.freeze()冻结对象
obj.name = 'xm'; // 这时候在修改对象是修改不了的
console.log(obj);
其实是修改了对象属性的特征 configurable writable,后面我们讲对象的时候会详细讲
10. 基本类型与引用类型
let a = 1; // 在栈内存中开辟一块空间
let b = a; // 在内存中新开辟一块空间,复制a在内存中的值(占用内存空间小所以可以复制一份)
consoleg(a, b);
=> 1 1
// 当改变其中一个,另一个不会改变,所以说这俩变量使用是两个内存空间
a = 3;
consoleg(a, b);
=> 3 1
let obj1 = {}; // 在堆内存中开辟一块空间
let obj2 = obj1; // 占用内存空间大,所以不会在复制一份给你,而是引用同一内存地址
// 当改变其中一个,另一个也会跟着改变,所以说这俩变量使用是一个内存空间
obj1.name = 'zcy';
console.log(obj1, obj2);
=> { name: 'zcy' } { name: 'zcy' }
总结:基本类型传值,引用类型传址
JS中引用类型 object
JS中基本数据类型:undefined, null, boolean, number, string, symbol (这些说的是数据类型)
11. null与undefined详解
// 一般初始化引用类型的变量使用null,初始化基本数据类型使用undefined
typeof null;
=> 'object'
typeof undefined;
=> "undefined"
function show (name) {
console.log(name); // 调用函数不传值为undefined
}
show();
typeof是对值的类型检测
const a = 1;
let b;
typeof a; // 对a的值1进行类型检测
=> number
typeof b; // 对b的值进行类型检测,b没有值所以为undefined
=> undefined
typeof c; // 对一个没有声明的变量的值进行类型简称,连变量都没有更何况值了,值也没有,undefined
=> undefien
12. 严格模式
a = 1;
var a = 1;
console.log(a);
// 使用var声明他也能用,不使用var声明他也能用,好比现实世界闯红灯,你闯能过去马路,你不闯红灯也能过去马路
就不太严谨,我们让他严谨一点,代码里只能声明才能用,现实中不闯红灯才能过马路,那么代码里我们使用严格模式,现实里订立相关法规
1.
"use strict"
a = 1; // 在严格模式下不声明就使用这样会报错
console.log(a);
2.
"use strict"
var a = 1;
console.log(a);
3.
{
"use strict"
var a = 1;
console.log(a);
}
b = 2;
console.log(2); // 开启严格模式影响当前作用域及其子作用域
我对JavaScript如初恋,JavaScript虐我千百遍。

浙公网安备 33010602011771号