day01
am:
前端三大基础知识:
HTML:专门编写网页内容
CSS:专门设计网页样式
JavaScript:专门设计网页交互的语言
交互:输入数据,程序处理数据,返回结果
什么是JavaScript:
1、专门设计网页交互的语言
2、运行在JavaScript解释器中
3、“解释”执行——像读书一样
4、互联网第一大语言:JSer
布兰登艾奇:4门语言拼凑出——JavaScript
ECMAScript标准:JavaScript核心语法
微软:JScript
ECMAScript标准:一纸空文
JavaScript和JScript都号称完全实现了ECMAScript标准
W3C:DOM标准:专门操作HTML元素,CSS样式,事件的统一标准!
BOM:专门操作浏览器窗口的工具。
没标准,由浏览器厂商自行实现
JavaScript=ECMAScript+DOM+BOM
Mozilla基金会——>Firefox
JSer最大挑战:浏览器兼容性问题
JavaScript典型用途:
1、客户端数据计算
2、客户端表单验证
3、动画
JavaScript特点:纯文本;解释执行;弱类型;基于对象
如何让使用:
1、使用浏览器自带的js解释器:
F12——>控制台
光标处写脚本代码,回车执行。
console:指代控制台:专门调式程序输出结果的窗口。
log:控制台console提供的一个功能:向控制台输出一行日志。
多行:shift+enter——>换行
**JavaScript中区分大小写!**
**字符串单双引号都行**
2、单独安装专门的解释器软件:node.js Chrome V8
win+R——>cmd——>node
退出:两次Ctrl+c
执行.js文件:1、先cd到.js文件所在路径
2、node 文件名 回车
3、随网页一同运行:
浏览器 包含两种工具:
排版引擎:专门加载HTML内容和CSS样式
解释引擎:专门运行js脚本
<script>元素:专门包含js脚本块的元素
<script>中脚本块何时运行?随网页加载,解释执行
<script>中都要使用js语法!
html元素的事件“属性”中:
什么是事件?元素可以根据鼠标或键盘的不同操作相应不同的交互行为。
charset必须和文件的存储编码一致
<script>解释执行,读到执行。先读先执行。——<script>放置的先后顺序影响程序结
果。
优化:放在body的最后
一次定义处处使用,一次修改处处生效!
解决:凡是重复编写的代码块,都要封装为一个方法
方法:执行一个专门功能的一组代码的序列。
一般定义在<head>下的<script>中
语法:function 方法名(){重用的代码块}
*不调不执行*
调试:bug? debug:解决问题,排除错误
只要没反应或效果没出来就是出错!——>F12
查看错误原因——>定位错误位置!
<script>脚本块中的错误,仅影响“当前脚本块”中出错“位置之后”的脚本执行。
不影响<script>之外的其他元素加载或脚本执行。
function中的错误:只有调用方法是才触发!
页面内部脚本块问题:仅当前页面可用!
解决:外部.js文件!
什么是.js文件:专门保存js脚本源代码的文件。
源代码都要放到js解释器才能执行。
如何使用.js文件?2步:1、创建.js文件,编写源代码 2、在页面引入外部.js文件
内外部同名方法,解释执行!
pm:
JavaScript=ECMAScript(核心语法)+DOM(操作网页内容)+BOM(操作浏览器
窗口)
ECMAScript(核心语法)
*区分大小写*
*字符串必须用引号(单双都行)包裹*
*每条语句结尾都建议有分号*
语句:让程序可以做一件事的一行命令
脚本块:多行语句的序列
程序:让计算机可以模拟执行人类的想法!
注释:不会被解释执行或显示的代码说明——给程序员看的
注释也占网页流量!生产环境必须去掉!
HTML注释:<!---->
CSS注释:/**/
JS注释://单行注释 /*多行注释*/
*变量*
什么是变量?内存中专门存储数据的空间
程序都是在内存中运行
任何程序:IPO:Input Process Output
数据 数据 数据
何时使用变量?只要在程序中临时存储数据,都要放在变量中
怎么使用变量?声明,命名,初始化和使用
声明:在内存中开辟一个存储空间,并且起一个名字
怎么声明?var 变量名;
赋值:将等号右边的数据,装入等号左边的变量中!
如果未赋值:js默认赋值为undefined
命名规则:见名知意
保留字、关键字不能当变量名
保留字:js中已经占用的特殊意义的关键字
使用:使用变量名等于直接使用变量中存储的数据
+:拼接多段文字为一句话!
常量:一旦创建,值不可改变的特殊变量
如何使用常量:const 常量名=常量值;
强调:只有等号可以向变量中存入新值。普通运算不会改变变量的值。只是使用变量的
值。
只要带var就是声明,只要声明就会开辟内存空间、
js中新同名变量的空间会替换旧的空间。
有几个var,就会创建几个存储空间。
数据类型:变量中存储的数据类型。
js是弱类型:变量本身没有类型。只有变量中的值才有类型。
一个变量,可以反复保存不同类型的数据。
为什么要有数据类型:现实中所有数据根据用途不同,都分为不同数据类型。
原始类型:数据保存在变量本地!
number类型:表示一切用于比较或数学计算的数字
程序中数字分整数、浮点数(现实中的小数)
js中一切数字都用number保存,不分整数类型和小数类型
如何定义number类型?不带引号的数字字面量
程序中数字类型的舍入误差:程序中不能准确表示1/10,就好像现实中不能准确表示
1/3一样!
如何修正:按指定位数四舍五入:数字.toFixed(小数位数)
今后计算结果小数位数超长,说明碰到舍入误差。按位四舍五入。
精度计算不要用JavaScript
string类型:一串字符的序列!
Unicode:对所有语言文字中的字符编号
Why“因为计算机只处理数字,无法处理文字。
计算机处理unicode编号,就等效于处理编号对应的文字。
转义字符:专门表示非打印字符以及特殊符号
如何使用转义字符:特殊符号 比如:
换行 、 tab键
如果字符串中包含与语法相冲突的特殊字符,要用转为原文
*字符串变量的内容一旦创建补课费改变!如果改变,只能创建新字符串,抛弃旧字符串
。*
鄙视题!
var str = "Hello";
str = str + “Word”;
3个!
boolean类型:仅有两个值的特殊数据类型:true,false
何时使用boolean?只要一个值只有真假两种情况,就用boolean类型
undefined类型:表示一个变量仅声明过,但从未赋值。所有未赋值的变量,默认值都
是undefined。
undefined类型的值还是undefined!
原始类型的大小:
number:整数4字节,浮点8字节
string:每个字符两字节
day02
回顾:
JavaScript:ECMAScript(核心语法)
DOM(操作网页内容)
BOM(操作浏览器窗口)
ECMAScript:标准
Netscapt:javaScript Microsoft:JScript
变量:内存中存储数据的一块空间
一切数据必须存在变量中
声明:var 变量名——>在内存中开辟一块空间
赋值:变量名=值——>将值保存到左边的变量空间中备用
使用:使用变量名,就等效于直接使用变量中的数据
数据类型:
why:存储空间的大小,用途
原始类型:数据保存在变量本地
number string boolean undefined null
string:字符串内容一旦创建不能改变
var str = "Hello";
str = str + "World";
3个!
正课:
数据类型间的转换:
隐式转换:程序自动转换数据类型(坑)
弱类型:1、变量声明是不必限定数据类型,今后可能保存任何数据类型
2、数据类型间可以自动类型转换
仅考虑+:只要有字符串参与,一切类型都加""变为字符串
如果没有字符串,都转换为数字计算:其中true——>1 false——>0
强制转换:程序员通过调用专门函数,手动转换类型
2 string:x.toString();——>将x转为字符串类型
2 number:Number(x);——>将任意类型转为number类型
string——>number:
转为整数:var num = parseInt("str");
读取字符串中的整数部分
1、从第一个字符向后读。
2、如果碰到第一个数字字符,开始获取数字,再次碰到不是数字的字符,停
止读取
3、如果开头碰到空格,忽略
4、如果碰到的第一个非空格字符,不是数字,说明不能转——>NaN: Not
a Number
什么是NaN:不是数字(内容)的数字(类型)
转为浮点数:var num = parseFloat("str");
用法和parseInt全完相同
唯一差别:parseFloat认识小数点
prompt("提示信息"):专门用于请求用户输入数据,收集数据的对话框!
var str = prompt("提示信息");
*凡是从页面上获得的数据,都是字符串!必须先转换再计算*
什么是运算符:程序模拟人类运算的特殊符号
算数运算:-任意类型做-,都会被转为数据类型
如果有参数,不能自动转换为数字,则返回NaN
如果除数为0:Infinity——>无穷大
typeof(x):判断任意数据的类型
被除数%除数——模运算:被除数/除数,取除不尽的余数
何时用:限制一个数不能超过某个最大范围时
递增/递减运算:i++ ==> i = i +1;
i++单独用:++放前放后,效果一样:i++ ==> ++i;
i++出现在表达式内部:
前++,前+1,再参与表达式
后++,先用旧值参与表达式。表达式之后再+1
关系运算:判断大小!条件判断中使用
结果:成立:true,不成立:false
*自带隐式类型转换*
字符串参与运算:从第一个字符开始,取出每个字符 PK unicode编号
"Hello" H e(101)
"Hi" H i(105)
关系运算中:任何类型和数字比较,都转为数字,再比较
布尔类型参与关系运算,始终转为数字比较
PM:
关系运算:现将参与判断的数据,强转为相同类型,再比较
字符串比较:
undefined做==比较:
undefined类型,从null类型继承来的
undefined值被自动转换为null!
undefined == null ——>true
===严格相等:不带自动类型转换的相等比较!
类型和值必须都相等!才返回true。
严格相等最初就是为undefined和null设计的
只要不确定比较的类型,又不希望自动类型转换时,就用===
NaN做==:
isNaN(x):专门用来判断一个数据是不是NaN
如果是NaN返回true;如果不是NaN返回false
是
只要不能转换为数字的,都返回true
只要能自动转换为数字的,都返回false
关系运算中"",可以自动转换为false或0
总结:1、普通数据,先转换为相同类型,再比较
2、undefined,就用===
3、NaN,就用isNaN(x)
逻辑运算:基于多组关系运算,得出一个结论
&&:而且
||:或者
!:非,颠倒true和false,今后只要颠倒判断结果,就用!
短路逻辑:只要前一个判断足以得出最终结论,则后续条件不执行!
验证是不是汉字:>="u4E00" && <="u9FA5"
闰年的判断公式:(year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
位移:n << m ——>n*(2的m次方)
n >> m ——>n/(2的m次方)
赋值运算:赋值运算结果就是等号右边表达式的结果
扩展的赋值表达式:对已有的数据计算的同时,将结果再存回变量
何时使用:修改原变量值
三目运算:根据不同条件,动态返回不同结果!
三目:至少需要3个表达式。
语法:
一个条件,二选一:条件?当条件满足时返回的值:当条件不满足时返回的值
多个条件,多选一:
条件1?条件1满足时的值:
条件2?条件2满足时的值:
条件n?条件n满足时的值:
默认值;
需求1:2个数中取最大的
var score1 = 100;
var score2 = 80;
var result = score1 > score2 ? score1 : score2;
注意:后一个条件中不用包含否定前一个条件的关系判断。
因为,进入后一个条件隐含的条件就是前一个条件不满足。
day03
NaN == NaN? false NaN和任何数据比较,永远返回false
今后只要可能判断NaN时,用isNaN(x)
var str = "Hello";
str > 10? str > 10000? false
NaN NaN
关系运算中,字符串比数字,字符串转为数字!
注意:逻辑运算中,不要急于将第一个条件之后的++/--提取出来
使用变量错误的情况:*没声明的变量,只要使用就出错!*
var name;
console.log(Name);//程序运行错误错误!会导致程序停止
console.log(name);//undefined1
函数(方法):封装执行一项专门任务的步骤的代码序列
何时定义方法?只要发现一段代码重复使用,就封装为方法
语法:声明
function 方法名(参数列表){
方法体:步骤清单
return 返回值;
}
调用:方法名(参数值列表);
参数:方法内独有的变量。接收传入数据,在方法内处理。参数让方法变灵活!
如何声明方法参数:不用var!
参数何时被创建?只有方法被调用时才自动创建
返回值:方法执行完成后,由方法返回的数据
定义返回值:不用再声明变量,直接用return值!
为什么定义返回值:因为调用方法的人需要明确的返回结果。
返回值主要给调用者使用。
return:本意退出方法!
退出同时,可返回数据!
可以再任何需要的地方,调用方法执行返回值;
带返回值的方法,使用时,等效于直接使用返回值数据。
作用域:一个变量的可用范围!
全局作用域:直接放在全局作用域中的变量,叫全局变量
只要希望所有作用域公用的变量都要声明在全局作用域
window
局部(函数)作用域:声明在方法内部的变量或方法参数的变量都叫局部变量
值传递:将一个变量的值赋值给另一个变量,其实将原变量中的值,复制一份给新变量
。
js中一切赋值都是值传递!
对未声明的变量赋值:js会自动在全局创建该变量!
函数作用域和变量作用域完全一样
函数作用域在调用方法时创建,方法执行完立刻销毁!
PM
问题:
方法参数:依据方法内部的处理逻辑至少需要几个数据才能正常执行。
方法参数和外部定义了了那些变量没有任何关系。
方法参数作用:1、接收外部传入数据,在方法内处理
2、规定调用方法的人必须提供哪些参数!
方法的返回值:根据方法调用者的需要! 如果方法调用者需要明确返回一个结果,就定
义返回值!否则,可以不定义返回值!
何时必须使用变量接住?方法的返回值,后续程序可能反复使用!
鄙视题:
var num = 0;
function f1(num){
var num = 100;
console.log(num);
}
f1();
console.log(num);
//100 0
正课:
自定义函数:
全局函数:ECMAScript定义了标准,由个浏览器厂商已经实现的函数。我们直接调用
!
isNaN(x) parseInt/Float(x)
encodeURI( kword ):将url中的非法字符转为单字节符号——编码
decodeURI( kword ):将encodeURI转后的字符串,转换为原文——解码
unicode编码:每个字符2字节
utf-8:字母、数字单字节,汉字3字节
url规定参数值中,再次出现保留字,就是非法:
保留字:/ ? $ : 等
encodeURIComponent( kword );既能对多字节非法字符编码,又能对单字节非法字符
编码——今后只使用component就够了
何时使用?将数据通过url发送时,都要先编码再发送
decodeURIComponent( kword );对encodeURIComponent()编码的字符串解码。收
到编码后的字符串后,都要先解码,再处理。
eval():专门执行字符串格式代码
程序结构:3种:顺序;分支;循环
程序:IPO
需求:找名词——>程序中的数据
两类:输入数据
输出数据
分析处理流程:
分支结构:程序运行过程中,可以根据不同的条件,执行不同的任务。
分支结构:if...结构:1件事,要么做,要么不做
if...else...结构:2件事,二选一执行
else if结构:多件事,多选一执行
day04
回顾:
方法参数:方法内处理逻辑必须的数据
参数仅限方法内部使用!方法外无法访问方法的参数变量
参数名称自定义!
返回值:调用者是否需要获得方法的执行结果
分支:if结构 1件事 可做可不做
if...else... 2件事 必须二选一
if...else if...[else...] 多件事 多选一执行
正课:
switch...case...多条分支,根据条件判断,选择执行
switch...case...用的是严格相等,不带自动类型转换
语法:swith(表达式){
case 表达式1://如果表达式的值===表达式1的值
代码段1;
case 表达式n:
代码段n;
default://如果表达式的值和都有的case都不相等
默认代码段;
}
运行机制:如果找到与表达式匹配的case,不但执行当前case下的代码,而且之后所有
代码都被触发!
switch(true){
case socre >= 90: console.log("A");
case score >= 80: console.log("B");
case score >= 60: console.log("C");
default: console.log("D");
}
break:退出当前结构;
多条件公用同一套执行逻辑是,不加break。
switch(true){
case socre >= 90: console.log("A");break;
case score >= 80: console.log("B");break;
case score >= 60: console.log("C");break;
default: console.log("D");
}
循环结构:程序反复执行同一套代码段。遇到结束条件,会结束执行。
没有循环结束条件,永远循环呢执行——死循环
循环三要输:
1、循环条件:循环继续执行的条件。一旦循环条件不满足,循环立刻退出!
2、循环变量:用于循环条件中做判断的变量。循环变量都会向着循环退出的趋势变化
(不满足循环条件的趋势)——循环计数器
3、循环体:每次循环要做的事情
while循环:当满足条件时,就继续循环做...事
语法:
var 循环变量;
while(循环条件){
循环体;
迭代变化循环变量;
}
break:退出当前结构
while中何时用break:循环条件不满足之前,希望强行退出循环。
如何使用break?可以放在任何需要退出循环的位置。
随机数:Math.random();0<=n<1
任意min——max之间取随机数
公式:parseInt(Math.random()*(max-min-1)+min)
do-while循环:先执行一次循环体,再判断是否继续!
如果循环条件不满足,循环体至少可以执行一次!
var 循环变量;
do{
循环体;
迭代变化循环变量;
}while(循环条件);
*变量声明提前*:“相同作用域内”,var...不论出现在什么位置,解析时,优先提取到
js开始位置“声明”!
for:完全等效于while循环。
循环变量变化规律固定,循环次数已知、固定
for(声明并初始化循环变量;循环条件;迭代变化循环变量){
循环体
}
continue:跳过本轮循环,继续执行下一轮循环
遇到复杂问题:
先用简单办法做最简单的事情。
从简单办法中找规律!
day05
程序 = 数据结构 + 算法
良好的数据结构,可以极大提高程序的执行效率!
数组:存储:连续存储多个数据的存储空间
使用:相当于多个变量的集合
why?现实中数据都是批量分类管理
何时使用:只要批量管理多个数据,就要用数组保存
如何使用:创建,初始化,访问数组中的数据
创建:数组都是用[]创建出来的。
var arr = [];——>创建了一个数组对象,数组中包含0个元素
var arr = [90, 34, 23];——>创建了一个数组对象,数组中连续存储3个元素
2个不限制:1、不限制元素的个数! 2、不限制元素数据类型
*数组是引用类型的对象*
原始类型:数据保存在变量本地
引用类型:数据不保存在变量本地!保存在“堆”中。
由地址指向实际数据
引用类型特点:可以保存多个数据,而且数据个数随时变化
why?原始类型中只能保存1个值
1个值无法精确描述一个东西
现实中,都是用多个属性共同描述一样东西
对象:凡是存储在堆中的,都是对象!
使用引用类型的对象:使用变量,等效使用对象的地址
使用对象地址,等效于使用对象本身
数组对象支持直接输出数组内容
其他数组创建语法:var arr = new Array(num);
new:要在堆中开辟空间!
Array:ECMAScript标准的内置类型
new Array:在堆中创建一个数组类型的存储区域
(num):初始创建num个元素
var arr = new Array(7);
//[undefined, undefined, undefined, undefined, undefined, undefined, undefined]
undefined输出时,变为一个空字符
var arr = new Array(元素1, 元素2,..., 元素n);
null:一个变量没有指向任何对象
何时使用null:主动释放对象!主动释放的对象不能被找回
null vs undefined:
null专用于主动释放对象!
undefined:专用于自动初始化任何未赋值的变量
垃圾回收:js引擎自动销毁不再被引用的对象!
垃圾回收程序:随js程序运行而后台同时运行
只要对象还有变量引用,就不回收。
访问数组:数组一组变量的集合。
如何获得其中一个变量/数据:下标,数组中唯一标识一个元素的序号。从0开始。最后
一个元素的下标是“元素个数-1”
js内置对象不但封装存储,而且封装常用API
API:已经实现的方法!可以直接调用!
Array API:
1、arr.length属性:数组中元素的个数
访问任意数组的最后一个元素:arr[arr.length - 1]
length属性值,随数组长度变化而自动变化!
js中数组可根据程序需要,“自动扩容”,保证程序正常执行
数组扩容和缩容:都是设置length属性的值
如果length属性值>旧值,会扩容;反之,缩容(截断)
被截断的元素,不能被找到,不会被回收。只能随数组对象一起回收。
固定用法:在任意数组结尾追加一个新元素:arr[arr.length] = 新值;
下午:
栈中的变量 生命周期:和堆完全不同
var a = 5;//全局变量随网页生命周期
function fun(){
var b = 10;
}
fun();//作用域环境栈
/*fun的作用域环境栈 出栈 fun中局部变量,一同消失*/
console.log(b);//refError
结论:局部变量的声明周期和所在方法的作用域环境栈有关
作用域创建,局部变量一同创建
作用域结束,局部变量一同消失
什么是数组遍历:对数组中每个元素执行相同的操作
for(var i = 0; i < arr.length; i++){
arr[i]——>当前元素
}
关联数组:数组下标可以自定义名称!Key/value对
何时使用关联数组:数组元素的内容无法描述自己的意义时,使用关联数组为每个元素
起名
关联数组的length属性作废了!
for in:专门遍历关联数组用的!
for(var key in arr){
//从第一个元素开始,将元素的key赋值给临时变量key
arr[key]——>当前正在遍历的元素的值(value)
}
关联数组直接量定义方式:强调:大括号
{"key1":"value1", "key2":"value2", ...}
冒泡排序:[3, 5, 3,。。]:见array.html
数组常用方法:
x.toString()方法:任何对象都有toString方法
默认用,分割每个元素
将任何对象转为字符串
一般不主动调用,js在需要时自动调用
x.valueOf()方法:同toStrin()
var str = arr.join("分隔符"):将数组转为字符串。但是可自定义分隔符!
用法,将字符拼接为单词或句子 chars.join("");
var newArr = arr.concat(1个元素值, [数组], ...):将参数拆散成单个元素,追加到数组
中。
*不会修改原数组,只能返回新数组对象*
var subArr = arr.slice(start, end + 1);截取数组下标从start开始,到end位置的元素,
生成子数组对象。*含头不含尾*
arr.splice:删除!插入!替换!
删除元素:arr.splice(start, count);
替换元素:arr.splice(start, count, 值1, 值2, ...);
插入元素:arr.splice(start, 0, 值1, 值2, ...)
返回每次删除元素组成的新数组
arr.reverse();颠倒所有数组元素
arr.sort();默认升序排序。默认都转为字符串排序!
day06
手册:JavaScript——>js对象——>js数组——>Array对象参考手册
回顾:
转为字符串:x.toString()——>任何对象都有toString方法
var str = arr.join("分隔符")——>自定义元素分隔符
固定用法:arr.join("");——>将数组中的字符串无缝拼接为单词或字符串
拼接和截取:var newArr = arr.concat(otherArr, 值1, ...)
var subArr = arr.slice(start, end + 1);
复制原始数组中的部分元素,原数组不变
含头不含尾
splice:*直接修改原数组!*返回被删除 的元素
删除:[var removed =] arr.splice(start, count);
替换:[var rrmoved =] arr.splice(start, count, 值1, 值2, ...);
自动调整数组容量,容纳所有修改的新值
插入:[var rrmoved =] arr.splice(start, 0, 值1, 值2, ...);
正课:
排序:arr.sort();默认按字符串升序排列
自定义排序:2步:Step1:定义比较器函数!
什么是比较器函数?定义任意两值比较策略的方法
比如:num1 - num2 > 0 ——> num1 > num2
num1 - num2 < 0 ——> num1 < num2
function compare(a, b){
return a - b;
}//如果返回>0数,a > b; 如果返回<0数,a < b; 如果返回=0数,a = b;
Step2:将比较器函数传递给sort方法!
***如何将方法做参数传递?***
js中方法也是一个对象!方法名就是指向对象的变量名!
function compare(a, b){return a - b;}
//可以定义在使用前后的任何位置
//原因:var声明和function声明自动提前!
相当于:var compare = new Function("a", "b", "return a - b;");
//必须定义在使用之前!原因:仅声明提前,赋值不能提前!
arr.sort(compare);注意!将方法作为对象传递是,仅使用方法名,后不加圆
括号。
降序:颠倒比较结果,可以导致升序变降序
升序:function compareASC(a, b){return a - b;}
颠倒(*-1):function compareDESC(a, b){return b -a;}
栈和队列:
什么是栈?后进先出!(LIFO)栈其实就是数组,只不过用一对方法模拟了栈的操作!
栈:只能从数组一端出栈,入栈。另外一端封闭!
操作栈:
结尾入栈出栈:元素下标始终不变,最后一个元素始终最新
入栈:arr.push(值1, ...);
出栈:var last = arr.pop();
开头入栈出栈:所有元素下标随入栈出栈操作而变化
入栈:arr.unshift(值1, ...);
出栈:var first = arr.shift();
队列:FIFFO
入队列:arr.push(值1, ...);
出队列:var first = arr.shift();
二位数组:数组的元素又是另一个数组对象!
创建二位数组:创建普通数组,完全一样!
只不过将普通元素,换为一个数组对象而已
var arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
arr[3] = [10, 11, 12];
如何访问二位数组中的任意元素:arr[父数组中的下标][子数组中的下标]
何时使用二位数组:数据包含明显上下级关系
内置对象
什么是内置对象?内置对象就是ECMAScript标准中已经定义好的,由浏览器厂商已经
实现的标准对象!
内置对象中封装了专门的数据和操作数据常用的API。
JavaScript中内置对象:
String,Boolean,Number,Array,Date,Math,Error,Function,Object,Global
包装类型
什么是包装类型?专门封装原始类型的数据,并提供对数据常用操作的内置类型。
为什么要用包装类型?让原始类型的数据也可以像引用类型一样,拥有方法和属性。
JavaScript中的包装类型有三个:
String类型,Number类型,Boolean类型
何时使用包装类型?只要用原始类型的数据调用方法或访问属性,js引擎都会自动创建
对应的包装类型对象。
方法调用完,包装类型对象自动释放。
var str = "Hello";
//var strObject = new String(str);
str += "world";
//strObject = null;
String包装类型:*字符串内容,一旦创建,不可改变*
创建原始类型字符串变量:
直接量:var stuName = "Smith";
类型转换:var priceString = String(190.3);
创建引用类型字符串对象:
var carType = new String("BMW528Li");
str.length:返回str字符串中的字符个数
大小写转换:都转小写:str = str.toLowerCase();
都转大写:str = str.toUpperCase();
何时使用:希望大小写一视同仁时,就要先转换,在处理
day07
内置对象:见PPT
包装类型:见PPT
var num = 5.678;//原始类型
//num = new Number(num);//包装类型
console.log(num.toFixed(2));
//num = null;//释放包装类型对象!
创建字符串:原始类型还是包装类型?是否new
var str = "...";//原始类型
var str = String("...");//原始类型,类型转换
**********************************************
var strObj = new String("...");//包装类型对象
转义字符:代替字符串中的非打印字符:
如果字符串内容中包含和语法冲突的特殊字符,可用转为普通字符
比如:console.log(" js是互联网"第一大语言"");
字符串内容一旦创建不能改变!
如果修改,都要创建新字符串,保存新结果,替换旧字符串
var str = "Hello";
var strObj = new String(str);
str = str.toUpperCase();
//strObj = null;
console.log(str);
*规律:所有字符串API,都需要变量接收返回值!*
字符串的字符个数:str.length属性
*字符串类型底层其实都是用字符数组实现的*
比如:str[i]
大小写转换:大小写字母一视同仁时,先转化,再处理
比如:重名验证,重复邮箱,验证码
获取指定位置的字符:var char = str.charAt(index);
获取指定位置字符的unicode编码:var num = str.charCodeAt(index);
优化:*频繁对字符串+=,要用数组代替!不会产生中间对象*
Step1:每个字符串放入数组
Step2:join("")拼接字符元素
今天后要把任何类型变为String,不要用toString,而用+"",效率更高。
字符串三大操作:1.查找关键字! 2.替换关键字 3.获取子字符串
查找关键字:var index = str.indexOf("关键字");
返回关键字所在位置!*如果没找到,返回-1!*
indexOf:懒:只找第一个关键字位置!
蠢:默认只能从位置0开始!
var index = str.indexOf("关键字", from);
from:开始查找的位置,从from开始向后查找
一句话办几件事时,可以把表达式当值用!
var str = "女神说要来,我草草的收拾了房间。结果她又说不来了。我说:我草";
var index = -1;
while((index = str.indexOf("我草", index + 1)) != -1){
console.log("位置" + index + "发现关键字");
}
从最后一个字符,向前找:只要关键字离结尾近,就用last
var index = str.lastIndexOf("关键字", from);
from:开始查找的位置,从from开始向前查找
*返回的index完全相同!字符在数组中的下标是固定的!*
2处修改:index从str.length开始;每次index要-1
2.获取子字符串:以下三个方法省略第二个参数,默认都是取到结尾!
var subStr = str.slice(start, end + 1);
start,end支持正负
var subStr = str.substring(start, end + 1);
用法同slice!唯一差别:不支持负值作为参数!
var subStr = str.substr(start, *count*);
JavaScript——>js字符串——>
下午:
按规律分割字符串:var subs = str.split("分隔符"[, count]);
鄙视题:var str = "no zuo no die";
课堂练习:判断字符的种类:unicode范围:
48-57:0-9 数字字符
65-90:A-Z 大写字母
97-122: a-z 小写字母
19968-40869:汉字
什么是模式匹配:可以设置查找或替换的规则!
何时使用模式匹配:要查找的关键字可能发生有规律的变化。
如何使用模式匹配:1.先定义模式:/关键字/模式
比如:var reg = /no/ig; no是要查找的关键字原文,不加""
i表示忽略大小写! g表示全局查找和替换!
String类型中,提供了专门支持模式匹配的API!
按模式*替换*关键字:str = str.replace(reg, "新值");
默认replace仅替换第一个关键字!
要想全局替换,要在模式中定义“g”
获得*所有*关键字的*内容:var kwords = str.match(reg);
只能取得关键字的内容,无法确定每个关键字的位置!
kwords.length:找到的关键字个数!
*如果未找到,返回null!*
只要有可能返回null!都要先判断 !=null,再处理!
SetupRegexBuddy.exe 全部默认安装
var index = str.search(reg); 和indexOf完全相同!
indexOf不支持模式查找!search其实是indexOf的模式查找版
今后在网页中只要处理字符串的格式,就要用正则表达式
*正则表达式*
什么是正则达表示:字符串中字符出现的规律
何时使用正则表达式?验证字符串格式,查找关键字,替换关键字
比如:银行卡查询密码:6位数字
用户名:字母,数字,_的组合
正则表达式:
选择符号:[所有备选字符]:[去草],必须多选一使用
一个[],只能代表一位字符的规则
[^xxxx]:表示出了xxxx都行!反义。注意必须放在[]中的第一个位置,否则变为普通字
符匹配。
-符号:字符的范围:备选字符是连续的范围!
比如:[0-9] [a-z] [A-Z] [a-zA-Z]//-可以局部使用
汉字范围:[u4e00-u9fa5]
预定义字符集:使用简化的符号,定义常用字符集
比如:[0-9] ——> d [a-zA-Z0-9_] ——> w 空字符 ——> s
如果规则正文中出现特殊符号,用转为原文
.一个人一字符!
数量词:规定前边一个字符出现次数的两次
语法:{min,max}
{num}:固定长度
{min,}:至少min个,多了不限
手机号:+86s1[3578]d{9}
用户名:w{6,8}
day08
回复:
[]:备选字符集,只能多选一。一个[]只能匹配一位字符
比如:我[去草]:我去 我草
[]内:开头^:除了xx都行:[01235689] ——> [^47]
-:表示备选字符的范围 :[a-z] [0-9] [A-Z]
预定义字符集:
[0-9] ——> d
[a-zA-Z_] ——> w
s:空字符:
空格
量词:修饰前一位字符出现的次数
{min,max}:最少min个,最多max个
{min,}:最少min个,最多不限制
{num}:固定num个
比如:验证座机号码:d{3,4}-d{7,8}
正课:
特殊数量词:+ * ?
?:可有可无,对多只能出现一次
比如:我了?去: 我去 我了去 我了个去X 我了了去X
*:可有可无,不限制出现次数
比如:点亮我生命的火*:
点亮我生命的
点亮我生命的火
点亮我生命的火火火
+:至少出现一次!不限制出现次数
比如:点亮我生命的火+:
点亮我生命的火
点亮我生命的火火火
如果正文中出现+?*,都要用转义
():分组:改变模式的匹配顺序
比如:验证身份证号:d{15}(d{2}[0-9xX])?
验证手机号:(+86)?s+1[3578]d{9}
^:整个正则表达式的开头,表示以xxx开始
$:整个正则表达式的结尾,表示以xxx结束
?= 预判,前一个字符之后,必须紧跟xxx
?! 预判,前一个字符之后,必须不能跟xxx
课堂练习:中文姓名:[u4e00-u9fa5]{2,6}
电子邮件:w+@w+([-]w+)*(.w+)+
其中:w+([-]w+)* —— 匹配域名
一个以上的字母,后可跟“-字母”,可有可无
(.w+)+
“.字母”组合至少出现1次
RegExp对象:专门封装一条正则表达式,提供使用正则表达式的常用API
如何使用RegExp对象:1.创建 2.调用API
v如何创建正则表达式对象:ar regExp = /正则表达式/ig;
API:
验证:var boolean = regExp.test("被检查的字符串");
如果验证通过:返回true;否则返回false
验证 vs 查找:
验证要求完整匹配!查找要求部分匹配!
**test方法默认:只要找到就返回true!**
正则表达式前加^,后加$
查找:exec:查找关键字的位置,又能找到关键字的内容
indexOf不支持正则,search支持正则,每次只能找1个
match所有内容,但得不到位置!
var arr = regExp.exec("被查找的内容");
arr[0]:找到的关键字内容
arr.index属性:找到的关键字的位置
exec方法每次只能找1个,但是每次自动修改regExp对象的lastIndex属性!
regExp对象的lastIndex属性:表示下次开始匹配的位置!
查找:仅判断有没有,或者仅查找位置:str.indexOf()
支持正则表达式:str.search()
仅所有关键字的内容:str.match()
即找位置,又找内容:regExp.exec()
/正则表达式/
var regExp = new RegExp("\d{6}", "ig"); 动态创建正则表达式
强调:所有都要改为\
贪婪模式: .+ .*,默认先匹配整个字符串,再缩小范围!
懒惰模式: (.+?) (.*?),从第一个字符开始,向后扩展范围
下午:
从正则表达式匹配的内容中,取一部分:RegExp.$n
n:正则表达式中第n个分组,其实就是第n个圆括号
强调:分组从1开始
必须通过RegExp类型,直接调用$n,不能使用对象!
String对象与正则表达式
str = str.replace(/正则表达式/ig, "替换值");
var arr = str.match(/正则表达式/ig); str.search()
str.split(/正则表达式/);
trim功能:去除字符串开始和结尾的空格。中间空格不去除!
对输入字符串的处理,多数要先清除开头结尾空格,再处理
IE8不支持trim()方法!
自定义trim()方法:
function trim(str){
var regExp = /(^s+)(s+$)/g;
str = str.replace(regExp, "");
return str;
}
String总结:所有的API都无法修改原字符串,都会返回新的字符串
所有StringAPI都需要用变量保存结果!
str.length 字符个数
str = str.toUpperCase()/toLowerCase()
查找关键字:var index = str.indexOf("关键字"[, from])
var arr = str.match(/正则表达式/g);
获得子字符串:var substr = str.slice(start, end + 1);
str.substring(start, end + 1);
str.substr(start, count);
替换:str = str.replace(/正则表达式/g, "替换值");
获得指定位置的字符:var char = str.charAt(index);
str[index];
字符编码转码:var code = str.charCodeAt(index);
var char = String.fromCharCode(code);
RegExp对象总结:
var reg = /正则表达式/ig;
var reg = new RegExp("正则表达式", "ig");
*其中所有的都要改为\!*
验证str中时候包含reg匹配的关键字:
var boolean = reg.test(str);
*强调:完整验证,都需要在正则表达式前加^后加$*
同时查询所有关键字的内容和位置
while((arr= reg.exec(str)) != null){
arr[0] ——> 找到的一个关键
arr.index ——> 当前关键字的位置
}
RegExp.$n:
获得正则表达式中第n个分组(圆括号)匹配的子字符串
Math类型:封装了所有数学计算有关的API
不能new!
Math.PI
Math.round(num) ——> 四合五入取整
Math.ceil(num) ——> 向上取整
Math.floor(num) ——> 向下取整
Math.pow(底数, 幂);
Math.sqrt(num);//平方根!
绝对值:Math.abs(num);
Math.max/min(值1, 值2, 值3, ...);
取数组中的最大值:var max = Math.max.apply(Math, arr);
随机数:Math.random(); 0<=r<1
任意min-max:
Math.floor(Math.random() * (max - min +1) + min);
/*随机生成四位验证码*/
//Step1:数组:所有字母、数字
var codes = [];
for(var i = 48; i <= 57; codes.push(i), i++);
for(var i = 65; i <= 90; codes.push(i), i++);
for(var i = 97; i <= 122; codes.push(i), i++);
function getCode(){
var arr = [];
for(var i = 0; i < 4; i++){//0-61之间取随机数
var index = Math.floor(Math.random()*(60-0+1) + 0);
var char = String.fromCharCode(codes[index]);
arr.push(char);
}
return arr.join("");
}
while(true){
var code = getCode();
var input = prompt("输入验证码:" + code);
var reg = /^[a-zA-Z0-9]{4}$/;
if(reg.test(input)){
if(code.toLowerCase() == input.toLowerCase()){
document.write("登录成功");
break;
}else{
alert("验证码输入错误!");
}
}
}
Date对象:封装一个时间点数据,提供对时间、日期的常用API
创建:var date = new Date();
1.创建Date类型对象; 2.自动获得浏览器当前时间点!
自定义时间:var date = new Date("2015-6-9 16:47");
1.创建Date类型对象; 2.自定义一个具体时间点
*Date对象中,
保存的是从1970年1月1日 0:00:00到现在的毫秒数
var date = new Date();
API:
1.每个分量都有一对get/set方法,获取/设置该分量的值!
2.命名:年/月/日 没有s,时,分,秒 有s
3.取值、赋值:除了每月中的日之外,其余都是从0开始,到-1结束
每月中的日,从1开始,带31结束
月:取值时,要+1修正;赋值是,-1修正
星期://日 一 ............ 六
//0 1 6
日期计算:两日期对象相减,得到毫秒数
时间做+:var nowMs = date.getTime(); 返回时间毫秒数
var nextMs = nowMs + 5*60*1000;
var next = new Date(nextMs);
使用毫秒做计算,不改变原时间对象!需要重新封装时间对象
最大仅能算到“天数”。再算“月数”,无法确定每月天数。
day09
回顾:
Date对象:内部封装了一个毫秒数
创建日期对象:
var date = new Date("2016/7/4");PPT上 new Date("2016-7-4");仅兼容chrome
API
1.每个分量都有一对get/set方法
2.命名:年月日星期 不带s;时分秒带s
3.值范围:月中的日:1-31;其他:0-减1
计算:1.两日期相减,得到毫秒数
2.日期+/- 天小时分秒:用毫秒
3部:1.var ms = date.getTime();
2.ms = ms +/- 毫秒数
3.var newDate = new Date(ms);
正课:
3.任意分量的计算:
先取出分量值,做计算,再set回去!
var now = new Date();
var day = now.getDate();//4
day -= 10;//-6
now.setDate(day);
document.write(now);
date.setXXX();1.自动调整进制
2.*直接修改原日期对象*
如何保留原日期对象?先new出新Date对象,再set
var newDate = new Date(oldDate.getTime());
日期格式转换:
date.toLocaleString();//获得日期和时间的本地格式
date.toLocaleDateString();//仅获得日期部分的本地格式
date.toLocaleTimeString();//仅获得时间部分的本地格式
日期格式转换:都要自定义format(date)方法!
function format(date){
var week = ["日", "一", "二", "三", "四", "五", "六"];
var y = date.getFullYear() + "年";
var m = date.getMonth() + 1 + "月";
var d = date.getDate() + "日";
var w = " 星期" + week[date.getDay()];
var h = date.getHours();
var am = h >= 12 ? " 上午 " : " 下午 ";
h = h > 12 ? h - 12 : h;
h = h < 10 ? "0" + h : "" + h;
var mi = date.getMinutes();
mi = mi < 10 ? "0" + mi : "" + mi;
var s = date.getSeconds();
s = s < 10 ? "0" + s : "" + s;
var str = y + m + d + w + am + h + ":" + mi + ":" + s;
return str;
}
Number类型 API:
num.toFixed(n); 按n位小数四舍五入,*返回一个字符串*!
何时使用:在计算之后,显示结果是,*最后调用toFixed方法*
vs Math.round(num):只能取整 返回一个数Number
num.toString(n):按n进制输出数字的字符串格式
错误处理:
什么是错误处理:导致程序运行停止的运行时异常状态
什么是错误处理:在出现异常状态是,保证程序不停止的机制
如何错误处理:
错误类型:Error类型:所有错误对象的父类型
6种子类型:EvalError,
RangeError:参数超出范围
比如:num.toFixed(n) n<0 抛出RangeError
ReferenceError:引用错误:找不到对象
比如:只要使用未声明的变量时,都要抛出ReferenceError
SyntaxError:语法错误!修改源代码就可以解决!
TypeError:错误的使用了类型和类型的方法!
URIError:URI错误
如何处理错误:
try{
可能出错的代码
}catch(err){只要抛出错误,都要创建一个Error对象
错误处理的代码
1.获得错误信息:err.name 类型
2.根据错误的类型,执行不同的处理
}[finally{可有可无
//程序中使用了大对象!一样要在finally中主动释放
无论是否出错,都必须执行的代码
}]
能用if...else解决的问题,就不用try...catch!
何时使用try...catch?try...catch处理的是无法预料的问题!
主动抛出异常:如何告知方法调用者出错?
thow new Error("自定义的错误信息");
下午:
Function对象:
1.以声明方式定义方法:放前放后无所谓
function 方法名(参数列表){方法体;return 返回值}
2.以创建对象方式定义方法:必须定义在使用之前!
var 方法名 = new Function("参数1", ..., "方法体;return 返回值");
只有声明方式的方法定义才被提前解析!——方法声明提前
重载:方法,根据传入的参数列表不同,执行不同的任务
js支不支持重载:语法不支持,但是可以通过 arguments对象 模拟重载效果
arguments对象:方法对象中保存所有参数的类数组对象
类数组对象(object like array):长的像数组的对象
*方法内,自动创建!直接使用!*
arguments.length:保存变量的个数
arguments[i]:访问传入的第i + 1个变量
3.使用匿名函数赋值的方式定义方法:
匿名函数:没有方法名的函数定义!
var compare = function(a, b){return a-b;}
鄙视题:js中方法定义的方式有几种:3种!
A.function compare(a, b){return a - b}
**************************************************************************
B.var compare = function(a, b){return a - b;}
C.var compare = new Function("a", "b", "return a- b;");
D.var compare = new Function(a, b, return a- b;); X
function isEmpty(str){
if(str === undefined){
return true;
}else if(str == null){
return true;
}else{
var reg = /^s*$/;
return reg.test(str);
}
}
var ltrim = function(str){
var reg = /^s+/;
return str.replace(reg, "");
}
var rtrim = function(str){
var reg = /s+$/;
return str.replace(reg, "");
}
匿名函数2个用途:
1、回调函数:函数何时执行,程序员不需要控制!
由所在环境执行!
比较器!
//var compare = function(a, b){return a - b;} arr.sort(compare);
arr.sort(function(a, b){return a - b;})
事件处理函数:onclick = "calc(12)";
2、自调函数:匿名函数自己调用自己!
当函数不需要重复使用时,使用匿名函数自调。
语法:
(function(参数...){
方法体;
})(参数值...);
在函数定义的位置立即执行!
闭包:函数外使用了不属于自己的局部变量
何时使用闭包?保护局部变量
day10
回顾
1. 闭包
判断闭包3特点:
1. 嵌套函数
2. 内层函数操作了外层函数的局部变量
3. 外层函数将内层函数返回到外部
被全局变量保存住
判断闭包执行结果:
*1. 外层函数被调用几次,就有几个受保护的局部变量副本
2. 反复调用来自一个闭包的函数,受保护的局部变量就变化几次
正课:
1. 面向对象
1. 创建自定义对象
2. ****继承
1. 面向对象:在程序中都是用一个对象来描述现实中一个具体的东西;
现实中的一个东西都包含属性和功能:
属性:描述一个东西特点的变量
功能:东西可以执行操作
什么是对象:封装多个数据的存储空间
什么是自定义对象:封装现实中一个东西的属性和功能的存储空
间。现实中东西的属性会成为对象中的属性变量。现实中的东西的功能,会成为对象中
的方法(函数)
2. 创建自定义对象:3种方式:
1. var obj = {'属性名1':值1,
'属性名2':值2,
...
'功能名1':function()
{...}};
js中一切都是对象!所有对象的底层都是hash数组
属性:如何访问属性:2种:obj.属性名 obj["属性名"]
访问对象中不存在的属性
(访问数组中不存在的下标):不会出错,返回undefined
强行给不存在属性赋值,不报错!js会自动创建同名属性
如何判断某个对象是否包含指定成员:3种
1. obj.hasOwnProperty("成员名");
2. "属性名" in 对象
如果找到,返回true,否则返回false
3. 直接使用 obj.属性名 作为条件:
arr.indexOf !== undefined
如果不包含,返回undefined ————> false
如果包含,返回值或function ————> true
何时省略:判断方法是否存在时,可省略 !==
如果确定属性值一定
不是null, 0, "", NaN 也可省略
方法:如何在方法中,访问当前对象自己:
****this关键字:运行时,指代正在*调用*方法的对象
(.前的对象)
this本质是window下唯一的一个指针,指向当前正在
调用方法的对象
如何在方法内,访问当前对象自己的属性:this.属性名
**在方法内访问当前对象自己的属性,必须用this.属性
名
省略this,默认访问活动对象和window中的变量(闭
包除外)
***this和定义在哪无关!仅和调用时使用的当前对象有
关
***如果无主的调用或复制,默认this都是window!
PM:
正课:
1. ***面向对象:继承
面向对象三大特点:封装 继承 多态
封装:将描述同一个东西的属性和方法,定义在一个对象中
继承:父对象中的属性和方法,子对象可直接使用
多态:同一个对象,在不同情况下,呈现不同的状态
重载:同一方法名,传入参数不同,执行不同的操作
重写:子对象觉得父对象的成员不好用,可自己定义一
个,覆盖父对象的成员
创建对象:3种:
1. 对象直接量
var obj = {"属性名":值, ..., "方法名":function(){...}};
2. var obj = new Object();//创建一个空对象
obj.属性名 = 值;
obj.方法名 = function(){... this.属性名 ...};
3. 利用构造函数*反复*创建*相同结构*的对象
构造函数:描述一类对象结构的特殊函数
2步:
1. 定义构造函数
function 构造函数名|类型名(属性参数1, ...){
this.属性名 = 属性参数1;
//在当前正在创建的对象中创建一个属性名
//赋值为属性参数1的值
...
this.方法名 = function(){
...this.属性名...
}
}
2. 利用构造函数创建对象
var obj = new 构造函数名|类型名(属性值1, ...);
new:1. 创建一个空对象:new obj = {};
2. 利用空对象,调用构造函数
构造函数在空对象中添加属性和
方法
3. 设置新对象的 __proto__ 指向构造函数的
prototype对象
4. 返回新对象的地址
继承:js中一切继承都是用原型对象实现的!
原型对象:每个函数对象都有一个原型对象
构造函数的原型对象负责保存所有子对象共享的成员!
建议:所有子对象共享的方法,都应定义在构造函数的原型对象中。———
—避免重复定义方法对象,浪费内存。
说明:其实所有内置类型的API都是定义在类型.prototype
扩展对象属性:2种扩展:
1. 扩展共有属性:通过构造函数.prototype添加的属性
2. 扩展自有属性:通过某一具体子对象添加属性
判断自有属性或扩展属性:
1. 判断自有属性:obj.hasOwnProperty("属性名");
2. 判断共有属性:"属性名" in obj && !obj.hasOwnProperty("属性名")
在原型对象关系中包含 且 子对
象自己*没有*
删除属性:delete 对象.属性名
*仅能删除当前对象自己的属性,无法删除共有属性
全局变量:3种
var n = 1; window.n = 1; window["n"] = 1;
不能delete 不能delete 能delete
原型链:由各级对象的 __proto__ 逐级继承形成的关系
获得任意对象的父级原型对象:Object.getPrototypeOf(子对象) =》子对象.__proto__
检查对象的父对象:父对象.isPrototypeOf(子对象);
day11
面向对象:封装 继承 多态
1. 创建对象:3种:4种:
1. 直接量:var obj = {"属性名":值, ..., "方法名":function(){}};
__proto__ ————> Object.prototype
2. new关键字:var obj = new Object();
obj.属性名 = 值;
...
obj.方法名 = function(){}
3. 使用构造函数反复创建相同结构的对象:2步
1. 定义构造函数:
function 构造函数名(属性参数, ...){
this.属性名 = 属性参数;
if(!构造函数名.prototype.方法名){
构造函数名.prototype.方法名 =
function(){}
}
}
2. 使用new创建对象同时,调用构造函数:
var obj = new 构造函数名(属性值, ...);
4. Object.create(父对象, {扩展属性的列表对象});
2. this:指代当前正在调用方法的对象
this和定义在哪无关!仅和调用时使用的对象有关!
所有无主(不用var赋值的变量,匿名函数)都是window的
3. 原型,原型链,继承:
原型:保存所有子对象共有属性和方法的对象!
所有函数都有prototype,指向自己的原型对象
所有对象都有 __proto__ ,指向自己父级原型对象
所有原型对象都有constructor,指回原型对应的构造函数
原型链:所有父子级对象间由 __proto__ 形成的多级引用关系
————>*多级*继承
原型相关API:
1. 判断自有属性和共有属性:
1. 判断自有:obj.hasOwnProperty("属性名");
2. 判断原型链上的属性:2种
判断不包含:if(!("属性名" in obj/原型))
if(obj.属性名 === undefined)
if(!obj.属性名)
3. 仅判断共有:必须满足两个条件
!obj.hasOwnProperty("属性名") && obj.属性名
2. 获得任意对象的原型:
obj.__proto__ X
Object.getPrototypeOf(obj)
3. 判断父对象是否在子对象的原型链上
父对象.isPrototypeOf(子对象)
***检测一个对象是不是数组类型:4种:
1. Array.prototype.isPrototypeOf(obj);
2. obj instanceof Array
对象 是不是 构造函数 的实例
3. obj.constructor == Array 仅判断直接父级
4. 利用当前对象,强行调用原始的toString方法
Object.prototype.toString.call(obj) == "[object Array]"
apply(obj)
继承:
为什么要继承:代码重用!节省空间!
1. 直接继承对象:想方设法修改对象的 __proto__ 属性
3种:
1. 仅修改一个对象的 __proto__
Object.setPrototypeOf(子对象, 父对象);
2. 通过修改构造函数的原型对象,实现批量修改后续子对象的继承关系。
构造函数.prototype = 父对象
强调:仅影响之后创建的对象的继承关系
之前创建的对象依然继承旧构造函
数.prototype
3. var obj = 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);