zhangdong@tedu.cn
JS 基础语法
1、使用JS
1、浏览器内核
内核主要负责页面的渲染
内核主要由两部分组成
1、内容排版引擎
解析HTML/CSS
2、脚本解释引擎
解释JS
浏览器 内核 排版引擎 解释引擎
IE Trident - Chakra
Firefox Gecko - Monkey系列
Safari Webkit Webcore Nitro
Chrome Webkit Webcore V8
Opera Presto - Carakan
Opera Webkit Webcore V8
(2013~)
2、搭建JS运行环境
1、独立安装的JS解释器
要求:安装NodeJS
开始-> 搜索输入 cmd
操作:向控制台中输出一句话
console.log("你好世界!");
console.log('Hello World');
2、嵌入在浏览器内核中的JS解释器
1、直接在浏览器Console中输入脚本并执行
2、将JS脚本嵌入在HTML页面中执行
1、通过 html 元素事件
onclick 事件 :在鼠标单击时要执行的操作
<button οnclick="JS脚本"></button>
<div οnclick="JS脚本"></div>
...
<ANY 事件名称="JS脚本"></ANY>
2、在<script>标记中 编写JS脚本
<script>
document.write("<h1>Hello</h1>");
</script>
3、使用外部脚本文件,编写JS脚本
1、创建脚本文件
***.js
编写JS脚本
2、在使用的页面中引入JS文件
<script src="文件URL"></script>
3、JS调试
代码出现问题,结束本块运行,但不会影响后续块
2、语法规范
1、语句-会被JS解释器所执行的代码
由表达式、关键字、运算符组成
严格区分大小写(重要)
每条语句都由 ; 表示结束
中英文符号:
1、, 和 ,
2、. 和 。
3、; 和 ;
4、: 和 :
5、" 和 “
6、() 和 ()
2、注释
单行注释:只能注释一行内容
语法://
多行数值:一次性注释多行内容
语法:/* */
3、变量 和 常量
1、变量
1、什么是变量
内存:保存程序运行过程中所需要用到的"数据"
空间:
位 :bit 8bit = 1byte
字节:byte 1024byte = 1kb
千字节:kb 1024kb = 1mb
兆字节:mb 1024mb = 1gb
G : gb 1024gb = 1tb
T : tb
变量:表示的就是内存中的一段存储空间
生活中:
1、宾馆的房间
2、超市储藏箱
变量值:保存在变量中的数据
变量名:标识数据在内存中的名字
2、变量的声明
到内存中 声明一段空间,并且起个别名再保存数据
语法:
1、声明变量
var 变量名;
2、为变量赋值
变量名=值;
简写:
var 变量名=值;
3、一条语句声明多个变量
var 名1,名2,...,名n;
ex:
var stuName="张三丰",age=18,gender,score;
3、变量名的规范
1、不允许使用JS的关键字或保留关键字
2、允许包含字母、数字、下划线(_)以及$
var stuName;正确
var $stuName;正确
var stu-name;错误,不能出现 -
3、不能以数字开头
var 1name;错误
var name1;正确
4、不能重复
5、尽量见名知意
var a;
var b,c,d,e,f,g;
var studentName;
6、推荐使用 "匈牙利命名法","驼峰命名法","下划线命名法"
驼峰命名法:
1、变量名由一个单词组成,采用全小写
2、变量名由多个单词组成,第一个单词采用全小写,
其余的每个单词首字符变大写
var studentName;
4、变量的使用
1、未经初始化的变量
1、变量声明之后,没有被赋值就直接使用
var stuName;
console.log(stuName);
结果为:undefined
2、变量未被声明过,而直接使用
console.log(stuAge);
2、声明变量不使用var
在JS中,允许声明变量时不使用var关键字
如果省略var关键字,声明的就是"全局变量"
但,并不推荐此写法
stuGender="男";
console.log(stuGender);
3、可以对变量进行存取操作
1、设置变量的值-存值操作(SET操作)
将数据保存在变量中
特点:只要变量出现在赋值符号(=)的左边,一律是存执操作
var stuName="张三丰";
stuName="张无忌";
var newName=stuName;
2、获取变量的值-取值操作(GET操作)
将数据从变量中取出来使用
特点:只要变量"没"出现在赋值符号的左边,一律都是取值操作
var stuAge=18;//存值操作
console.log(stuAge);//在控制台上打印输出stuAge的值
document.write(stuAge);//在页面上打印输出stuAge的值
var newAge = stuAge;
针对newAge 是存值操作
针对stuAge 是取值操作
stuAge = stuAge + 10;
存值 取值
套餐名:香辣鸡腿堡套餐
汉堡:香辣鸡腿堡
配餐:烤翅
饮料:可乐
2、常量
1、变量与常量
变量:是一个可以变化的数据
常量:是一个不能变化的数据
常量的特点:
在程序中,一旦被声明好,在程序运行过程中就不允许被修改
2、语法
const 常量名=值;
注意:
1、声明常量时必须赋值
2、通常,常量名称采用全大写形式(规范)
3、练习
声明一个变量 用来 保存一个圆的 半径值
计算 该圆的周长,并打印输出 2*π*半径
计算 该圆的面积,并打印输出 π*半径*半径
4、数据类型
1、作用
决定了数据在内存中所占的空间大小
2、数据类型分类
1、原始类型(基本类型)
1、number类型
数字类型
可以表示32位的整数,也可以表示64位的浮点数
整数:32位空间(4字节)
浮点数:小数,64位空间(8字节)
整数:
1、保存十进制数字
由0-9共10个数字组成,逢10进1
var age = 35;
2、保存八进制数字
由0-7共8个数字组成,逢8进1
JS中,八进制数字值,由0开始
var num=010;
3、保存十六进制数字
由0-9,A-F 共 16个数字组成,逢16进1
JS中,十六进制数字,由0x开始
var num=0x10;
浮点数:
小数
支持小数点计数法:35.5,76.8,31.00004
支持指数记录法:4.3e2
2、string类型
字符串类型
表示一系列的文本字符
由Unicode字符,数字,标点符号组成的序列
Unicode : 编码方式之一,
可以由一组十六进制的数字(Unicode码)来表示一个字符。
每个字符在计算机内存中,占2个字节
如何查看字符的Unicode码???
字符.charCodeAt(); 十进制表示方式
字符.charCodeAt().toString(2); 二进制
字符.charCodeAt().toString(16);十六进制
张:24352(十进制)
张:0101111100100000(二进制)
张:5f20(十六进制)
如何将 Unicode码 转换为字符???
使用 \u 将 十六进制的Unicode码转换为字符
var str = "\u5f20";
中文汉字的范围:
从 \u4e00 开始 到 \u9fa5 结束
string在声明的时候需要使用"" 或 '' 引起来
var num1 = 456;//number
var num2 = "456";//string
特殊字符需要转义:
ex:
想在字符串中 打印输出 ""
\n : 换行
\t : 一个制表符
\" : "
\' : '
\\ : \
3、boolean类型
布尔类型
在程序中只表示真 或 假 的状态值(条件中用的多)
该类型 仅有两个值
true :真
false :假
在实际运算中true当做1运算,false当做0运算
4、undefined
语义:访问的数据不存在
2、引用类型
js是解释执行
js两大类型:原始类型和引用类型
所有的var 都会提前到当前script中最前端
1、隐式转换:
规律:1、默认一切转数字类型,做算术计算。
boolean类型 true--> 1 false--> 2
2、+法中,只要有一个是字符串,都转为字符串,
+变为字符串拼接
其他类型转字符串,在字符串前后直接加引号
表达式:有数据、变量和运算符组成的公式
*默认,从左到右,两两计算
NaN: 不是一个数字 的 数字
意义 类型
Not a Number
何时遇到:当无法转为数字是,或无法正常计算时
undefine和任何数计算,结果为NaN
特点: 和任何数据做计算,结果永远为NaN
加法技术中,碰上字符串,也会转为NaN
typeof(x):返回x的数据类型名称:Number string boolean
undefined
2、强制转换:程序员主动调用专门函数完成的转换
1、任意 to String:2种
var str = x.toString();
var str = String(x)---->相当于隐式转换
***String(x)万能
x.toString: null和undefined转不了
何时使用:通常都在js需要时,自动调用
2、***任意 to Number 3种
1、任意 to Number ;var n = Number(x)--> 隐式
何时使用:将非字符串类型转为数字时使用
将纯数字组成的字符串转为数字类型
2、String to Number:
1 to 整数 var n=parseInt(string)
何时使用:将*字符串*转为整数时使用
如果传入的不是字符串,则先隐式转为String
原理: 从头开始读取字符串中的每个字符
跳过开头的空字符
只读取数字字符
只要碰到第一个不是数字的字符,就退出
不认识小数点
Number vs parseInt
Number 只认识纯数字组成的字符串
Number却可转boolean类型
parseInt(str)认识包含非数字字符的字符串开头位置的数字
parseInt转不了boolean
2、String to 浮点数:var n=parseFloat(str);
何时使用:只要将字符串转为小数时
用法和parseInt用法完全一样
只认第一个碰到的小数点。
3、任意类型 to Boolean :var bool = Boolean(x);
"" 0 NaN undefined null --->false
其余都是true;
3、条件运算符(三目运算符)
目:操作数
单目运算符:只有一个操作数,++,--,!
双目运算符:有两个操作数,+,-,*,...
三目运算符:要求有三个操作数
条件运算符:
? :
表达式1 ? 表达式2 : 表达式3;
表达式1 :是一个条件,结果为boolean类型
如果表达式1的值为true,则执行表达式2
如果表达式1的值为false,则执行表达式3
输入一个考试成绩,如果成绩大于60分,输出及格,否则输出 不及格
练习:输入一个年龄,如果年龄大于等于 18岁,打印输出 "你已成年",
否则,打印输出,"还未成年"
条件运算符的嵌套:
表达式2, 表达式3的位置处分别可以再嵌套一个条件表达式
ex : 根据成绩 输出成绩 等级
成绩100 输出 A
90 ~ 100 输出 B
80 ~ 90 输出 C
60 ~ 80 输出 D
60以下 输出 E
课堂练习:获取用户输入,保存在变量input中
var input = [window.]prompt("输入提示");
****凡是从页面上进来的,都是字符串***
算数运算符:+ - * / % ++ -- 都带隐式转换
返回值:只能是number,如果运算无效,返回NaN
隐式转换:默认转Number
+法中,碰到字符串,都转字符串,再拼接;
%膜运算(取余数):m%n:m/n取除不尽的余数部分
何时使用:1、判定能否整除:
比如:判定奇偶数:
m%2等于0,说明m是偶数
m%2不等于0,说明m是奇数
2、限制计算结果,永远小于除数
***递增、递减运算:++ --
n++: n=n+1;讲n中的值加1,后在保存回n中
2种情况:
++n:前++ ,返回*新*值
n++:后++ ,返回*旧*值
++n或n++单独使用,无影响
如果参与其他表达式中,会影响执行结果。
关系运算:
做比较,比大小
返回值:true、false
隐式转换:默认都转为数字再比较
如果两个都是字符串,则按位pk每个字符的unicode
特殊情况:
1、如果无法转为数字,转为NaN
NaN不等于,不大于,不小于任何值,甚至自己
NaN !=x --->true
isNaN(num):专门判定一个num数值是否为NaN
如果是NaN,就返回true,否则返回false
何时使用:只要判断一个数字无效,就用isNaN
开发中何时使用,反着用
用isNAN判断一个num是不是数字,或是否能被
隐式转为数字使用
!isNaN(num):返回ture--->num是数字
返回false---->num不是数字
2、如果两个都是字符串,则按位pk每个字符的unicode号
undefine vs null
undefine:所有变量的默认初始值,自动赋值
null:主动清空一个变量,释放一个变量
typeof的监测结果:
typeof(undefined)--->undefined
typeof(null)--->object
===:全等,首先类型必须相同,其次值相同
全等不带隐式转换
何时使用:要求类型相同,且值相等时。
3、如果参入比较的两个值都是字符串类型
不再转数字,而是pk每个字符的unicode号
总结:凡是条件:一般都是关系运算或是逻辑运算
***逻辑运算:多个条件(关系运算),综合得出最后的结论
只可能返回true/false
隐式转换:默认转换为boolean类型:boolean(x)
何时使用:只要综合多个条件,得出最终结论
如何使用:3种
&&:读作且,程序总称为“逻辑与”
条件1&&条件2:必须条件1和条件2都为true,
结果为true,只要任意一个为false,结果为false
||:读作与,程序总称为“逻辑或”
!:读作与,程序总称为“非”
!条件:颠倒条件的true/false结果
***短路逻辑:逻辑运算中,如果前一个条件已经可以得出结论
则后续所有条件不再执行!
利用短路逻辑筛选按条件执行语句
条件&&操作:如果满足条件,才执行操作
否则,什么也不做
***函数:封装一项任务的步骤清单的代码段,再起一个任务名
函数是一个引用类型的对象
对象:内存中同时存储多个值的空间
何时使用:发现一项任务,被反复调用,要先将任务步骤封装
为一个函数,再反复调用
如果声明函数:
function 函数名([参数变量列表]){
步骤清单代码段
[return返回值]
}
如何调用函数:函数名([参数变量列表]);
强调:1、函数只有被调用时,才会执行!
2、函数可被反复调用!----代码重用
参数变量:专门接受方法执行所必须的数据的变量
何时使用:如果一个函数,必须提供指定数据,才能正常执行时,
需要提供几个数据,就定义几个参数接收
如何定义参数:不需要var,直接在函数名后的括号中定义参数名
每个参数名直接用逗号分隔
何时,如何转入参数值:调用时,按照参数定义的个数和顺序传入
为什么使用参数:参数可以让方法变的更灵活。
***内存中函数生命周期:
1、定义时:将函数封装在一个对象中保存---函数对象
函数名,其实是指向函数对象的一个变量
***定义时,不会读取函数的内容
2、调用时:在执行环境中增加一个档期函数的执行环境对象
才会逐行读取病执行函数的内容
3、调用后:函数的执行环境弹出,活动对象被释放
***作用域:一个变量的可用范围
本质其实是一个存储多个变量的对象
2、1.全局作用域:专门保存全局变量的对象
全局变量:在任何时候,任何位置都可被访问
2.函数作用域:专门保存函数内部的局部变量的对象
------活动对象
局部变量:2类:1、参数变量 2.在函数内声明的
值在函数调用是的函数内部才可以使用
return返回值:函数调用的执行结果
何时使用:只要函数的执行,需要有明确的返回结果时
要看调用者是否需要获得执行结果
如何定义返回值:在函数定义结尾:return返回值
何时如何获得返回值:调用时:
var 变量=函数名(XXX);
***按值传递:两变量间赋值或想函数中传递参数时
都是将原变量中的值复制一个副本给对方
修改一方,另一方不受影响
function buy(card){
card-=3;
console.log("余额"+card);
}
var card=10;
buy(card);//输出7
console.log("余额"+card);//输出10
***声明提前:在正式执行程序前,都会先预读所有var声明的变量
和function声明的函数,集中到当前作用域的顶部集中声明
***赋值留在原地***
function fun(){
return 1;
}
console.log(fun());//输出2
function fun(){
return 2;
}
console.log(fun());//输出2
var fun=100;
console.log(fun());//报错
定义函数的第二种方法:
var 函数名=functon(参数){函数体;return 返回值};
vs 声明函数
第二种方法,函数定义不会被提前,仅函数名提前
声明函数,整体(函数名+函数定义)提前
问题1:如果一个表达式或函数有结果,就可至今当一个值用
问题2:如果传入参数个数不符,不会报错:
个数超了,多出的没用
个数不够,未接到值的参数变量,默认值undefine
问题3:在函数内,为没用声明过的变量赋值,
变量会被自动创建在全局--->危险
强烈建议:所有变量使用前,必须用var声明。
function max(a,b,c){
var max=a;
b>max && max=b;//利用短路逻辑
c>max && max = c;
return
}
console.log(max(5,4,6));
全局函数
手册中:课程表--JavaScript--javascript对象---js functions
干扰项:BOM,凡是在BOM阶段交的都不是全局函数。
编码解码:
encodeURL:对包含多字节字符的url字符串编码为单字节字符组成
decodeURL:键encodeURL编码后的字符串,解码为原文
为什么:url不允许包含多字节字符:比如汉字
www.baidu.com/s?kw=张东
%E5%BC%AO%E4%B8%9C
问题:url还不允许包含保留的特殊符号。比如:/
解决:encodeURLComponent/decodeURLComponent
eval:专门执行字符串格式的js语句
还可计算字符串格式的表达式的值
除数为0:js中除数可以为0,结果为:infinity
Infinity,可参与关系运算
isFinite(num):专门判断一个数组是否在有限范围内
*分支结构:
程序3中结构:顺序 分支 循环
顺序:除去声明提前,其余代码默认都从上向下顺序执行
分支:根据不同的条件,执行不同的代码
循环:让程序反正执行一段相同代码
*分支:3种
1、一个条件,一件事。满足条件就做(,不满足就不做)
如果操作简单:利用短路:条件&&(操作1,操作1,...)
如果操作复杂:
2、一个条件,两件事,满足条件做第一季,不满足做另一件
如果操作简单:三目:条件?操作1:操作2;
3、多个条件,多件市,多选一执行,可一件不执行
如果操作简单:三目:条件1?操作1:
条件2?操作2:
.....? ....:
默认操作;//不能省略
第一个汉字的uncode编码为 "\u4e00"
最后一个汉字的UNcode编码为"\u9fa5"
***for**循环
语法:
for(var 循环变量=初始值;循环条件;迭代编号循环变量){
循环体;
}
特殊写法:
1、for中第一部分,可同时声明并初始化多个变量
2、for中的第三部分,可同时执行多个小操作
3、for循环条件可省略,省略后是死循环
比如:for(;;)代替while(true)
***数组:多个变量的集合,起一个统一的名字---用法
连续保存多个数据的引用类型的对象---存储
为什么使用数组:
程序=数据结构+算法
好的数据结构可以极大提高程序的执行效率!
何时使用:程序中都是用数组集中管理多个数据
如果使用:创建 赋值 取值
1、创建:4种
1、创建空数组:var 数组名=[];---js中见到[],就是数组
2、创建数组同事,初始化数组中的每个元素:
var 数组名=[值1,值2,值3,...]
内存中的数组:引用类型的对象
每个值相当于一个元素
每个元素都有个下标
下标从0开始,每次增1,到个数-1结束
数组对象的个数:arr.length
arr.length用于等于最大一个下标+1;
3、创建空数组:var 数组名=new Array([n]);
new创建一个新对象
Array数字类型
n标识初始元素的格式,省略则创建空数组
4、创建数组同时初始化数组元素:
var 数组名=new Array(值1,值2,值3,...);
new Array的歧义:new Array(7);
如何使用数组中每个元素:数组名[i]
数组名[i]的用法和普通的变量完全相同!
赋值:数组名[i]=值
取值:任何位置使用数组名[i],等效于直接使用数组名[i]中的值
数组是引用类型对象:按值传递
原始类型的值,赋值后,相互不影响
引用类型的对象,赋值后,依然引用同一个对象
任何修改,都会影响对方
null:主动释放一个对象
垃圾回收器:专门释放内存中不再被引用的对象的小程序
伴随主程序执行
什么是: js引擎会自动释放不再被任何变量引用的存储空间
每个对象都有一个引用计数器,增加引用+1,减少引用-1
一个对象,应用计数器为0,不在被任何变量引用,被回收
建议:使用完较大的对象后,都要主动释放
数组的length熟悉固定套路:2个
1、获得最后一个元素值:arr[arr.length-1]
2、想数组未尾追加一个新元素:arr[arr.length]=新值;
遍历数组:依次对数组中每个元素执行相同操作
//三要素
1、条件:小标i<数组长度
2、变量:下标i从0开始,每次++
for(var i=0;i<arr.length;i++){
当前元素:arr[i]
}
chrome中的console.log有时是异步执行,伴随住程序同时执行
关联数组:
什么是关联数组: 可自定义下标名称的数组
vs索引数组: 下标都是数字的数组
为什么: 索引数组中的下标都是无意义的数字,不便于查找
何时: 只要希望在数组中按照意义快速定位一个元素时
如何:
创建: 2步:
1. 创建空数组: var ym=[];
2. 向空数组中添加新元素,使用自定义的下标名称
ym["name"]="杨幂";
ym["math"]=81;
ym["chs"]=53;
ym["eng"]=89;
访问: ym["下标名"]——用法同普通变量
强调:key必须是字符串
特点: ***length属性失效,永远为0***
如果遍历hash数组:
for( var key in ym){
//in依次取出ym数组中的下标名保存到key中
//key仅获得下标名
//ym[key]获得当前元素的值。
//强调: key不加"",因为key是变量,不断变化
}
关联数组中的key不能重复
所以数组如果访问不存在的下标位置,不会保存
会返回undefined9
原理:
索引数组的问题: 查找只能靠遍历
结果: 查找速度受存储位置和元素总数的影响极大
关联数组解决:
hash算法:
根据一个字符串,计算出一个尽量不重复的序号
添加元素:
将自定义的下标名交给hash算法计算出不重复的序号,
将元素保存到序号位置
取值时:
将自定义的下标名较为hash算法,计算出和存入时相同
的序号,直接去序号位置获取元素值
优点:
无需遍历, 查找速度和存储位置以及元素总数无关
今后:只要遍历索引数组,选普通for循环
只要遍历关联数组,值能用for in 循环
indexOf 接收一个数组和一个值,
返回值在数组中的下标位置i
只找第一个,然后就退出
如果没找到,就返回-1
2、数组API:浏览器场所已经实现的方法
开发人员直接调用,不需要了解具体实现。
将数组转为字符串:2个
var str =arr.toString();返回数组中元素的内容,用逗号分隔
var str = arr.join("连接符");***可自定义连接符***
固定套路:
1、无缝拼接数组每个元素:var str = arr.join("")
如果不加"",等效于toString,用逗号
var chars=["h","e","l","l","o"];
var word = chars.join("");
console.log(word);//hello
2、将单词拼接为句子:var str = arr.join(" ")
var words =["no","zuo","no","die","!"];
var stmt = words.join(" ");
console.log(stmt);//no zuo no die !
3、将数组拼接为html元素
var provs = ["北京市","天津市","河北省","河南省"];
var html = "<select><option>" +
provs.join("</option><option>")
+"</option></select>";
document.write(html);//输入在页面上为下拉列表
优化:数组的拼接比字符串拼接效率更高
建议:今后凡是频繁的字符串拼接,都要2步:
1、先将要拼接的子字符串放入一个数组中用
2、利用数组的join方法,一次性生成结果字符串
拼接数组:var newArr = arr1.concat(arr2,值1,值2)
强调:concat不能修改原数组,总是返回一个新数组
获取子数组:var subArr = arr.slice(stati,endi+1)
starti:开始获取下标位置
endi:表示获取到的下标位置
***含头不含尾**
slice方法支持倒数参数:其实负数下标不存在
假定的负数下标从-1开始
splice:删除 插入 替换
1、删除:arr.splice(starti,n)
从starti位置开始,删除n个元素
2、插入:arr。splice(starti,0,新值1,新值2,....)
在starti位置插入新值1,新值2...
原starti位置及其之后的元素,被向后顺移
3、替换:arr.splice(starti,n,新值1,新值2,...)
新元素的个数和n不一定相等
数组会自动调整元素的位置和长度
颠倒数组中所以元素的位置:arr.reverse();
数组的sort方法:arr.sort();
特点:默认按升序排列
默认一切都转为字符串,再按字符串比大小
自定义排序规则:2步
1、定义比较器函数:专门比较任意两数大小的函数
规定:两个参数(a,b)
必须返回数组:如果a>b,就要返回正数
如果a<b,就要返回负数
如果a=b,就要返回0
2、将比较器函数做完参数传入sort方法中
arr.sort(比较器函数名);//函数名不加圆括号
函数 vs 方法:
都是function
不属于任何对象的叫函数(不需要通过.访问)
属于特定对象的函数叫方法(需要通过对象.才可访问)
***函数也是引用类型的对象
***给升序改降序,只要给比较器的逻辑*-1;
数组API
*栈和队列:其实都是数字,只不过使用了不同的方法
栈:一端封闭,只能从另一端进出的*数组*
何时使用栈:只能从数组一端进出
LIFO
结尾出入栈:
入栈:arr.push(新值);==》arr[arr.length]=新值
出栈:var last = arr.pop();
开头出入栈:
入栈:arr.unshift(新值);
出栈:var first = arr.shift();
每次出入栈都会影响所有剩余元素的位置发生顺移---低
队列:只能从一端进入,必须从另一端出
何时使用:只要先到的先得
2****二维数组:数组的元素又引用了另一个子数组
何时使用:保存横行竖列的二维数据
保存上下级关系的数据
如何创建:2步
1、创建一个空数组:var data =[]
2、设置数组中每个元素再引用另一个小数组
data[0] = [0,0,0,0];
访问二维数组中任意位置的元素:data[r][c]
二维数组行下标r不能越界,越界就报错
遍历二维数组:固定套路
外层循环遍历行,内层循环遍历当前行的中的列
for(var r =0;r<data.length;r++){
for(var c=0;c<data[r].length;c++){
当前元素:data[r][c]
}
}
***字符串对象:对个字符组成的只能*数组*
和数组相同的API
访问字符串中任意一个字符:str[i]
字符串的长度:str.length
凡是不直接修改原数组的API,字符串都能用
比如:var substr = str.slice(starti,endi+1)
var newstr = str.concat(otherstr);
不能用:reverse() push() str[i]=‘字符’
笔试题:
内置对象:11个
ES标准已经规定好,有浏览器厂商已经实现的对象
开发人员直接使用,不必关系具体实现
String Number Boolean ----包装类型
Array Date RegExp Math
Error
Function Object
Global----->window
***包装类型: 专门封装原始类型的数据,
并提供对原始类型数据操作方法的对象
何时使用: 试图用原始类型的值调用方法时自动创建
用完自动释放
具体创建何种包装类型,要看值的类型
为什么有包装类型:原始类型的值没有任何方法
new String(xxx) vs String(xxx)
String(xxx):隐式类型转换为字符串,返回原始类型的字符串值
new String(xxx):创建一个String包装类型的对象
返回String包装类型的对象
转义字符:如果字符串内包含与预防冲突的特殊符号
可用转义字符将特殊符号标记为普通字符
比如:"-->\" '-->\'
String API:所有API都无法修改原字符串,必定返回新字符串
1、大小写转换
var newStr = str.toLowerCase();//全部转小写
var newStr = str.toUpperCase();//全部转大写
何时使用:只要不区分大小写
2、获取指定位置的字符或unicode
var char =str[i]
str.charAt(i);
var unicode = str.charCodeAt(i);
3、查找关键字的位置:2个API,返回的都是关键字的位置下标
找下一个匹配的关键字位置:var i = str.indexOf("kword",starti)
如果省略starti,从0开始
找前一个匹配的关键字位置:
var i = str.lastIndexOf("kword",starti)
如果省略starti,从最后一位开始
strarti:开始查找的位置
如果没找到,都返回-1;
获取指定位置的字符:
str.charAt(i) => str[i]
获取指定位置的字符的unicode号
str.charCodeAt(i) 获得str中i位置的字符的unicode号
将unicode号反向转为正文:
String.fromCharCode(unicode);
获取子字符串:
str.substring(starti,endi+1) =>str.slice(starti,endi+1)
强调: substring不支持负数参数!
解决: length-n 表示倒数第n个
str.substr(starti,n) 获取str中starti开始的n个字符
相当于: str.substring(starti,starti+n)
强调: 不考虑含头不含尾
****正则表达式:
什么是: 规定一个字符串中字符出现规律的表达式
何时: 2种:
1. 按照规则模糊匹配多种关键词
2. 按照规则验证字符串格式时
如何:
1. 关键词的原文就是最简单的正则表达式
2. 字符集:
什么是: 规定一位字符可选字符列表的集合
何时: 如果一位字符,有多种备选字时
如何: [备选字符列表]
强调: 一个字符集只能匹配1位
简写: 如果备选字符列表中字符是连续的,可用-省略中间的字符
比如:1位数字: [0-9]
1位小写字母: [a-z]
1位大写字母: [A-Z]
1位字母:[A-Za-z]
1 位汉字: [\u4e00-\u9fa5]
特殊: 除了XXX [^字符列表]
3. 预定义字符集:
什么是: 对常用字符集的简化写法
包括: 一位数字: \d [0-9]
一位字母,数字或下划线: \w [0-9A-Za-z_]
一位空字符: \s 空格,制表符等空字符
通配符: . 任意字符
强调: 只有在规则完全匹配时才能使用预定义字符集
问题: 无法匹配字符出现的个数
解决: 量词
4. 量词:
什么是: 规定一位字符集出现次数的规则
何时: 只要规定一位字符集出现的次数
如何:
强调: 总是跟在字符集之后
1. 有明确范围的:
6~8位 {6,8}
6位以上 {6,}
必须6位 {6}
2. 没有明确范围:
? 可有可无,最多一个
* 可有可无,多了不限
+ 最少一个,多了不限
5. 选择和分组:
选择:或|
分组:()
6. 指定匹配位置:
^ 匹配字符串开头
$ 匹配字符串结尾
比如: 仅匹配开头的空字符: ^\s+
仅匹配结尾的空字符: \s+$
同时匹配开头或结尾的空字符: ^\s+|\s+$
\b 匹配单词边界: 开头 结尾 标点 空字符
7.转义:\
8.预判:在正式匹配前,先大概预判整个字符串的规则
多用于排除法
比如:密码强度:6-8位字母、数字或下划线字符
必须包含一个大写和一个数字
所有字符:4大类:数字,小写字母,大写字母,特殊符号
1、排除:不全由数字和小写字母组成
(?![0-9a-z]+$)
2、排除:不全由大写字母和小写字母组成
(?![a-zA-Z]+$)
3、只能有字母或数字、_组成----
\w{6,8}
最终: (?![0-9a-z]+$)(?![a-zA-Z]+$)\w{6,8}
使用正则判断是否包含符合规则的关键词:
var i=str.search(/正则/i)
在str中查找符合正则要求的关键词,返回其位置
如果找不到,返回-1
问题1: 所有正则,默认都区分大小写
解决: 加后缀i 表示忽略大小写
问题: 1. 只能获得位置,无法获得内容
2. 只能找第一个。
解决: match方法
3. 查找所有关键词的内容
var kwords=str.match(/正则/ig)
查找str中所有符合正则要求的关键词,保存在结果数组kwords中
***如果找不到,返回null!
强调: 只要API的返回可能是null,就必须先验证不是null,再使用!
问题: 所有正则,默认仅匹配第一个关键词
解决: 加后缀g 表示查找全部
问题: 只能返回所有关键词的内容,无法返回每个关键词的位置。
4. 即查找每个关键词的内容,又查找每个关键词的位置 ?
替换: 将字符串中找到的敏感词替换为新内容
简单: 将所有敏感词替换为一个统一的新值
str=str.replace(/正则/ig,"新值");
高级: 根据不同的敏感词,动态选择要替换的新值
str=str.replace(/正则/ig,function(kword){
return 根据kword动态选择不同的替换值返回
})
其中: replace会在每个找到的关键词上执行function
每次执行,都会将本次找到的敏感词自动赋值给kword参数变量。
替换或删除子字符串:
var nweStr = str.replace(reg,"替换字符");
格式化字符串:
正则表达式中的每个(),都是一个字表达式
每个字表达式都会自动获得一个从1开始的编号
替换时,可用$n,指代本次匹配中第n个子表达式的对应内容
分隔字符串:
var subs=str.split(reg,[count]);
reg:正则表达式
[count]可有可无,从0开始,代表切割的第几个
例如:var mail=zhangdong@dane.com;
var arr = mail.split(/@/);
console.log(arr[0])输出zhangdong
String API:
获取子字符串:3种
var sub = str.slice(starti,endi+1)
str.substring(starti,endi+1)//不支持负数参数
str.substr(starti,n);//获取多少个
查找:4种
1、查找固定关键字,仅返回位置,可指定开始位置
var i =str.indexOf("kword"[,starti]);
str.lastIndexOf("kword"[,starti]);
何时使用:关键字确定
通过循环,反复获得每个关键字的位置
2、只判断有没有:var i=str.search(reg);
返回值:找到返回i,没找到返回-1;
3、获取所以关键字的内容:var kwords=str.match(reg);
g
返回值:找到返回所以关键字内容的数组
没找到返回null,必须先判断不是null,再使用
4、即获得每个关键字的内容,又获得每个关键字的位置:
var arr = reg.exec(str);
特点:1、每次只返回一个关键字的内容,存在arr的[0]
如果找不到了,返回null
2、将本次找到的关键字的位置保存在arr.index
3、自动调整reg.lastIndex属性为下次开始的位置
课堂练习:网络爬虫
正则:<a[^>]*href=['"][^'"]*['"][^>]*>.*</a>
默认贪婪模式:尽量匹配最差的符合条件的子内容
懒惰模式:只匹配最短的符合条件的子内容
贪婪改懒惰:.*----> (.*?)
RegExp.$n:获得本次匹配中第n个子表达式匹配的内容
替换:str=str.replace(reg."替换值");
如果reg中没有g,只替换第一个匹配的
验证:
var bool = reg.test(str);
如果str符合reg的要求,返回true,说明验证通过
否则返回false,说明验证未通过
***强调
凡是验证,前加^后加$;
如果不加,只要局部匹配,就通过
Math:封装了数学计算的常量值和方法
***不能实例化对象
实例化:用new创建一个指定类型的具体对象---实例
instance
Math常用API
取整:3种
上取整 下取整 四舍五入取整
Math.cei(n) Math.floor(n) Math.round(n)
n.toFixed(d) VS Math.round(n)
n.toFixed(d):指定d位小数四舍五入,*返回字符串*
Math.round(n):不能指定小数位数,只能取整
*返回number*
乘法和开平方
乘法:Math.pow(底数,幂)
开平方:Math.sqrt(n);
最大值和最小值
var max = Math.max(值1,值2,...);
//默认不支持数组;
固定套路:获取数组中的最大值和最小值:
var max =Math.max.apply(Math,[值1,值2,...])
随机数:Math.random() 0<=r<1;
公式:min -max取随机整数
Math.floor(Math.random()*(max-min+1)+min)
Date:封装了1970年1月1日0点至今的毫秒数
创建:4种
1、创建日期对象,同时获得客户端*当前时间*
var now = new Date();
2、自定义任意时间点
var date = new Date("xxxx/xx/xx[xx:xx:xx]");
3、自定义任意时间点
var date = new Date(xxxx,xx,xx[,xx,xx,xx]");
月,都要-1修正。
4、复制一个日期对象:
何时使用:日期API都至今修改原日期对象
如果希望留住旧日期对象,就需要先复制,再修改副本
如果复制:var old= new Date("XXX");
var target=new Date(old.getTime());
其中:old.getTime()返回旧时间中的毫秒数
Date对象API:
分量: 年 月 日 星期
FullYear Month Date Day
时 分 秒 毫秒
Hours Minutes Seconds Milliseconds
1、每个分量都有一对儿get/set方法
getXXX获得分量的值
setXXX(n)设置分量的值,Day没有set
2、命名:年月日星期,没有s结尾
时分秒毫秒,都有s结尾
3、返回值:除Date外,其余都是从0开始,进制-1结束
强调:只有month需要修正,其余都正常
4、日期转字符串:
var str= date.toLocaleString();//日期+时间
var str = date.toLocaleDateString()//日期
var str = date.toLocaleTimeString()//时间
Date的计算:2种
1、两日期对象可相减,结果是毫秒差
2、对日期任意分量做加减:3步,取分量,做加减,set回去
set方法自动调整进制
固定套路:date.setXXX(date.getXXX()+/-n);
错误处理:即使程序出错,也要保证程序不退出的机制
Error对象:在错误发生时,自动创建的封装错误信息的对象
属性:err.name:错误类型:6种
SyntaxError:语法错误
ReferenceError:引用错误,找不到对象或变量时;
TypeError:类型错误,错误的使用了对象的"方法"
RangeError:范围错误,参数超范围
EvalError:Eval错误,错误的使用了eval函数
URlError:URL错误
如何错误处理:
语法:try{
可能出错的语句;
}cathc(err){
一旦出错,执行的错误处理代码;
}[finally{
无论是否出错,都要执行的代码
}]
建议:能用if屏蔽的问题,优先选择if
大多说try catch都可提前预防
笔试题:js中如何解决浏览器兼容性问题:3种
1、不兼容的类型或方法:2种
if else
try catch
2、不兼容的值,短路逻辑中的||
值1||值2
***错误处理中的return
1、finally中的return,会替换try catch中的return
2、即使finally中没有return,finally中的代码一定会再return钱
执行,但无法影响已确定的return结果
*****函数对象
执行环境栈:ESC,保存全局已经每个函数的执行环境的栈结构
执行环境:EC,调用函数是,创建的引用函数资源的对象
窗口一打开,默认ESC中压入一个全局EC
全局EC引用了window对象VO
window对象中的变量都是全局变量
变量对象VO,专门存储变量的对象
函数声明周期
定义时:仅创建一个函数对象,封装了函数的定义
不会读取函数的内容
调用时:创建函数的EC对象压入ESC中
函数的EC对象引用了,当前函数的活动对象的AO
活动对象:AO:专门保存本次函数调用是的局部变量
AO中有一个属性始终指向window对象
变量使用规则:优先在AO中找
找不到,才去window对象找
调用后:函数的EC对象出栈,AO对象失去引用,被回收
AO对象中的局部变量一起被释放
***重载:overload
相同名称,不同参数列表的多个函数
在调用是,可根据传入参数的不同,动态选择对应的函数执行
js语法默认不支持重载,但可用arguments对象模拟重载的效果
arguments对象:调用时,自动创建并接收所有传入的参数值
类(like)数组(的)对象
2点:1、arguments[i];
2、arguments.length;
何时使用:今后只要多个操作,共用同一个函数名时,
***类数组对象 VS 数组对象:
类型不同:类数组对象的父类型是Object
数组对象的父类型是Array
导致类数组对象无法使用数组类型的方法
类数组对象转为数组对象 固定套路:
var arr = Array.prototype.slice.apply(arguments);
call
总结:今后大部分方法依然要定义参数
只有不确定传入参数的个数时,才省略参数,用arguments
****匿名函数:定义时,不用任何变量引用的函数,
何时使用:2种情况:
1、如果一个函数只执行一次----匿名函数自调
2、如果一个函数作为对象教给其他函数使用时---回调
创建一个比较器函数:3种
1、声明方式定义函数:funciton compare(a,b){return a-b}
只有声明方式定义的函数才能被声明提前
***以下两种方式定义的函数,不能被提前
2、函数直接量方式定义
var compare = funciton(a,b){return a -b}
3、使用new关键字:
var compare = new Function("a","b","return a -b")
//括号中的引号必须要加
匿名函数的优点:节约内存空间
调用前和调用后,内存中不创建任何函数对象
总结:arr.sort(function(a,b)(return a-b));
****作用域与作用链
作用域:一个变量的可用范围,其实就是变量的实际存储位置
只可能是window中或AO中
window:全局作用域--全局变量
AO:函数作用域---局部变量
本质:EC对象的一个scope属性
引用了window或AO对象
作用域链:以当前EC的scope属性为气垫一次引用每个AO,直到
window结束,形成的多级引用关系
只要在作用域链上存在的变量,当前函数都可使用
*****闭包:
问题:全局变量 VS 局部变量
全局变量:优:反复使用,且共享使用
缺:可能随时在任意位置被篡改---全局污染
建议:尽量避免使用全局变量
局部变量:不可反复使用!方法调用完自动释放
解决:闭包:反复使用一个局部变量,且不会被污染
何时使用:想反复使用一个局部变量,且不希望被污染时,
就要用闭包结构包含局部变量
如何使用:1、定义外层函数(工厂函数)
特点:2个
1、定义了受保存都局部变量
2、返回一个专门操作局部变量的内部函数对象
2、调用外层函数(工厂函数),获得返回的内部函数对象
3、使用获得的内部函数对象,操作受保护的局部变量---唯一途径
缺点:比普通函数占用更多的内存空间(外层函数的AO)
判断闭包输出结果:
1、找受保护的局部变量
2、外层函数被调用几次,就创建了几个受保护的变量副本
3、同一次外层函数调用返回的内层函数,永远使用统一个变量
*****面向对象:
对象:程序中描述现实中一个具体属性的方法的结构
内存中保存多个属性和方法的一块存储空间
面向对象:OOP程序中,描述一个具体事务都要用对象来封装事物
的属性和功能
写任何程序,都要先找对象
再识别对象的属性和功能
封装:将描述一个事务的属性和方法集中定义在一个对象中
2、创建对象:3种
1、仅创建一个对象:2种
1、var obj={"属性名":值,"属性名":值,....};
对象 vs 关联数组
***js中一切对象底层都是关联数组;
每个属性可用["属性名"]访问
遍历一个对象中所有属性,也用for in
也可以在任何时候动态添加新属性
强行访问没有的属性返回undefined
方法其实就是属性引用了一个函数对象而已
2、 var obj=new Object();//创建一个空对象
约等于{};
obj.属性名=值 <==> obj["属性名"]=值;
......
******this关键字:存在EC中,保存正在调用当前方法的对象
默认this--->window
对象中的方法,要使用对象内部的属性是,必须用this引用
不用this:默认在作用域链(AO和window)中找
加this:在this应用的当前对象中找
*****this和定义在哪儿无关
只和调用时使用的对象有关
没有用任何对象,就直接调用的函数,this默认值window
2、反复创建多个相同结构的对象时,2步
1、创建构造函数:规定一类对象,统一属性的函数
function 类型名(属性参数列表){
this.属性名=参数值;
this.属性名=参数值;
... ...
this.方法名=function(){
}...
}
2、用new调用构造函数,装饰一个新创建的对象
var obj=new 类型名(属性值,...);
new:1、先创建空对象,相当于{};
2、用空对象调用构造函数,this-->正在创建的空对象
按照构造函数的定义,为空对象添加属性和方法
3、将新创建对象的_proto_属性指向构造函数的
Prototype对象
4、将空对象的地址,保存到等号左边的变量中
***原型和原型链
原型:prototype 保存所有子对象共有属性值的父对象
每个(构造)函数都自带一个prototype对象
所有被构造函数创建的字对象都有一个_proto_属性
指向构造函数的prototype对象
什么东西放在构造函数的prototype中?
所有子对象共用的属性值和方法---只在读取时共享
特殊情况:修改prototype中共有属性,必须只能用prototype对象
不能用子对象
如果用子对象修改共有属性,会在子对象创建创建共有属性副本
原型链:由各级子对象的_proto_属性连续引用形成的结构
所有对象都有_proto_
所有对象原型链的顶部都是Object.prototype
.运算符:访问一个对象的属性,只要在原型链上有的,
都可以访问
重写:如果字对象觉得父对象的方法不好用,可在子对象定义同名
方法,就会覆盖父对象中的同名方法
原型相关API
1、判断对象的属性是自有,还是共有
自有属性:在当前对象本地保存的属性
共有属性:从原型链中继承来的属性
如何判断自有:obj.hasOwnProperty("属性名")
如果返回false,不一定说明共有,也可能没有!
如何判断在原型链上有没有:2种
1、"属性名" in 对象
2、if(obj["属性名"])如果有效
可能被干扰:如果属性值刚好为0,NaN,null,""
如何判断共有:固定套路
if(obj.hasOwnProperty("属性名")){
console.log("是自有属性")
}else if("属性名" in obj){
console.log("是共有属性")
}else{
console.log("没有属性")
}
2、获得任意子对象的原型(父对象):
obj._proto_
var prototype=Object.getPrototypeOf(子对象);
何时使用:无法获得构造函数时,又希望设置子对象的公有
属性
3、判断父对象是否在子对象的原型链上
上级对象.isPrototypeOf(子对象)
强调:isPrototypeOf不仅找直接父级,而是找整个原型链
*****/*笔试题*/
如果判断一个对象是数组类型:typeof失效
1、if(Array.prototype.isPrototypeOf(obj)){
obj是数组类型
}
2、其实构造函数的prototype指向原型对象
同时,原型对象有constructor指向构造函数对象
if(obj.constructor==Array){
obj是数组类型
}
3、判断子对象是否是指定构造函数的实例instanceof
if(子对象 instanceof 构造函数名){}
instanceof也是查找挣够原型链
4、if(Object.getPrototypeOf(obj)==Array.prototype){}
5、call和apply
call和apply:在调用方法时,修改EC中的this
Object.prototype.toString.call(arr)=="[object Array]"
执行的一刹那,相当于arr.toString();
apply(arr)
call VS apply:
1、都是,在调用方法时,修改当前调用方法的对象
差别:传入参数的形式:
xxx.call(obj,值1,值2,值3...)
xxx.apply(obj,[值1,值2,值3...]);
6、ES5中新函数:Array.isArray(obj)
继承:父对象中的属性和方法,子对象可直接使用
为什么继承:代码重用!节约内存空间!便于维护
js中的继承都是用_proto_
1、直接继承对象:修改对象的_proto_
3种:
1、仅修改一个对象的_proto_
Object.setPrototypeOf(子对象,父对象)
2、通过修改构造函数的原型对象,实现批量修改后续子对象
的继承关系
构造函数.prototype=父对象
强调:仅影响之后创建的对象的继承关系
之前创建的对象依然继承旧构造函数.prototype
3、Object.create(父对象[,{属性列表}])
创建一个空对象
继承父对象中的属性
继承同时可再扩展属性和方法
2、仅继承机构:模拟java中的继承。
function 父类型构造函数(属性参数1,属性参数2){
this.属性1=属性参数1;
this.属性2=属性参数2;
}
function 子类型构造函数(属性参数1,属性参数2,属性参数3){
父类型构造函数.call(this,属性参数1,属性参数2)
this.属性3=属性参数3;
}
var obj=new 子类型构造函数(值1,值2,值3)
总结:面向对象:封装 继承 多态(重载和重写)
多态:同一个东西在不同情况下,表现不同的状态
java 竖杠语法 java中两竖代表什么
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章