JavaScript反爬笔记(2)_JS基础_变量+数据类型+控制流+函数(详解闭包)+特殊对象(JSON/Date)

目录

一、变量

二、常用数据类型

三、控制流

四、函数

五、特殊对象


一、变量

1、变量格式

  • 以字母、下划线(_)或者美元符号($)开头;后续的字符也可以是数字(0-9)
  • 大小写敏感

2、注释格式

// 单行注释

/* 这是一个更长的,
   多行注释
*/

3、声明方式

var    //声明一个局部变量或全局变量,可选初始化一个值
// 如果不初始化会输出undefined

let    //声明一个块作用域的局部变量,可选初始化一个值
//let 声明的变量只在 let 命令所在的代码块 {} 内有效,在 {} 之外不能访问
let c = 3;
console.log('函数外let定义c:' + c);    //输出c=3
function change(){
let c = 6;
console.log('函数内let定义c:' + c);
} 
change();    //输出c=6
console.log('函数调用后let定义c不受函数内部定义影响:' + c);    //输出c=3

const    //声明一个块作用域的只读常量,且必须初始化
const b = 2;    //正确
// const b;    //错误,必须初始化
console.log('函数外const定义b:' + b);    //有输出值
// b = 5;
// console.log('函数外修改const定义b:' + b);    //无法输出

注:在函数外声明一个变量,如果在函数内再用var声明一次并改变其值,不会改变其函数外的值,如果直接赋值,则变量本身值被改变

/*在函数内用var声明*/
var varLocation = '我是函数外部的值';
function test(){
    var varLocation = '我是函数里边的值';
    alert(varLocation); 
}
test();    // '我是函数里边的值'
alert(varLocation);     // '我是函数外部的值'

/*直接赋值*/
var varLocation = '我是函数外部的值';
function test(){
    varLocation = '我是函数里边的值';
    alert(varLocation); 
}
test();    // '我是函数里边的值'
alert(varLocation);     // '我是函数里边的值'

参考链接:https://www.runoob.com/js/js-let-const.html

4、变量提升

JavaScript 会将当前作用域的所有变量的声明提升到作用域的顶部

JavaScript 只有声明的变量会提升,初始化的不会

在 ECMAScript 6 中,let(const)将不会提升变量到代码块的顶部

/* 例子1 */
console.log(x === undefined); // true
var x = 3;

/* 例子2 */
// will return a value of undefined
var myvar = "my value";
(function() {
  console.log(myvar); // undefined
  var myvar = "local value";
})();

参考链接:https://www.cnblogs.com/chenjg/p/9525208.html

5、函数提升

只有函数声明会被提升到顶部,而函数表达式不会被提升

/* 函数声明 */
foo(); // "bar"
function foo() {
  console.log("bar");
}


/* 函数表达式 */
baz(); // 类型错误:baz 不是一个函数
var baz = function() {
  console.log("bar2");
};

二、常用数据类型

1、对象(Object):是一种无序的集合数据类型,它由若干键值对组成

参考链接:https://www.w3school.com.cn/js/js_objects.asp

2、映射(Map)

var m = new Map();     // 空Map
m.set('Adam', 67);     // 添加新的key-value
m.has('Adam');     // 是否存在key 'Adam': true
m.get('Adam');     // 67。如果不存在则返回 undefined
m.delete('Adam');     // 删除key 'Adam'
m.clear();    	// 移除Map对象的所有键/值对
m.keys();	// 返回一个新的 Iterator对象, 它按插入顺序包含了Map对象中每个元素的键
m.values();    // 返回一个新的Iterator对象,它按插入顺序包含了Map对象中每个元素的值
m.entries();    // 返回一个新的 Iterator 对象,它按插入顺序包含了Map对象中每个元素的 [key, value]**数组**

对象(Object) 和 映射(Map) 的差异

Object的键只能是字符串或者 Symbols,在Map里键可以是任意类型,包括函数、对象、基本类型

