一、基础扫盲
1、JavaScript特点
a)解释型
没有编译的概念,代码是由浏览器里的解释器解释运行的。
代码执行到报错停止,但是前面执行的代码,效果依然会体现。
浏览器不同或解释器不同,代码执行效果可能会不一样。(系统引擎和V8引擎)
b)弱类型
类型检查弱,并且当解释器期望在什么位置需要什么类型时,会根据一定的规则完成自动转换。比如,在if语句中期望提供布尔型,如果你提供的不是布尔型,则自动转换而不给任何提示。
c) Unicode字符集
变量名支持中文
\u0053\u0074\u0072\u0069\u006e\u0067.\u0066\u0072\u006f\u006d\u0043\u0068\u0061\u0072\u0043\u006f\u0064\u0065就代表String.fromCharCode
d)代码从上往下执行,哪个写在前面就哪个先执行。不像别的语言有一个入口。
e)JS的标准 ECMAscript ES5
3、编程语言共性
- 注释
- 关键字
- 标识符
- 常量
- 变量
- 运算符
- 语句
- 函数
- 数组
区分大小写
忽略换行和多余空格(分号;代表语句结束)
写代码的时候注意全角和半角,一般符号都只认识半角
4、注释
// 单行注释
/* ...*/多行注释
5、关键字
6、保留字
在当前标准下,还没有特殊含义,但是可能后续标准会用到,也轮不到我们用。
7、标识符
说白了就是一些变量名,函数名等。使用之前必须自己预先定义
字母、数字、下划线、美元符号(数字不允许为首)中文
驼峰命名法
8、直接量(常量)
直接出现在代码中,执行过程中不变的量。
二、数据类型
- 原始类型 字符串、数值、布尔值
null、undefined
- 对象类型 对象、数组、函数等
- null和undefined
一般情况下,null代表空,undefined代表未定义。
- 数值
JavaScript不区分整数和小数
var a = 0;
var a = 1.3;
- 字符串
单引号和双引号意义完全一样
var a = “小肩膀”;
var a = ‘小肩膀’;
字符串中有引号的时候
var a = “小’肩膀”;
var a = ‘小”肩膀’;
d)布尔值 true false
JS在适当的时候会自动完成类型转换。也就是如果当它需要布尔型的时候,对它来讲,就只有两种值,真值和假值
false undefuned null 0 -0 NaN "" //空字符串
以上7种为假值,其余均为真值
三、变量
1、变量的概念
变量其实就是内存中的一块存储区域,声明定义了一个变量就是在内存开辟了一块空间,用来存储数据。
变量名实际就对应这块空间的地址。
2、变量声明的基本格式
var a; //定义一个变量
var a,b; //定义两个变量,中间用逗号运算符分隔
var a = 0; //定义的同时初始化 这个等价于 var a; a = 0;
var a = 0, b = 1;
变量用var关键字重复声明不会报错,但是会覆盖前面的同名变量。不单单要注意变量与变量的重名,还要注意变量与函数,函数与函数的重名。
没有以var关键字定义的变量,在任何位置都是全局变量,不建议故意不写var去定义一个全局变量。
3、变量声明提前
alert(a);
var a; //弹出undefined
alert(a);
var a = 5; //弹出undefined 只是声明提前 赋值不提前
4.变量作用域
不包含在任何函数内部的代码叫顶层代码,定义在顶层代码中的变量就是全局变量。定义在函数中的变量,就是局部变量。
function test(){
var a = 5;
}
test();
alert(a); //报错 a是test函数里面的局部变量 外面不能直接访问
function abc(){
var b = 6;
function test(){
alert(b);
}
test();
};
abc();
alert(b); //先弹出6 然后报错
四、运算符
1、算数运算符
a)+ -
当+-作为一元运算符时,代表强制转换到数字,如果无法转换,返回NaN。比如:+[] +{} +new Date()
当加号作为二元运算符时,加号也可以表示字符串连接,只要加号有一边是字符串,则优先字符串连接。
b)* / %
c)++ --
++ 递增 比如:i++ 就等同于i = i + 1的简写
2、位运算符
& 位与
| 位或
^ 位异或
~ 位非(位取反)
<< 左移
>> 右移
>>> 无符号右移
3、赋值运算符
= //在任何位置都代表赋值
+= //i += 2; 等价于i = i + 2;
-= *= /= %=
4、关系运算符
a)== !=
俩等号在任何位置都代表比较,两边会自动类型转换
b)=== !==
仨等号在任何位置都代表比较,两边不会自动类型转换
5、比较运算符
< > <= >=
6、逻辑运算符
&& 与 || 或 ! 非(取反)
a) &&的特点
短路:从左往右,碰到假就不执行后面的表达式(相当于if的简写)
var a = 0;
(a == 1) && (a = 3);
alert(a);
应用于赋值
var b = 1;
var a = “张三”+ b && c;
b) ||的特点
短路:从左往右,碰到真就不执行后面的表达式
var a = 0;
a || (a = 100);
alert(a);
应用于赋值
var a = 100;
a = a || 0;
alert(a);
7、逗号运算符
同时定义两个或两个以上变量。
多个表达式语句连接成一条语句。
8、三元运算符(相当于if...else的简写)
表达式1 ? 表达式2 : 表达式3
var b = 1,c = 1;
var a = b == c? 3 : 6;
console.log(a);
9、typeof 运算符
用来判断数据类型
10、instanceof
一般用来判断对象属于哪个类
五、语句
JS中以分号代表一个语句的结束,如果多个表达式语句之间用的逗号运算符分隔,算一条语句。
1、代码执行的三种结构
顺序结构
分支结构
循环结构
2、分支结构
- if
- switch
跟别的语言有所不同,表达式的结果类型可以是string、number、boolean、对象、array。与if最大的区别就是switch没法做区域判断
3. 跳转语句break continue
break可以用在switch和循环中
continue只能用在循环中
2、循环结构
- while
- do...while
- for 一般用于数组遍历
for(初始化表达式;循环条件表达式;循环后的操作表达式)
{
执行语句;
}
可以放任意表达式,多个表达式之间用逗号分隔
- for...in 一般用于对象和数组遍历
4、省略括号的情况
实际上if、whlie、do...while、for、for...in语句后面都只能跟一条一句。如果需要多个语句。你要么用花括号括起来,代表这些是复合语句。或者用逗号运算符连接成一条语句。
5、块级作用域
在JS中用var定义的变量没有块级作用域。在流程控制语句中定义的变量,作用域范围也是整个函数。【只看函数的{}】
用let定义的变量有块级作用域【for{ }】
6、throw语句
if(x < 0) throw new Error(“x不能为负数”);
7、异常处理语句 try/catch/finally
try{
//...
}catch(e){
//try语句中报错 这里的代码才会执行
//...
}finally{
//不管try语句是否异常 这里代码都会执行
//...
}
8、“use strict”指令 //严格模式
六、数组
1、数组的概念
数组也是一个容器,它是一堆数据的集合,是连续的一块内存地址空间。
2、数组的声明
var arr = []; //定义空数组
var arr = new Array(); //定义空数组
var arr = new Array(5); //定义一个5个成员的数组
3、length属性用于获取数组长度
4、数组下标从0开始
5、JS的数组没有越界的概念,会返回undefined
6、JS的数组非常灵活,数组成员可以是任意类型的组合
var a = 50;
var arr = [
“abc”,
59,
[100,200],
{x:300,y:400},
function(){return 500;},
function(){return 600;}(),
10 + a
];
7、数组成员(元素)的读写(访问和赋值)
8、作为数组的字符串 字符串切片
var str = "javascript";
console.log(str[5]); //charAt
9、数组遍历(for和for...in,和for...of)
for...in和for...of(ES6):前者接受数组下标,后者接受数值的值
arr.map(function(value,index){
})
(ES5)
arr.map(function(value,index){
//可以在函数内部this调用obj
},obj)
foreach和map用法类似
var arr = [
[1,2,3],
[4,5],
[7]
],c = 0;
for(var i=0;i<arr.length;i++){
for(var k=0;k<arr[i].length;k++){
c += arr[i][k];
}
}
console.log(c);
七、对象
1、对象的分类
a) 内置对象
包括数组、日期、正则表达式等,这些有对应的内部类。提供了很多方法供我们使用。
b) 宿主对象
主要指DOM对象,由浏览器实现。不同的浏览器,可能不一样。
无需创建,可以直接使用。
c) 自定义对象
2、对象的属性(方法)
a) 自有属性
b) 继承属性
3、对象的创建
var obj={}; //隐式创建
var obj=new Object();
4、对象的结构
{属性名1:属性值,属性名2:属性值}
5、对象属性的定义和访问
a) var obj = { x : 1, y : 2 }; //初始化的时候就定义属性
b) obj.x //这里必须写死在代码中
c) obj[“x”] //这里是一个字符串 可以拼接 动态生成
d) 对象的属性可以随时创建,并且前面不能加var关键字
6、对象方法的定义和调用
obj.test = function(a,b){
alert(100);
};
obj.test(1,2);
7、序列化对象(JSON)
JSON.stringify() //对象转字符串
JSON.parse() //字符串解析成对象
9、对象属性遍历(for...in)
for(var name in obj){
obj[name];
}
10、window对象和navigator对象
a) 全局对象概念
当JS以浏览器为运行环境的时候,window是它的全局对象,可以用this引用。
当JS以调试器为运行环境的时候,也有全局对象,但不叫window,也可以用this引用。
b) 全局对象的特点
顶层代码中定义的所有变量,都是全局对象的属性
顶层代码中定义的所有函数,都是全局对象的方法
全局对象调用它的属性和方法时,可以省略对象名称
var a = 5;
alert(window.a);
function test(){
alert(666);
}
window.test();
c) navigator 对象
navigator 是window下的一个属性,也是一个对象,该对象包含有关浏览器的信息。
JSON数据解析
1、JSON.解析() JSON.成员数() JSON.取通用属性() JSON.清除()
2、JSON数组最外层一定是花括号,表示是对象。
3、数组表现形式
最外层用中括号表示,多个数组成员之间用逗号隔开。数组下标从0开始。数组成员访问方式,数组名[数组下标]
4、对象表现形式
最外层用花括号表示,多个属性之间用逗号隔开,每个属性都是 属性名:属性值 的名值对。属性访问方式,对象名.属性名 或者 对象名[“属性名”]
JSON解析数组
JSON解析对象
JSON访问特殊属性名
八、函数
1、函数的概念
函数是JS的一个基本组成单位,每个函数用来完成一定的功能,函数里可以调用别的函数来完成功能。函数是JS里最小的封装。
2、函数声明、定义/实现、调用的概念
a) 函数的结构
function 函数名(参数列表){
//语句
//return 语句
}
b) 函数的声明
//第一种
function test(){
var a = 5;
alert(a);
}
test();
//第二种
var test = function(){
var a = 5;
alert(a);
}
3、函数声明的提前
第一张方式声明会自动提前
test();
function test(){
alert(5);
}
第二种方式定义的函数 声明无法提前,会报错
4、JS函数中可以再定义函数(私有函数)
5、函数的形参和实参
function test(a,b){
return a+b;
}
test(5,6);
6、return语句
a) return只能用在函数体中
b) return后面跟多个表达式,用逗号分隔,只返回最后一个表达式计算的结果
function test(){
var a,b,c;
return a = 100,b = 200,c = a + b;
}
test();
c) 在return和后面的表达式之间不能有换行,JS会自动补全分号
return
true; 会解析成return;true;
7、匿名函数【没有名字】
function(){
//.....
}
作用:1、赋值给变量、赋值给对象的属性
2、作为参数传入函数,类似回调函数
3、作为命名空间,定义完后直接调用(防止和其他参数冲突!)
8、匿名函数的调用
(function(){
//....
})();
(function(){
//....
}());
!function(){
//....
}();
9、匿名函数的传参
!function(a,b){
alert(a + b);
}(5,6);
10、作为命名空间的函数
(function(){
//...
})()
11、函数的作用域
(function(){
function test(){
var a = 5;
alert(a);
}
})();
test(); //报错 test是私有函数 外面不能直接访问
12、如何在外部间接调用私有属性和函数?(!!!!!)
第一种:
var obj = function(){
var b = 6;
function test(){
var a = 5;
alert(a);
}
return {
b : b,
test : test
}
}();
//这里有括号是把函数的返回值赋给obj 不加括号是把函数赋给obj;
obj.test();
alert(obj.b); //弹出5 再弹出6
第二种:
var obj = {};//自己创建个属性,再把匿名函数的fun挂到里面
!function(o){
var b = 6;
function test(){
var a = 5;
alert(a);
}
o.b = b;
o.test = test;
}(obj);
obj.test();
alert(obj.b); //弹出5 再弹出6
//把obj去掉会报错 test() 跟obj.test() 不是同一个东西
第三种:
!function(w){
function i(){
var a = 5;
alert(a);
}
w.Hex = i;
}(window);
Hex();
//弹出5 正常调用应该是window.Hex window对象在浏览器里可以省略
//在浏览器里Hex() 和 window.Hex() 是同一个东西
JS调试器里没有window这个对象 所以会报未定义
即使定义为空对象,它也没有可以省略的功能,所以一般定义成this,把调试器的全局对象的引用,赋值给window。这样window调用属性和方法的时候就可以省略了。
13、那么怎么在调试器里改装呢?
第一种方法 补全
var window = {};
function test(){
return Hex.x; //return window.Hex.x;
}
!function(w){
//...
w.Hex = {x:2};
}(window);
对上面的代码来个稍微的变形
var window = {};
function test(){
return Hex.x; //return window.Hex.x;
}
!function(){
//...
window.Hex = {x:2};
}();
第二种方法 去掉对象改装成全局变量
var window = {};
var Hex = {}; //定义成一个全局变量
function test(){
return Hex.x;
}
!function(w){
Hex = {x:2}; //这里window去掉
}(window);
14、函数的重载
JS中没有函数的重载 无法根据函数参数的不同 来分辨不同的函数
一定要注意函数与函数,函数与变量,变量与变量不要重名
function test(a){
return a;
}
function test(a,b){
return a + b;
}
alert(test(5));
//NaN (not a Number)
15、作为值的函数
把函数当做参数传
function test(a,b){
return a+b;
}
function abc(a,b,f){
return f(a,b);
}
abc(5,6,test);
16、JS支持可变参数arguments
17、this关键字
在顶层代码引用this就代表window
函数里的this 谁调用它 就指代谁
18、函数的方法 call apply
九、闭包
1、作用
让函数内的局部变量,可以达到保留的效果
2、形成条件
函数返回的是一个函数
3、通常写法
十、类
1、构造函数、原型对象和实例化的概念
//构造函数 constructor
function People(){
this.name = "小肩膀";
this.age = 28;
}
//方法只定义了一次 可以减少内存的使用
//People.prototype 构造函数的原生对象
People.prototype.eat = function(){
return "饭";
}
//实例化对象
var people1 = new People(); //new后面的构造函数名 要和定义的时候对应
var people2 = new People();
console.log(people1.eat == people2.eat);
2、原型链
- 当我们定义一个对象 var obj = {}; 等价于var obj = new Object();
所以它的原型是Object.prototype
b) 当我定义一个数组 var arr = []; 等价于var arr = new Array();
所以它的原型是Array.prototype
Array.prototype的原型是Object.prototype
c) 当我们实例化一个对象var people = new People();
它的原型是People.prototype
People.prototype的原型是Object.prototype
d) 每一级都会继承
十一、JS的内部类
1、JS事先定义好的一些类,方便使用。内部类的父类是Object
2、分为动态类和静态类
动态类使用的时候,先创建一个对象实例,然后使用其属性和方法
静态类通过类名,调用属性和方法 Math.random()
Math类
Math是静态类,提供了常用的数学函数和常数,我这给大家介绍几个最常用的函数,其它的请大家参考javascript帮助文档。
abs(x) 返回数的绝对值
ceil(x) 对一个数进行上舍入
floor(x) 对一个数进行下舍入
max(x,y) 求x,y中较大的数
min(x,y) 求x,y中较小的数
round(x) 对 x进行四舍五入
random() 一个大于0小于1的16位小数位的数字(含0但是不含1)
Date类
Date() 返回当前日期和时间
getDate() 从Date对象返回一个月中的某一天
getDay() 从Date对象返回一周中的某一天
getMonth() 从Date对象返回月份
getYear() 从Date对象返回年
getHours() 从Date对象返回小时数
getMinutes() 从Date对象返回分钟
getSeconds() 从Date对象返回秒数
toLocaleString()
取现行时间戳
Date.now();
new Date().getTime();
new window.Date().getTime();
String类
indexOf() 返回某个字符串值在该字符串中首次出现的位置
substr() 提取取从start下标开始的指定数目的字符
substring() 提取字符串中介于两个指定下标之间的子串
charAt() 返回指定位置的字符
length 属性,可以得到字符串的长度
toString() 将对象中的数据转成某个格式的字符串
split() 把字符串分割为字符串数组
match()/replace()/search()
toUpperCase()字符串到大写
toLowerCase()字符串到小写
Array类
Array提供了对数组的操作,使用Array对象可以轻松的创建数组,
并对数组进行删除、排序和合并等操作。
concat() 连接两个或更多的数组,并返回结果。
sort() 对数组的元素进行排序
toString() 把数组转换为字符串,并返回结果
pop() 删除并返回数组的最后一个元素
push() 向数组的末尾添加一个或更多元素,并返回新的长度
splice() 方法用于插入、删除或替换数组的元素
length 属性,获取长度
全局函数
parseInt
parseFloat
- 事件
click 鼠标点击
submit 表单提交
事件
按钮点击的四种写法
在HTML中直接绑定
在JS中,获取DOM对象,添加onclick属性
添加事件监听,addEventListener() 或 attachEvent()
jQuery方法on绑定
十二、jQuery
//jquery获取元素的值
$("#user").val();
$("#user").val(a);
$(".user").val(a);
$("input[type='password']").val();
//jquery遍历数组
var b = ["张三","李四","王五"];
$.each(b,function(i,v){
alert(i + " " + v);
})
var arr = [1,2,3,4,5,6,7,8,9,10],c = 0;
$(arr).each(function(i,v){
c = c + v;
});
alert(c);
//原生js遍历数组
for(var i = 0; i < b.length; i++){
alert(i + " " + b[i]);
}
$().click(function(){})
$().on(‘click’,function(){})
十三、ajax
$.get("login.php");
var data = "u=15968079470&p=2222222222";
data = {
u : "15968079470",
p : "2222222222",
};
$.post("login.php",data,function(response){
//....
})
$.ajax({
url : "",
type : "",
data : {
}
success : function(response){
//....
}
})
十四、模块化编程
define()
- 用来定义一个模块
- 这是一个函数
- 一般接收三个参数
a) 是一个字符串,指定文件存在路径,或者说是模块名
b) 是一个数组,指定依赖,本模块正常执行,必须要用到的一些文件
c) 是一个函数,该函数的参数,分别对应第二个参数的数组成员调用后 的接口。函数体内部是本模块的具体代码。一般该函数会有一个返回值, 返回本模块调用的接口
4、我们的处理方式是掐头去尾留中间。如果一个实战中涉及多个模块,则 用闭包封装,闭包最后返回的为该模块的接口。
5、这个函数原生JS不具备。也就是说是利用原生JS封装出来的一个函数。 所以这个函数,网站也有可能会自己去实现,而不是调用别人的写好的 JS库。也就是你可能会看到名字不是define,但是写法很像的代码。我 们的处理方式类似
十五、JS混淆
1、eval加密
如果代码是服务器返回的,通常我们不能直接文本取中间,我们要用JSON解析。
因为代码是以文本的方式发送的,所以有可能字符会冲突,服务器发送过来会用转义字 符转义 “\” 。用JSON解析就去自动处理掉这些东西。
2、把变量名、函数名、参数名等,替换成没有语义,看着又很像的名字。
_0x21dd83、_0x21dd84、_0x21dd85
3、用十六进制文本去表示一个字符串 \x56\x49\x12\x23
4、利用JS能识别的编码来做混淆
\u6210\u529f表示中文字符(成功)。JS是Unicode编码,本身就能识别这种编码。类似的一些变量名,函数名都可以用这个表示,并且调用。
\u0053\u0074\u0072\u0069\u006e\u0067.\u0066\u0072\u006f\u006d\u0043\u0068\u0061\u0072\u0043\u006f\u0064\u0065就代表String.fromCharCode
('')['\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72']['\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65'];效果等同于String.fromCharCode
5、把一大堆方法名、字符串等存到数组中,这个数组可以是上千个成员。然后调用的时候,取数组成员去用(arr[1001])。
var arr = ["Date","getTime"];
var time = new window[arr[0]]()[arr[1]]();
console.log(time);
6、charCodeAt、String.fromCharCode结合eval就是一种混淆手段
这个名字好认,所以也有的网站会自己写一个类似的函数,用这个函数转换,并把函数名改掉。
var a = "你好";a.charCodeAt(0); //把字符转换成ASCII码
String.fromCharCode(20320,97,49,65); //把ASCII码转换成字符
有时候服务器会直接发送一段ASCII过来(65,56,48,97),然后用
String.fromCharCode转换后,再用eval执行
- 字符串加密后发送到前端,然后前端调用对应的函数去解密,得到明文
对于这种,
首先把函数括号中的所有参数匹配出来,包括里面的逗号
然后调用JS解密得到明文字符串
最后用明文字符串加上引号,替换函数名(参数列表)