目录
一、变量
二、常用数据类型
三、控制流
四、函数
五、特殊对象
1、变量格式
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 + "
";
}
//运行结果
/*
该数字为 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 + "
";
i++;
}
//返回
/*
该数字为 0
该数字为 1
该数字为 2
该数字为 3
该数字为 4
*/
2.3 do/while 循环:该循环会在检查条件是否为真之前执行一次代码块,然后如果条件为真的话,就会重复这个循环。
do
{
需要执行的代码
}
while (条件);
3、条件判断
if (condition)
{
当条件为 true 时执行的代码
}
if (condition)
{
当条件为 true 时执行的代码
}
else
{
当条件不为 true 时执行的代码
}
if (condition1)
{
当条件 1 为 true 时执行的代码
}
else if (condition2)
{
当条件 2 为 true 时执行的代码
}
else
{
当条件 1 和 条件 2 都不为 true 时执行的代码
}
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