Map 可直接进行迭代,而 Object 的迭代需要先获取它的键数组,然后再进行迭代

参考链接:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map

3、数组(Array):用于在单一变量中存储多个值,值是可以重复的

参考链接1:https://segmentfault.com/a/1190000016503330

参考链接2:https://www.liaoxuefeng.com/wiki/1022910821149312/1023020967732032

4、集合(set):是一组不重复的值的集合

var m = new Set();     // 空Set

方法与Map相比
add(key)    // 在Set对象尾部添加一个元素,Map对应的方法是set(key, value)
// 缺少entries()
// keys()和values()方法相同

数组(Array) 和 集合(set) 的差异

Array对象可以存储重复的值,Set对象存储不重复的值

Set对象允许根据值删除元素,而数组中必须使用基于下标的 splice 方法

参考链接:重学JavaScript - 映射与集合 https://www.cnblogs.com/suRimn/p/10861689.html

5、布尔值(Boolean):true 和 false

6、null:表示空值。因为JavaScript 是大小写敏感的,因此 null 与 Null、NULL或变体完全不同

7、undefined :表示变量未定义时的属性

8、数字(Number):整数或浮点数。例如: 42 或者 3.14159

9、字符串(String):一串文本值的字符序列。例如:"Howdy"

参考链接:标准内置对象 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects

注1:深拷贝/浅拷贝

(1)定义

浅拷贝(shallow copy)只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存;

深拷贝(deep copy)会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象

(2)浅拷贝的实现

使用 Object.assign 方法

slice() 和 concat() 
针对多维数组

直接用=赋值

for···in只循环第一层

参考链接:实现浅拷贝 https://www.jianshu.com/p/1c142ec2ca45

(3)深拷贝的实现

巧用slice() 和 concat()
只能实现一维数组的深拷贝(多维数组无效)

for循环遍历

JSON.stringify()/JSON.parse()
相当于是把原数组转成字符串类型,之后再解析。缺陷在于:无法复制函数;丢失原型链(对象就丢失所属的类)

递归方法

jQuery方式
$.extend([deep], target, object1 [, objectN ]) 该方法可以运用于数组,也可以运用于对象

参考链接:实现深拷贝 https://www.jianshu.com/p/c30ee068f7dd

注2:==/===

=== 严格相等/一致运算符不会进行类型转换,仅当操作数严格相等时返回true

== 相等操作符会将两个不同类型的操作数转换相同类型,然后进行严格比较

 

三、控制流

1、For循环:循环可以将代码块执行指定的次数

1.1 语法:

for (语句 1; 语句 2; 语句 3)
{
    被执行的代码块
}

语句 1 (代码块)开始前执行
语句 2 定义运行循环(代码块)的条件
语句 3 在循环(代码块)已被执行之后执行

1.2 实例

for (var i=0; i<5; i++)
{
      x=x + "该数字为 " + i + "<br>";
}

//运行结果
/*
该数字为 0
该数字为 1
该数字为 2
该数字为 3
该数字为 4
*/

1.3 For/In 循环:遍历对象的属性

var person={fname:"John",lname:"Doe",age:25}; 
 
for (x in person)  // x 为属性名
{
    txt=txt + person[x];
}

2、While循环:只要指定条件为 true,循环就可以一直执行代码块

2.1 语法

while (条件)
{
    需要执行的代码
}

2.2 实例

//只要变量 i 小于 5,循环将继续运行
while (i<5)
{
    x=x + "The number is " + i + "<br>";
    i++;
}

//返回
/*
该数字为 0
该数字为 1
该数字为 2
该数字为 3
该数字为 4
*/

2.3 do/while 循环:该循环会在检查条件是否为真之前执行一次代码块,然后如果条件为真的话,就会重复这个循环。

do
{
    需要执行的代码
}
while (条件);

3、条件判断

  • if 语句 - 只有当指定条件为 true 时,使用该语句来执行代码

if (condition)
{
    当条件为 true 时执行的代码
}

  • if...else 语句 - 当条件为 true 时执行代码,当条件为 false 时执行其他代码

if (condition)
{
    当条件为 true 时执行的代码
}
else
{
    当条件不为 true 时执行的代码
}

  • if...else if....else 语句- 使用该语句来选择多个代码块之一来执行

if (condition1)
{
    当条件 1 为 true 时执行的代码
}
else if (condition2)
{
    当条件 2 为 true 时执行的代码
}
else
{
  当条件 1 和 条件 2 都不为 true 时执行的代码
}

  • switch 语句 - 使用该语句来选择多个代码块之一来执行
    首先设置表达式 n(通常是一个变量)。随后表达式的值会与结构中的每个 case 的值做比较。如果存在匹配,则与该 case 关联的代码块会被执行。请使用 break 来阻止代码自动地向下一个 case 运行

switch(n)

{ case 1: 执行代码块 1

break;

case 2: 执行代码块 2

break;

default: 与 case 1 和 case 2 不同时执行的代码 }

四、函数

1、正常语法

function functionName(parameters) {
  执行的代码
}

由于函数声明不是一个可执行语句,所以不以分号结束

2、匿名函数(没有名称的函数)

var x = function (a, b) {return a * b};

述函数以分号结尾,因为它是一个执行语句。

3、函数能够在声明之前被调用

4、自调用函数:注意括号

(function () {
    var x = "Hello!!";      //我会调用我自己
})();

5、高阶函数

一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数

function add(x, y, f) {
    return f(x) + f(y);
}

6、箭头函数

var f = () => 5;
// 等同于
var f = function () { return 5 };
 
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};

https://www.jianshu.com/p/772d2509fed1

7、闭包

(1)JavaScript 允许函数嵌套,并且内部函数可以访问定义在外部函数中的所有变量和函数,以及外部函数能访问的所有变量和函数。但是,外部函数却不能够访问定义在内部函数中的变量和函数。这给内部函数的变量提供了一定的安全性。当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了。

var pet = function(name) {          //外部函数定义了一个变量"name"
  var getName = function() {            
    //内部函数可以访问 外部函数定义的"name"
    return name; 
  }
  //返回这个内部函数,从而将其暴露在外部函数作用域
  return getName;               
};
myPet = pet("Vivie");
    
myPet();                            // 返回结果 "Vivie"

(2)定义:闭包简单理解就是能够读取其他函数内部参数和变量的函数(所谓函数嵌套函数)

(3)特点:

a 让外部访问函数内部变量成为可能(内部函数可以引用外部函数的局域变量,同时内部函数可以被返回)

b 外部函数的局部变量不会被垃圾回收机制回收,也就是说外部函数的局部变量会常驻在内存中 
一般函数执行完毕后,局部活动对象就被销毁,内存中仅仅保存全局作用域,但是由于闭包是建立在一个函数内部的子函数,由于其可访问上级作用域的原因,即使上级函数执行完,作用域也不会随之销毁

// 例子1
function outFn(){
  var i=0;
  function inFn(){
      i++;
      console.log(i);
  }
  return inFn;    // inFn 就是一个闭包函数,因为它能够访问到outFn函数的作用域
}
var fnFn=outFn();
fnFn();    // 1
fnFn();    // 2
fnFn();    // 3

// 执行完fnFn=outFn()后,变量fnFn实际上是指向了函数outFn,再执行inFn()后就会打印i的值
// 这段代码其实就创建了一个闭包,这是因为函数outFn外的变量fnFn引用了函数outFn内的函数inFn()

// 外部的函数连续调用了内部函数三次,当fnFn第一次执行完后,i的值变为了1,同时并没有被销毁
// 第二次是在第一次执行结果的基础之上的进行相关运算

// =======================================================================
// 例子2
// 例子1中定义了变量var fnFn=outFn();例子2中outFn()()直接调用了内部函数inFn,但并不存在外部变量,所以不是闭包
function outFn(){
  var i=0;
  function inFn(){
      i++;
      console.log(i);
  }
  return inFn;
}
outFn()();    // 1
outFn()();    // 1
outFn()();    // 1
// 当outFn()()第一次执行完后,整个outFn()被销毁,第二次outFn()相当于重新开辟了一块新的空间
// 所以第二次outFn()()和第一次打印的结果无关

// =======================================================================
// 例子3
function outerFn(){
  var i = 0; 
  function innerFn(){
      i++;
      console.log(i);
  }
  return innerFn;
}
var fnFn1 = outerFn();
var fnFn2 = outerFn();
console.log(fnFn1==fnFn2)    //False
// fnFn1和fnFn2是对象outerFn的两个不同的实例,创建在不同的内存地址上,所以不相等
// 而闭包找到的是同一地址中父级函数中对应变量最终的值,所以有如下结果
fnFn1();    //1
fnFn1();    //2
fnFn1();    //3
fnFn2();    //1
fnFn1();    //4
fnFn2();    //2
fnFn2();    //3


// ---------------------------
var fnFn3 = outerFn;
var fnFn4 = outerFn;
console.log(fnFn3==fnFn4)    // True
/*在JS中,对象和函数是引用类型,
也就是说,它们在赋值给其它变量时,只是把它自己的引用地址赋值给其它变量,而不是新建一个对象或函数。
fnFn3和fnFn4都只是被赋值了函数outerFn的引用地址,所以,他们的值是相等的*/ 

// =======================================================================
// 例子4
// 例子3中var i放在outerFn()内部,例子4中var i放在outerFn()外部
// 例子4中i是全局变量,在一个固定的内存地址上,且一直没有被释放,所以i一直在累加
var i = 0; 
function outerFn(){
  function innerFn(){
      i++;
      console.log(i);
  }
  return innerFn;
}
var fnFn1 = outerFn();
var fnFn2 = outerFn();
fnFn1();    //1
fnFn1();    //2
fnFn1();    //3
fnFn2();    //4
fnFn2();    //5
fnFn2();    //6

(4)作用:设计私有的方法和变量

var Counter = (function() {
  //私有属性
  var privateCounter = 0; 
  //私有方法
  function changeBy(val) { 
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }   
})();
console.log(privateCounter); //privateCounter is not defined 
console.log(Counter.value()); // 0
Counter.increment();
Counter.increment();
console.log(Counter.value()); // 2
Counter.decrement();
console.log(Counter.value()); // 1

参考链接1:《闭包,看这一篇就够了》https://blog.csdn.net/weixin_43586120/article/details/89456183

参考链接2:《闭包和垃圾回收机制》https://www.cnblogs.com/edwardwzw/p/11754101.html

参考链接3:《什么是闭包?》https://www.cnblogs.com/huanghuali/p/9851453.html

参考链接4:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Functions

五、特殊对象

1、JSON

JSON.parse()    用于将一个 JSON 字符串转换为 JavaScript 对象。
JSON.stringify()    用于将 JavaScript 值转换为 JSON 字符串。

2、Date

var now = new Date();
now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
now.getFullYear(); // 2015, 年份
now.getMonth(); // 5, 月份,注意月份范围是0~11,5表示六月
now.getDate(); // 24, 表示24号
now.getDay(); // 3, 表示星期三
now.getHours(); // 19, 24小时制
now.getMinutes(); // 49, 分钟
now.getSeconds(); // 22, 秒
now.getMilliseconds(); // 875, 毫秒数
now.getTime(); // 1435146562875, 以number形式表示的时间戳

参考链接1:https://www.runoob.com/jsref/jsref-obj-date.html

参考链接2:https://www.runoob.com/js/js-obj-date.html

 

整体参考链接:《JavaScript 指南》https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide

end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值