handler发送消息和接收消息异步处理:发送消息的函数即刻返回,另一部分在消息队列中逐一等待被处理
数据类型小写,构造函数首字母大写
不声明就会报错!
函数执行return后,后面的代码不会再执行
Arguments是类数组对象,具备数组相同的访问性质及方法,能由arguments[n]访问对应单个参数的值,并拥有数组长度属性length,arguments存储的是实参
window.onload=function(){} //(延迟加载,先加载dom树,再执行当前函数)
load事件绑定给window对象
JS中的内置对象/内置函数:
Object
Function
Array
Date
Regexp
Math(说内置函数要去掉)
Number
Boolean
String
回调函数:通过函数指针调用的函数
如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数
split:字符串->字符串数组
str.split(字符串/正则表达式,最大返回数组长度)
获取原型对象的方式:
obj.__proto__:获取到的是obj实例的构造函数的原型对象
obj.constructor.prototype
JS异常:try…catch必须成对出现
catch语句在try代码块发生错误时执行
判断正则表达式的方法:test(str);
浅谈javascript的Array.prototype.slice.call
js中的内置对象(详细篇)
JS:动态效果设置
一、JS的由来
最初研发:网景公司(浏览器公司)——livescript
整合:javascript
MySQL:一个关系型数据库管理系统的应用软件,将数据保存在不同的大仓库中,增加了速度,提高了灵活性
所使用的SQL语言(结构化查询语言,编程语言)是用于访问数据库的最常用标准化语言
二、语法
变量的声明,注释
1.标识符、变量的声明(尽量语义化)
1>标识符的声明(相当于属性名)
a.由字母、数字、下划线、$组成,且不能以数字开头
b.建议使用驼峰式命名(第二个单词开始,首字母大写)
var firstnameandlastname='zhangsan'; 不好
var firstNameAndLastName='zhangsan'; 推荐!
c.不能使用关键字和保留字
关键字:在js中具有特殊意义的字符
保留字:未来有可能成为关键字的字符
2>变量的声明
ES5:var(可重复声明)
//先声明,后赋值
var a; //声明一个a变量,但不赋值——值为undefined
a="hello"; //获取a变量并赋值hello
//声明并赋值
var a="hello";
a='hello'; (省去了var就必须给变量赋值)
//同时声明多个变量
var a=2,b=3,c=4;
想让它输出时,console.log(a,b,c);
ES6:也可以使用var声明变量(向下兼容)
let和const(只能声明一次,不能重复声明)
(都是局部变量)
不能变量声明提升(三、4>)
let:声明变量(不是程序员想改,是用户想改)
const:声明常量(一旦声明不可修改)
例子:const person={ //存到计算机里,计算机会自动分配一个引用地址,person所在的地址
name:'lisi',
age
gender
....
}
console.log(person);
结果:Object { name: 'lisi' 。。。}
如果常量值为引用数据类型,只要引用地址不变,可以修改内部属性
例子:const person={
name:'lisi'
};
person.name='tom';
console.log(person);
结果:Object { name: "tom" }
例子:var a=10;
function say(){
console.log(a);
var b=20;
console.log(b);
}
say();
//解析顺序:function say(){};
var a;
a=10;
function say(){
var b;
console.log(a);
b=20;
console.log(b);
};
say();
结果:10
20
例子:let a=20;
function say(){
console.log(a);
}
say();
结果是:20
2.注释
单行注释(可嵌套使用)://内容
多行注释(不能嵌套使用):/*内容*/
三、使用
浏览器端、node环境——都内置了Js解析器
全局对象
1>浏览器端
全局变量window(页面中最大对象)
window只能在浏览器端使用(因为一个文档开一个窗口,一个窗口里包含一个window对象)
window对象:浏览器中打开的窗口
onload方法:遇到function关键字声明一个函数,就会在内存中开辟一个新的内存空间,方便后续调用
当遇到window.onload时,整个页面(dom树)加载完才声明这个函数
当js代码需要获取页面中元素时,如果script标签在元素前面,就需要加
2>node环境
全局变量global(最大对象)
node端无窗口——>无window对象
可写在html的任意位置,但建议写在head中
1.浏览器端(核心js、dom、bom都可运行)
1.嵌入html标签中(script标签 type属性)(直接写js代码)
<script type="text/javascript"></script>
2.外部引入脚本,把js写在另一个文件里(script标签 src属性)——内部代码会被解析器忽略
<script src="./文件名.js"></script>
2.node环境 node.js(只能运行核心js)
node:JS运行环境,相当于封装了js解析器(谷歌V8引擎),能够使js脱离浏览器运行
node安装在云端(node --version检测node版本号,即检测是否安装成功)
两种运行方式:1>repl环境(临时环境,一般做测试时用)
r:read
e:eval 执行
p:print 打印
l:loop 循环(再次从r开始)
node,回车,进入repl环境——在repl环境输入一行代码,读取、执行、打印、循环
例子:xshell里node(下一行光标有>,说明已经进入repl环境中)
>1+1
2 p阶段,把执行结果打印出来
>console.log(1+1);
2 e阶段,输出2
undefined p阶段,打印的返回值
退出:Ctrl D 或 2次Ctrl C
2>node命令:(Linux里的程序,通过第三方软件安装相当于装了一个node程序)——真正项目开发时使用
1)创建:vi 文件名.js
2)执行:node 文件名.js
六、局部变量和全局变量(先声明)
1、全局变量:在整个作用域内都能被访问的变量
没var操作符
2、局部变量:只在声明的代码块内能够被访问
let,const
使用var并声明在函数内部
七、数据类型(6种)
1.五种基本数据类型(简单数据类型)
undefined,null,number,boolean,string
//测试数据类型的方法:typeof (a);
typeof a;
typeof测数据类型(调用typeof的结果):undefined,object(null+object),number,boolean,string,function
例子:var a=Object;
console.log(a);
console.log(typeof a);
结果:function Object() //构造函数Object
function //函数类型
typeof的返回值类型:string
1>undefined:未定义,派生自null
(1)声明一个变量而不赋值——值和数据类型都为undefined
例子:var a;
console.log(a);
console.log(typeof a);
结果:undefined
undefined
(2)直接赋值undefined)——值和数据类型都为undefined
例子:var a=undefined;
console.log(a);
console.log(typeof a);
结果:undefined
undefined
(3)既不声明也不赋值——没值(报错),数据类型为undefined
console.log(a);
结果:没值,报错
console.log(typeof a);
结果:undefined
2>null:空引用数据类型(返回值——null,返回值类型——object)
即将指向堆区,但此时没有指向(还没引用)
var a=null;
console.log(a);
console.log(typeof a);
结果:null
object
null==undefined //true,因为undefined派生自null
null===undefined //false
3>number
小数,整数,011(二进制),0xa(x:十六进制)(o:八进制)
NAN(not a number的缩写)
infinity(无穷大或小,正或负都可)
(1)方法:isNAN(a):a是不是 不是一个数 // 不是数,返回true
var a=10;
console.log("hello"/a);
console.log(typeof ("hello"/a));
结果:NAN
number
(2)方法:isFinite(a):a是否为无穷数 //是无穷数,返回true
console.log(10/0);
console.log(isFinite(10/0));
结果:Infinity
false
4>boolean:结果是true和false
例子:var a=true;
console.log(a);
console.log(typeof a);
结果:true
boolean
5>string:用“”或‘’包裹的字符
字符串拼接:``反引号(忽略格式,可以换行)
例子:console.log('null');
console.log(typeof 'null');
结果:null
string
json(字符串类型):前后台交互常用
接收一个对象:{
“name":"lisi", //属性名一定加引号
"age":10,
}
多个对象:【{
“name”:
"age":
},
{},
{}】
2>null:空引用数据类型
2.引用数据类型(复杂数据类型)——最大父类(js中所有对象的数据类型):object类
object:function
array
date
正则
...//不是基本数据类型,其余的就是object类型里的子类
object是动物
剩下三个是人,猫,狗
每个里面又会有实例对象
object的公有属性和方法:constructor:构造者
//每种子类调用这两种方法的的返回值不一定
toString():调用后的数据类型是string
valueOf():返回——对象本身、变量原始值
八、数据类型转换
基本数据类型和引用数据类型之间基本不做转换(引用地址变了,但原来的不用了还没销毁)
undefined和null是向其他类型转换
1.number
1>Number转换函数:Number(a);
——undefined和非空字符串——>NaN
"hello"、"10l"、"a10":NaN——带字母的字符串不能转换,是NaN
null、false、"":0
true:1
"10":10
"10.3":10.3
"+10":10
2>parseInt(a):
null:NaN(null,object,NAN,number)
true:NaN
false:NaN
"":NaN
"10l":10(10l,string,10,number) //从前到后解析
"10.3":10(直接取整,不是四舍五入)
3>parseFloat(a)
"10.3":10.3
4>一元操作符+或-(-)
+a:相当于调用了Number(a)
-(-)a:相当于调用了--Number(a)
2.boolean
*->boolean
1>Boolean转换函数:Boolean(a)——存在true,不存在false
null:false
undefined:false
0:false
非0:true
"":false
"...":true
2>两次逻辑非!(两次取反)
一个变量连用两次逻辑非,相当于将当前变量转换为boolean类型
!!null——false
3.string
String转换函数:String(a)
toString()
*->String
1>String转换函数:String(a)
直接在变量值之外添加""或''
undefined和null只能通过String转换函数
2>toString方法:toString((num:几进制)
undefined和null没有toString()
——————对象的toString
var obj={
name:'lisi',
age:20
}
console.log(obj.toString());
结果:[object Object] //[数据类型 对象]——object类型的对象
——————函数的toString
function say(){}
console.log(say.toString());
结果:function say(){}
——————数组的toString
var arr1=new Array(); //声明了一个空数组
var arr2=new Array('hello','world');
console.log(arr1.toString());
console.log(arr2.toString());
结果:<empty string> //浏览器端
hello,world
//valueOf方法:返回——对象本身、变量原始值
例子:var obj={
name:'lisi'
};
console.log(obj.valueOf());
function say(){}
console.log(say.valueOf());
结果:Object { name: "lisi" }
function say()
a.toString(2) //先将当前a变量转换成对应的二进制number值,再加“”
true.toString():"true"
10.toString():"10"
例子:var a=true;
console.log(a.toString());
console.log(typeof a.toString());
结果:true
string
九、值传递问题
基本数据类型在值传递时,传递的是值
引用数据类型在值传递时,传递的是引用地址
1>基本数据类型
var a=10;
b=a;
b=b+1;
console.log(a);
console.log(b);
结果:10
11
2>引用数据类型
var obj={
name:'lisi', //字符串类型的属性值加''
age:20,
gender:'men'
}
//var obj在栈区存储,{}在堆区存储
问题:
var obj1={
name:'lisi',
age:20
}
obj2=obj1; //obj2拿到了obj1的内存地址
obj2.name='terry'; //修改obj2的name,实际上修改的是obj1的name//不管obj1还是obj2修改的是同一个内存地址
console.log(obj1.name);
console.log(obj2.name);
结果:terry
terry
十、操作符
算数操作符:=,+和+=,-和-=,*和 *=,/和/=,%和%= (赋值,加减乘除,取余)
比较操作符(返回值都是布尔值)(会做数据类型转换):>,>=,<,<=,==和全等操作符
逻辑操作符:&&(逻辑与),||(逻辑或),!(逻辑非)
三目运算符(代码少)、条件分支语句
一元运算符(写在变量前面):+,-,++,–
位运算符:原码、反码、补码
1.算数操作符(至少两个运算符进行加减操作)
=:赋值操作符(从右向左赋值)
var a=10;
1、+和+=
+(a+b):1>number类型,直接相加
2>number+非number(转换为number)
3>undefined null boolean类型(以Number转换函数->number类型)
例子:var a=null;
var b=false;
var sum=a+b;
console.log(sum);
结果:0
对象调用toString方法,返回[object Object]
var obj={};
console.log(obj.toString());
结果:[object Object] //object类型的对象
4>string+将另一个变量转换为string类型,拼接
例子1:"10"+{}=10[object Object]
例子2:10+"10"=1010
5>非string类型+object类型
10+{}=10[object Object]
5.1>只重写了toString():调用toString()
例子:var obj={
toString:function(){ //相当于重写父类的toString方法
return 10
}
}
var a=10;
var sum=a+obj; //有自己的toString
console.log(sum);
结果:20
5.2>只重写valueof():调用valueof()
例子:var obj={
valueOf:function(){
return 1
}
}
var a=10;
var sum=a+obj;
console.log(sum);
结果:11
5.3>既重写toString()又重写valueof():调用valueof()
例子:var obj={
toString:function(){
return 10
},
valueOf:function(){
return 1
}
}
var a=10;
var sum=a+obj;
console.log(sum);
结果:11
+=:a+=2;——>a=a+2;
2、-和-=
3、*和*=
4、/ 和/=
5、%和%=
2.比较操作符(6个,返回值均为boolean)(会做数据类型转换)
>:(a>b)
num:num——直接比较
num:非num但不为string——将非number转换为number再比较 (“hello”转不了,比较结果返回false),但'10'可以]
例子:var a=null; //计算时把null转换成number了
var b=10;
console.log(a>b);
console.log(a<b);
结果:false
true
非num:非num——转为number
例子:var a=null;
var b=true;
console.log(a<b);
结果:true
string:string——比较字符编码
例子:var a='a';
var b='b';
console.log(a<b);
结果:true
num:obj——默认情况下调用tostring()
如果只toString(),调用toString()
如果只valueOf(),调用valueOf()
如果既重写了toString,又重写了valueOf,调用valueOf()
<
>=
<=
==:(a==b) ——先数据类型转换,再比较
undefined==null,返回值为true
NaN==NaN,返回值为false //"hello"和"world"可不相等啊
"10"==10,返回true //“10”转换成了10(非number转为number)
===:全等操作符——返回值是true或false
先比较数据类型,数据类型相同,再比较值
数据类型不同,返回false
obj===obj——比较引用地址
例子1:object类型(引用地址相同和不同的比较)
例子1.1:var o1={
name:'lisi'
}
o2=o1;
o2.name='terry';
console.log(o1===o2);
结果:true
例子1.2:var o1={
name:'lisi'
}
var o3={
name:'lisi'
}
console.log(o1===o3); //虽然{}里内容一样,但引用地址不一样
结果:false
3.逻辑操作符
&&:逻辑与(第一个数是false,返回第一个数)
a&&b
结果:返回值要么是a,要么是b
1>如果第一个数为undefined、null、NaN、false、""能够转换为false的值,返回第一个数
2>如果第一个数不是,返回第二个数
例子1:console.log("hello"&&"world");
结果:world
例子2:console.log(""&&"world");
结果:<empty string>
例子3:console.log(null&&"world");
结果:null
||:逻辑或
1>如果第一个数为undefined、null、NaN、false、""能够转换为false的值,返回第二个数
2>如果第一个数不是,返回第一个数
例子1:console.log(null||false);
结果:false
例子2:console.log(“hello”||false);
结果:hello
!:逻辑非(结果一定为boolean类型)
!null
1>用Boolean()转换函数转为boolean类型
2>取反
一个变量连用两次逻辑非,相当于将当前变量转换为boolean类型,相当于直接调用Boolean()转换函数
!!null:false
例子:console.log(Boolean(null));
console.log(!null);
结果:false
true
4.三目运算符(代码少)
1>和2>是等价的
1>三目运算符(代码少)
a>b?console.log(a):console.log(b)
表达式?成立:不成立
例子:var a=10;
var b=20;
a>b?console.log("a大”):console.log("b大”);
结果:b大
2>条件分支语句
if(a>b){
}
else{
}
5.一元运算符(写变量前面)
+:(+a),相当于调用了Number(a)转换函数
例子1:var a=null;
console.log(+a);
结果:0
例子2:var a=undefined;
console.log(+a);
结果:NaN
例子3:var a=true;
console.log(+a);
结果:1
-:-a:-Number(a)
++:
1>a++:a=a+1
先变量操作,后++
2>++a:a=a+1
先++,后变量操作
例子1:var a=10;
console.log(a);
console.log(a++);
console.log(a);
结果:10
10
11
例子2:var a=10;
console.log(a);
console.log(++a);
console.log(a);
结果:10
11
11
--
6.位运算符
(二进制)原码——>反码——>补码(用补码进行操作)——再转为原码
js中32位2进制
...128 64 32 16 8 4 2 1
正数:原码=反码=补码
负数:原码
反码=符号位不变,其他位取反
补码=反码+1
符号位:0表示正数,1表示负数
例子:-3+4:二进制是1
-3:原码:1000 0011
反码:1111 1100 //负数取反码时,符号位不变
1
------------
补码:1111 1101
4:原码=补码:0000 0100
sum:(补码之间做加运算)
1111 1101
0000 0100
-----------
结论的补码:0000 0001(一共九位,超出位数不要了)
& AND 都1——1
| OR 有1——1
^ XOR 只有一个是1——1
~ NOT 反转
<<
>>
>>>
计算机底层对float型数据存储可能会出现一些问题——把float型转换成int型
例子:console.log(0.1+0.2);
console.log((0.1*10+0.2*10)/10);
结果:0.30000000000000004
0.3
十一、条件分支语句
if else语句
switch case语句
1>if(a>b){ //表达式的结果是布尔值,不是布尔值也会转换成布尔值
}
else{
}
if(){
}
else if(){
}
else if(){
}
else{ //最后一个写成else
}
例子:var today=7;
if(today==1){
console.log("星期一");
}
else if(today==2){
console.log("星期二");
}
else if(today==3){
console.log("星期三");
}
else{ //当不满足上面条件时,也不会报错
console.log("星期日");
}
结果:星期日
2>switch case语句
switch(变量/表达式){ ()里和下一行的key==比较
case key:语句;break; //匹配成功,执行后面语句
case key:语句;break;
default:语句; //上面的都不满足就执行默认代码
//如果写在第一行,一定要加break,写在最后一行可以不加break
}
例子:var today=1;
switch(today){
case 1:console.log(111);break;
case 2:console.log(222);break;
default:console.log('week');
}
结果:111
break:跳出循环体
continue:跳出本次循环,继续进行下一次循环
十二、循环语句
前置、后置条件循环语句,增强for循环(JS特有):for(var key in obj){},(with语句)
循环三要素:初始条件;结束条件;迭代(循环)条件
1>前置条件循环语句(先判断条件)
(1)for(初始条件;结束条件;迭代条件){
循环体
}
死循环:for(;;){}
label语句:标识循环的名称
for循环前面起个名字(名字:for循环)
例子:outer:for(){
inner:for(){}
break outer; //出了这整个循环了
}
(2)初始条件; //初始条件写在外面
while(结束条件){
循环体;
迭代条件;
}
死循环:while(true){}
例子:var i=1;
while(i<10){
console.log(i);
i++;
}
结果(控制台):1
2
3
4
5
6
7
8
9
2>后置条件循环语句
初始条件;
do{
//循环体 //循环体至少执行一次
//迭代条件
}while(结束条件)
3>js特有,打印属性名和属性值(主要用来循环对象)
增强for循环(for in循环)——for(var key in obj)
例子:var obj={
name:'lisi',
age:20,
gender:'men'
}
//{}里有几个变量就循环几次,每次都会把name,age,gender分别赋值给key
for(var key in obj){ //key和obj可变
key: obj中所有属性的属性名
obj[key]: 所有属性的属性值
}
例子:var obj={
name:'lisi',
age:20,
gender:'men'
}
for(var key in obj){
console.log(key);
console.log(obj[key]);
}
结果:name
lisi
age
20
gender
men
with语句:with(作用域){里访问的变量都是obj里的变量} //使用频率低
例子:var obj={
name:'lisi',
age:20,
gender:'men'
}
console.log(obj.name); //可以合并成一句啊
console.log(obj.age);
console.log(obj.gender);
with(obj){
console.log(name);
console.log(age);
console.log(gender);
}
结果:lisi
20
men
例子1:
例子2:内层循环说只要k=3了,连k=3都不打印,直接跳出整个循环——外层循环只经历了一次
例子3:九九乘法表
document.write(内容);——(在document文档中输出)
document.writeln();——到了一行的末尾会自动换行
for(var i=1;i<=9;i++){
for(var k=1;k<=i;k++){
document.write(i+"*"+k+"="+(i*k));
}
}
结果:九九乘法表一行
for(var i=1;i<=9;i++){
for(var k=1;k<=i;k++){
document.write(i+"*"+k+"="+(i*k));
}
document.write("</br>"); //每次内层执行完后/br换行
}
结果:左下位置的九九乘法表
for(var i=1;i<=9;i++){
for(var k=1;k<=i;k++){
document.write(i+"*"+k+"="+(i*k)+" "); //每个式子输出后都有一个空格
}
document.write("</br>");
}
结果:左下位置的九九乘法表(每个式子后有一个位置的空格)
var space=" " //空间
for(var i=1;i<=9;i++){
for(var k=1;k<=i;k++){
var sp; //每个式子输出后空的格数
if(i*k<10){ //个位数空三格
sp=space+space+space;
}
else{ //两位数空一格
sp=space;
}
document.write(i+"*"+k+"="+(i*k)+sp);
}
document.write("</br>");
}
结果:左下位置的九九乘法表(结果:个位数空三格,两位数空一格)
十三、对象(一组属性和方法的集合)
Object{ } //不能操作类,但是能操作类的实例对象
创建实例对象,访问、删除、检测属性,对象序列化,方法
1.创建实例对象
1>对象字面量
var obj={
name:'lisi',
age:20
}
2>构造函数方式
var obj=new Object(); //构造函数的首字母一定大写,一见到new相当于在堆区中新开辟一块内存空间
obj.name='lisi';
obj.age=20;
2.访问属性
访问一个属性:点操作符,属性名是变量/特殊字符
访问多个属性:for(var key in obj){ }
1>点操作符
var obj={
name:'lisi',
age:20
}
obj.name='terry';
console.log(obj.name);
结果:terry
2>属性名是——变量/"特殊字符"——(用[""]访问)
1.变量
2.obj={
'name-first':'lisi', //特殊属性名需加" "
age:20
}
console.log(obj['name-first']);
console.log(obj.age);
console.log(obj);
结果:lisi
20
Object { "name-first": "lisi", age: 20 }
——循环数组对象元素,获取多个属性
//for(var key in obj){}方法
例子:var obj={
name:'lisi',
age:20,
gender:'men'
}
for(var key in obj){
console.log(key);
}
for(var key in obj){
console.log(obj.key); //到obj中找key变量(是变量,不能用.操作符)
}
for(var key in obj){
console.log(typeof key);
console.log(obj[key]);
}
结果:
//第一个for循环结果
name
age
gender
//第二个for循环结果
undefined
undefined
undefined
//第三个for循环结果
string
lisi
string
20
string
men
3.删除属性
delete 想要删除属性的属性名
delete obj.name
delete obj["name"]
例子:var obj={
name:'lisi',
age:20,
gender:'men'
}
console.log(obj);
delete obj.name;
console.log(obj);
结果:Object { name: 'lisi', age: 20, gender: 'men' }
Object { age: 20, gender: 'men' }
4.检测属性(两种)
继承属性/私有属性,私有属性hasOwnProperty(“属性”)
1>继承属性/私有属性——返回true
"name" in obj
例子:var obj={
name:'lisi',
age:20,
gender:'men'
}
console.log('length' in obj); //既不是私有属性,也不是继承属性
console.log('name' in obj); //私有属性
console.log('toString' in obj); //继承属性
结果:false
true
true
2>私有属性,返回true;继承属性,返回false
obj.hasOwnProperty('name')
例子1:var obj={
name:'lisi',
age:20,
gender:'men'
}
console.log(obj.hasOwnProperty('name'));
console.log(obj.hasOwnProperty("toString"));
console.log(obj.hasOwnProperty('length'));
结果:true
false
false
例子2:var obj={
name:'lisi',
age:20,
gender:'men',
toString:function(){ // 重写toString方法
return 10
}
}
console.log(obj.hasOwnProperty('name'));
console.log(obj.hasOwnProperty("toString"));
console.log(obj.hasOwnProperty('length'));
结果:true
true //重写toString方法后,属于自己的属性
false
5.对象序列化
前后台交互主要用json字符串格式——通用
object->json字符串——JSON.stringify(obj)
json字符串->object——JSON.parse(json)
例子: var obj={
name:'lisi',
age:20,
gender:'men'
}
var str=JSON.stringify(obj); //Object {"name":"lisi","age":20,"gender":"men"}
var obj1=JSON.parse(str); //Object { name: 'lisi', age: 20, gender: 'men' } //转回去了,和obj相同
console.log(obj==obj1); //false 转换后内存地址变了
6.方法
静态方法:声明在函数内部,只能函数本身调用
非静态方法:声明在函数的原型对象中,函数的原型、实例对象均可调用
每个对象都有一个构造者(constructor)
每个函数都有一个原型对象(prototype)//写一个函数后,会瞬间开辟出两块内存空间保存一个函数,函数(本身+原型对象)
1>静态方法:
调用:Object.关键字()
Object.assign(obj1,obj2)——对象合并,右边覆盖左边,结果:左边
Object.keys(obj):返回数组类型的所有属性名
Object.values(obj):返回数组类型的所有属性值
Object.defineProperty(obj,'key',{}):定义属性:哪个对象,哪个属性,属性值、属性配置(是否可修改等)
不可重复定义
{}里:直接写参数
{value:属性值是多少
writable:是否可修改 //返回值是布尔类型
enumerable:是否可遍历
configurable:是否可删除/配置}
set/get方法(不能和第一种方式同时使用):set设置属性值,get获取属性值
例子assign:var obj1={
name:'lisi'
}
var obj2={
name:'terry',
age:20
}
var result=Object.assign(obj1,obj2); //Object{name:"terry",age:20}——result、obj1、obj2一个结果
console.log(Object.keys(obj2)); //Array['name','age']
console.log(Object.values(obj2)); //Array["terry",20]
console.log(obj1==result); //true
console.log(obj2==result); //false
例子defineProperty(obj,'属性名',{})
{}里1>直接写参数
例子:var obj={
name:"lisi",
gender:'men',
}
Object.defineProperty(obj,'age',{
value:20,
writable:true,
enumerable:true,
configurable:true
});
console.log(obj.age); //原来的年龄
obj.age=30;
console.log(obj.age); //修改后的年龄
for(var key in obj){
console.log(key); //年龄可被遍历,遍历属性名
}
delete obj.age;
for(var key in obj){
console.log(key); //年龄可被遍历,被删除后,遍历属性名
}
结果:20
30
name
gender
age
name
gender
2>set/get方法(不能和第一种方式同时使用)
Object.defineProperty(obj,'age',{
set:function(v){
this._age=v; //内部设置方式
},
get:function(){ //获取属性过程
return this._age;
}
}
例子:var obj={
name:'lisi'
}
Object.defineProperty(obj,'age',{
set:function(n){
console.log("开始设置age啦----");
this._age=n;
console.log("设置完成啦");
},
get:function(){
console.log('开始获取啦----');
return this._age;
}
})
obj.age=20;
console.log(obj.age);
结果:开始设置age啦----
设置完成啦
开始获取age啦----
20
函数里(静态方法):Object.assign(),Object.keys(),Object.values(),Object.defineProperty(obj,‘key’,{})
属性:prototype,length(形参个数)
调用:Object.关键字()
原型对象里(非静态方法):toString(),valueOf(),mytest()
属性:constructor
原型对象里,1003.toString()或1002.toString()或Object.prototype.toString()
原型对象的构造者:Object.prototype.constructor是Object1001
十四、(object)的常用子类(函数、数组、日期、正则)
(包装器函数、Math对象、前世今生小游戏)
1.函数
创建、调用、参数、内部属性、属性、作为值和返回值的函数
1>创建(函数字面量、函数声明、对象中)
1)函数字面量 var say=function(){}; 表达式可以存储在变量或对象属性里
2)函数声明 function say(){};
3)对象中
var obj={
name:'lisi',
say:function(){}
}
obj.name
obj.say()
obj["say"]()
js解析器优先解析——函数声明(第二种)(遇到函数调用执行)
解析用var操作符声明的变量,但不赋值(遇到赋值代码赋值)
js中没有重载概念,函数名相同,即为重写
例子:function say(a){
console.log('a:',a);
}
function say(a,b){
console.log('a+b',a,b);
}
say(10);
结果:a+b 10 undefined
例子:function say(){
a=10;
}
console.log(a);
say();
结果:报错
2>函数的调用
函数名(实参): //只是让函数执行一遍,相当于window调用
new 函数名(); //在堆区中有新的内存空间出现,相当于new调用,一定返回实例对象Object{ }
——如果不需要新的内存空间,就用第一种方法
//用函数的属性调用——通过call和apply改变函数体内this值的指向
//this写的是谁就永远是谁,不需要再判断了,是this还得再判断一下
函数名.call(this,参数列表)
函数名.apply(this,[参数列表])
例子1:function say(a,b){
console.log(this)
}
new say();
结果:Object{ } //指向new出的内存空间,堆区中新的内存空间就是Object
//测试call()
例子2:function say(a,b){
console.log(this);
console.log(a,b);
}
say.call(this,10,20,30);
结果:Window
10 20
例子3:function say(a,b){
console.log(this);
console.log(a,b);
}
say.call([],10,20,30);
结果:Array[]
10 20
例子4:function say(a,b){
console.log(this);
console.log(a,b);
}
say.call({name:'lisi'},10,20,30);
结果:Object { name: "lisi" }
10 20
//测试apply()
例子:function say(a,b){
console.log(this);
console.log(a,b);
}
say.apply({},[1,2,3,4]);
结果:Object { }
1 2
3>函数的参数
形式参数:函数需要的参数
实际参数:实际调用时传递的参数
var say=function(形参){}
function say(形参){}
say(实参);
形参和实参的个数可以不一致,且数据类型不限
1、有几个形参,就声明几个形参;
2、有几个实参,就给arguments就赋几个实参
3、将arguments里的数组元素全部赋给形参,如果没那么多形参,就放在arguments里内部保存着
function say(a,b,c){
//内部做的操作
//var a;var b;var c;
//10给a;20给b
console.log(a,b,c);
}
say(10,20);
结果:10 20 undefined
4>函数的内部属性(arguments的length和callee,this)(每个函数都有自己的arguments和this)
arguments:类数组对象,保存实参
arguments[下标]
arguments的属性——length:返回实参个数
例子:function say(a,b){
console.log(arguments);
console.log(arguments.length);
//var a;var b;
//10给arguments[0],20给arguments[1],30给arguments[2]
//arguments[0]给a,arguments[1]给b
console.log(arguments[2]);
}
say(10,20,30);
结果:Arguments{0:10,1:20,2:30}
3
30
arguments的属性——callee(例子:阶乘):从函数内部 指向当前拥有arguments的函数
例子:计算一个数的阶乘
function jiecheng(num){
if(num<=1){
return 1;
}
else{
return num*jiecheng(num-1); //jiecheng可换成arguments.callee 在函数内部找,留下电话方式了
}
}
var result=jiecheng(3);
console.log(result);
结果:6
例子:计算阶乘的和(1!+2!+3!+...+10!=?)
后面再加:
var sum=0;
for(var i=1;i<=10;i++){
sum+=jiecheng(i)
}
console.log(sum);
this:指向函数赖以生存的环境对象 (简化:this指向对象)
什么时候确定?指向谁?——当前拥有this的函数 被调用时确定//被谁调用就指向谁
对象里的this就在对象里看
//this的指向
say(); //默认是window.say
obj.say(); //obj
new say(); //new
arr[0](); //arr 函数内部的this值指向arr
例子:function say(){
console.log(this);
}
say();
结果:Window //被Window调用,指向Window
当全局声明一个变量时,var a=10; //window.a
console.log(a); //其实是window.a
例子1:var length=10;
function say(){
alert(this.length); //整个代码相当于弹出window.length
}
say(); //被window调用
结果:弹框里是10
例子2:var length=10;
function say(){
length=30;
alert(this.length); //整个代码相当于弹出window.length //值随解析顺序发生变化
}
say();
结果:弹框里是30
例子3:var length=10;
function say(){
alert(this.length); //整个代码相当于弹出obj.length
}
var obj={
length:20,
say:say
}
obj.say();
结果:弹框里是20
例子4:var length=10;
function say(){
alert(this.length);
}
var obj={
length:20,
say:say,
run:function(handler){
handler(); //相当于window.say()
alert(this.length); // 变成了obj.length,obj.length是20
}
}
obj.run(say);
结果:弹框里是10 //只管当前函数是被谁调用的
弹框里是20
例子b:var length=10; //全局声明了一个length属性
function handler(){ //声明一个函数
length=20;
}
function say(){
alert(this.length); //this指向window,相当于window.length是多少
}
say();
handler(); // 执行handler函数时,会全局声明一个length变量
say();
结果:弹框里是10 //两个弹框,因为say函数内才有弹框
弹框里是20
例子c:var length=10; //全局声明了一个length属性
function handler(){ //声明一个函数
length=20;
}
function say(){
alert(this.length);
}
var arr=[say,say,say];
var obj2={
length:40,
handler:function(){
alert(this.length);
}
}
var obj={
length:30,
say:say,
handler:function(h,o){
h();
o.handler();
}
}
obj.handler(say,obj2);
结果:弹框里是10
弹框里是40
例子d:var length=10;
function say(){
alert(this.length);
}
new say(); //this指向新创建的内存空间
结果:弹框里是undefined
例子e:var length=10;
function say(){
alert(this.length); //相当于arr.length
}
var arr=[say,say,say]; //arr.length是数组长度是多少,是3
arr[0](); //say(); 相当于arr.say();
结果:弹框里是3
5>函数的属性(把函数当做一个普通的对象)
prototype,length(形参个数)
prototype:原型对象——存储非静态方法/公有属性和方法
length:say.length——返回形参个数
例子:function say(a,b){
console.log(a,b);
console.log(arguments.length); //实参个数
}
say(10,20,30);
console.log(say.length);
结果:10 20
3
2
6>作为值和返回值的函数
值:function say(){};
var handler=say;
handler(); //相当于say(),调用了第一行的函数
function run(h){ //实参say传给了形参h
h();
}
run(say);
返回值:所有的返回值要使用return关键字——在函数外部想使用局部变量
例子1:function say(){
var a=10;
return a; //根据当前方法的用途设定是否需要
//在函数外使用局部变量,相当于say返回a
}
var result=say(); //声明一个全新的变量去接收say的返回值
console.log(result);
结果:10
例子2:var length=10;
function say(){
return function(){
alert(this.length); //整个代码相当于返回window.length
}
}
var result=say(); //result是函数
result();
结果:弹框里是10
例子3:function say(){
var a=10;
function inner(){
console.log(a);
}
return inner; //返回inner函数
}
var result=say();
result(); //相当于调用say里边的inner函数
结果:10
例子5:链式作用域——先在自己的作用域内找,再逐级向上找
var a=0;
function say(){
var a=10;
function inner(){
var a=20;
console.log(a);
}
return inner;
}
var result=say();
result();
结果:控制台:20
2.数组
创建、访问数组元素、检测数组、数组转换、方法
每个数组元素的数据类型任意,数组长度可动态修改
Array.prototype.slice.call():改变数组的slice方法的作用域——在特定作用域调用slice方法
call()方法的第二个参数:传递给slice的参数(截取数组的起始位置)
1>创建(数组字面量,构造函数)
1)数组字面量
var arr=[]; //空数组
var arr=[null,undefiend,false,"",function(){},{}];
例子:var arr=[];
console.log(arr);
console.log(typeof arr);
结果:Array []
object
2)构造函数(一般用new关键字调用)
var arr=new Array(); //空数组
var arr=new Array("hello",false); //创建数组长度为2的数组,Array [ "hello", false ]
var arr=new Array(10); //创建一个数组长度为10的数组,打印时默认都为undefined
如果是1个number类型的参数,相当于创建一个number长度的数组
其他情况,相当于将参数作为数组元素创建数组
function Array(){
if(arguments.length==1){ //长度=1
if(typeof arguments[0]== 'number'){
//判断这个唯一的参数是不是number类型,右边是字符串类型, 因为==会做数据类型转换
}
else{
//底层:创建一个以1为长度的数组,数组元素为arguments[0]
}
}
else if(argumnets.length==0){
//创建一个以0为长度的数组
}
else if(arguments.length>1){
}
}
2>访问数组元素
每个数组元素都对应一个从0开始的数组下标(属性名)
arr[index]:访问+设置(可以增加数组元素)
arr[index]=10:给arr index位置的数组元素设置值为10
//存在——做替换
//不存在——数组长度扩展到index的长度,再设置值为10
length:改变数组长度——增加/删除数组元素
例子:var arr=["hello",false,null,true];
arr.length=2;
console.log(arr.length);
console.log(arr);
结果:2
Array [ "hello", false ]
3>检测数组:判断arr是否为Array类型
Array.isArray(arr)方法
例子:var arr=["hello",false,null,true]
console.log(Array.isArray(arr));
结果:true
判断arr的构造函数是否为Array
arr.constructor==Array;
4>数组转换(将数组转换成字符串类型)
toString() //每种子类调用toString方法,返回值不一定
//看子类是否重写了父类型的toString,如果重写了就返回子类型的toString返回值
//如果没重写,返回父类型的返回值,为[object Object](对象的toString()返回值)
join("-"); //以什么形式来连接一个数组项
例子:console.log(arr.join('-'));
——————数组的toString
var arr1=new Array(); //声明了一个空数组
var arr2=new Array('hello','world');
console.log(arr1.toString());
console.log(arr2.toString());
结果:<empty string>
hello,world
学习新方法时,参数,返回值(作用是什么)
5>方法——(添删4个,排序2,拼接1 切割2,查找2,迭代5——几乎都是非静态方法
1)添加/删除数组元素
栈方法:pop():删除最后一个数组元素
返回值:删除的数组元素
push(添加的数组元素):添加
返回值:添加后的数组长度
例子pop:var arr=[10,"hello",false,function(){},true,null];
var result=arr.pop();
console.log(result);
结果:null //删除的数组元素是null
例子push:var arr=[10,"hello",false,function(){},true,null];
var result=arr.push(20,{});
console.log(result);
console.log(arr);
结果:8
Array(8) [ 10, "hello", false, arr(),true, null, 20, {} ]
队列方法:shift():删除第一个数组元素
返回值:删除的数组元素
unshift(添加的数组元素):添加
返回值:添加后的数组长度
2)排序:(reverse,sort)——返回在原数组基础上排序后的新数组
reverse:数组反转
sort(无/回调函数):默认数组升序
参数(个数): 0:默认调用toString()后,字符编码排序
1:回调函数sort(function(a,b){ //a和b:每次比较的两个数组元素
if(a>b){ //比较操作符,会做数据类型转换
return 正数:第一个数放后边
return 0:不排序,不比较
}
})
回调函数:根据不同情况,返回不同的值
//降序排列:改符号/返回值
升序排列例子:var arr=[1,4,6,2,9,3,11];
var result=arr.sort(function(a,b){
if(a>b){
return 1;
}
else{
return -1;
}
});
console.log(arr);
console.log(result);
console.log(arr==result);
结果:Array [ 1, 2, 3, 4, 6, 9, 11 ]
Array [ 1, 2, 3, 4, 6, 9, 11 ]
true
例子://随意切换比较参数,得到比较结果
var arr=[{
name:'a',
age:20,
salary:1000
},
{
name:'d',
age:10,
salary:100
},
{
name:'c',
age:33,
salary:800
},
{
name:'b',
age:15,
salary:1500
}];
var result=arr.sort(handler("salary")); //sort的参数是回调函数
function handler(key){ //此时参数是salary
return function(a,b){ //a,b每次比较的两个数组元素
var c=a[key];
var d=b[key];
if(c>d){ //按工资升序排序
return 1
}
else{
return -1
}
}
}
console.log(result);
结果:0: Object { name: "d", age: 10, salary: 100 }
1: Object { name: "c", age: 33, salary: 800 }
2: Object { name: "a", age: 20, salary: 1000 }
3: Object { name: "b", age: 15, salary: 1500 }
3)操作方法(拼接concat,切割slice splice,
查找数组元素indexOf lastIndexOf)——只有splice旧数组变了
concat(想要拼接的数组):数组拼接——返回拼接后的新数组
例子:var arr=[1,2,3,4,5];
var arr1=[10,11,12];
var result=arr.concat(arr,arr1); //在调用的数组后再添加新数组 //改slice()
console.log("原数组:",arr);
console.log("新数组:",result);
结果:原数组:Array(5) [ 1, 2, 3, 4, 5 ]
新数组:Array(8) [ 1, 2, 3, 4, 5, 1, 2, 3, 4, 5,10, 11, 12 ]
slice():数组切割
参数个数:0:返回旧数组
1:当前到末尾(不含)
2:开始到结束(不含)
splice():数组切割——返回切割后(旧数组:剩下的,含content)
参数个数:0:返回空数组
1:
2:begin number(多了也不显示)
3:begin number "content"——新数组:被替换原来的
替换/插入:begin number 'content'
删除number个,在begin插入content
//查找数组元素,通过===进行比较
indexOf(内容):默认从前向后,找到一个满足条件的元素返回
lastIndexOf(内容):默认从后向前
返回值:找到——返回下标
找不到——返回-1
例子:var arr=[1,2,3,4,2,5];
var result1=arr.indexOf(2);
var result2=arr.lastIndexOf(2);
console.log("新数组1:",result1);
console.log("新数组2:",result2);
结果:新数组1: 1
新数组2: 4
4)迭代方法(循环)——有几个数组元素就执行几次
var arr=[11,2,13,4,5];
for(var i=0;i<arr.length;i++){ //底层循环
console.log(arr[i]);
}
//函数的参数都一样
参数:回调函数(数组元素 下标 数组) this:回调函数中this的指向(可选,想让它指向谁就写谁)
every():每个数组元素都满足条件,返回true
some():只要有一个数组元素满足条件,返回true
//返回新数组
map():对每个数组元素进行操作
filter():数组过滤——回调函数里是筛选条件
forEach():相当于对底层for循环进行了封装——无返回值
例子:arr=["yi","er","san","si"];
var result=arr.forEach(function(item,index,arr){
console.log(item,index,arr);},
{});
console.log(result); //undefined 因为forEach无返回值
结果:yi 0 Array(4) [ "yi", "er", "san", "si" ]
er 1 Array(4) [ "yi", "er", "san", "si" ]
san 2 Array(4) [ "yi", "er", "san", "si" ]
si 3 Array(4) [ "yi", "er", "san", "si" ]
例子every:var arr1=[1,2,3,4,5,6,7];
var result=arr1.every(function(item,index,arr){return item>4});
console.log(result);
结果:false //不是每个都大于4
例子map:var arr1=[1,2,3,4,5,6,7];
var result=arr1.map(function(item,index,arr){return item+10});
console.log(result);
结果:Array(7) [ 11, 12, 13, 14, 15, 16, 17 ]
例子filter:var arr1=[1,2,3,4,5,6,7];
var result=arr1.filter(function(item,index,arr){return item>3});
console.log(arr1);
console.log(result);
结果:Array(7) [ 1, 2, 3, 4, 5, 6, 7 ]
Array(4) [ 4, 5, 6, 7 ]
例子forEach:var arr=["hello","world",20,false];
arr.forEach(function(item,index,arr){console.log(item,index)});
结果:hello 0
world 1
20 2
false 3
//自己写myForEach()须知:声明位置
参数个数、类型
如何循环执行回调函数
回调函数中的this值指向
分析:调用:arr.myForEach(function(item,index,arr){},this);
var arr=[1,2,3,4];
var arr1=[1,2];
//声明在原型对象中
Array.prototype.myForEach=function(){
//只有一个参数,且是函数类型
if(arguments.length==1&&typeof arguments[0]=='function'){
//如何循环执行回调函数
for(var i=0;i<this.length;i++){
arguments[0].call(window,this[i],i,this);
}
}
//有两个参数
else if(arguments.length==2){
//如何循环执行回调函数
for(var i=0;i<this.length,i++){
arguments[0].call(arguments[1],this[i],i,this);
}
}
};
//函数的调用
arr.myForEach(function(item,index,arr){
console.log(item);
console.log(this);}, this);
console.log(this);
console.log(item,index,arr);
---------------用foreach修改数组内元素,需首先判断是基本数据类型还是引用数据类型
什么鬼这是!?不懂!?
用map方法不用考虑这些
//基本数据类型
var arr=[1, 2, 3, 4, 5];
arr.forEach(function(item,index){
//无效
//item=item+1;
//有效
//arr[index]=item+1; //Array(5)[2,3,4,5,6]
})
console.log(arr);
//引用数据类型
var arr = [{}, {}, {}, {}, {}];
arr.forEach(function(item,index){
//item.name='zhangsan'; //每个元素都有name属性
arr[index]=[1,2]; //Array(5)[[1,2][1,2],[1,2],[1,2],[1,2]]
})
console.log(arr);
ES6中:用reduce实现map
没有第二个参数循环会少执行一次!
reduce(function(pre,item,index,arr),this)——参数多了一个pre
pre:上一次回调函数执行的返回值
第一次执行时,this存在,pre就是this
this不存在,pre就是第一个数组元素
直接从第二个数组元素开始执行,循环会少一次
this:指向回调函数的返回值,根据第二个参数是否存在,改变回调函数的参数
例子:var arr=[11,12,13,14,15];
var result=arr.reduce(function(pre,item,index,arr){ //回调函数的第一个参数
console.log(pre,item,index,arr);
return index+10;}, //return作用:下一次pre,result最后值
{}); //回调函数的第二个参数
console.log(result); //最后一次的指数4+10
结果:见下图
分析:第一次执行时,reduce设置了第二个参数空对象,第一次的pre是第二个参数空对象
第一次执行时,reduce没第二个参数时,pre为数组第一个元素11,所以从12开始执行
结果:
reduce的例子:用JS编写,使用一次array的reduce方法,给定一个数组:var a=[1,2,3,4,5,6,7…],请写一个函数可以返回一个数组,形式如下:var b=[[1,2,3,4,5],[6,7,8,9,10]…],即5个一组分割成数组再组成一个更大的数组;最后一个数组如果不足5个,实际剩几个就包含几个,但不得为空
代码:slice方法
var arr=[1,2,3,4,5,6,7];
var newArr=arr.reduce(function(pre,item,index,arr){
var begin=index*5;
var end=begin+5;
var result=arr.slice(begin,end); //result是小数组
if(result.length){
pre.push(result); //只要小数组存在,就给pre大数组
}
return pre; //后来的pre是上一次切割后带有结果的数组
},[]); //第一次的pre是空数组
console.log(newArr);
结果:Array [[1,2,3,4,5],[6,7]]
splice方法:修改原数组了,考虑的东西会更多一些
。。。
。。。
。。。
3.日期(C++,java中都有)——JS中的内置对象
1、创建日期类型:new Date(); //(年,月,日,时,分)可加参数,从0月开始算,0~11月
//字符串形式("年/月/日")或("年-月-日"),无月份问题
例子:var date=new Date();
console.log(date);
结果:现在的时间
2、设置日期
setDay()
setDate()
3、获取日期
new Date().getTime() //返回当前日期的毫秒数
4.正则表达式(C++,java中都有)——JS中的内置(描述字符模式的)对象
表单验证大部分用的是正则表达式——匹配一段字符串
字符串调用字符串方法进行匹配/正则调用正则方法和字符串进行匹配
不用正则表达式,默认只匹配一个(search只能找到一个)
在表达式内容里写:
[]:把里面看做每一个字符进行匹配
[]{1,2}:1~2个字符,贪婪模式下最多放一起的字符
^:不在[]内的任意字符
\w:任何ASCII字符,等价于[a-zA-Z0-9]+_
\W:任何非ASCII字符组成,等价于[^a-zA-Z0-9]
?:等价于{0,1}
+:等价于{1,}
*:等价于{0,} 更多
|:或者
^:匹配字符串的开头,多行检索时,匹配一行的开头
$:匹配字符串的结尾,多行检索时,匹配一行的结尾
两种模式:贪婪模式(默认),非贪婪模式
1.创建表达式
1)字面量 var p=/表达式内容/gi; (g:全局搜索)(i:忽略大小写)
2)构造函数 var p=new RegExp("表达式内容","gi")
例子:var str='hello world Hello HELLO,javascript is very easy than java';
//第一种创建方式
var p=/hello/;
//第二种创建方式
var p=new RegExp("hello","ig");
--------------------------------------------------------
var result=str.search(p); //字符串调用方法,在字符串里找和p匹配的
console.log(result);
结果:0
Array(3) [ "hello", "Hello", "HELLO" ] //如果是match的话
//p里的test方法/esec方法,测试str是否符合正则表达式的规则
var result=p.test(str);
console.log(result);
结果:true
----------包装器函数(可进行基本数据类型的封装)(构造函数)——和转换函数区分
返回首字母大写类型的对象object类型
使用new关键字调用,才能得到实例对象 num=new Number()
Number.prototype.×××(所能调用的方法都在Number.prototype里)
var num=10;
num.toString();
//num->new Number(num)的实例对象中——自动装箱过程,object类型
//new Number(num).×××——实例对象调用实例对象中的属性和方法
//console.log(num); 变成了基本数据类型number类型——自动拆箱过程
第一种:Number()
new Number(); //包装器函数,返回object类型的Object
Number(); //转换函数,返回值类型是number
例子:var num=10;
var a=Number(num);
var b=new Number(num);
console.log(a);
console.log(typeof a);
console.log(b);
console.log(typeof b);
结果:10
number
Number { 10 }
object
Boolean()
String()
String包装器:声明在String.prototype.xxx——研究实例对象的公有方法
用str.×××调用就行
length,concat,slice,substr,substring,toUpperCase,toLowerCase
indexOf,lastIndexOf,trim,search,match,replace,split,charAt,charCodeAt
length:返回字符串长度
例子:var str="hello";
console.log(str.length);
结果:5
concat():字符串拼接
slice():字符串切割
2:begin end end为-1:倒数第一个字符(不包含),-2:倒数第二个字符
substr():字符串切割——不修改原字符串
0:原字符串
2:begin number
例子:var str="hello";
console.log(str.substr());
console.log(str.substr(1,2));
结果:hello
el
substring():字符串切割
0:原字符串
2:begin end(不管负几,改变切割方向,不含末尾)
例子:var str="hello";
var result=str.substring(1,3);
console.log(result);
console.log(str.substring(1,-1));
console.log(str.substring(4,-1));
结果:el
h
hell
toUpperCase():小写—>大写
toLowerCase():大写—>小写
例子:var str="hello";
var result=str.toUpperCase(只要是数字就行);
console.log(result);
例子:HELLO
indexOf()
例子:var str="hello";
var result=str.indexOf('o');
console.log(result);
结果:4
lastIndexOf()
trim():除字符串前后空格(注意是前后的空格)
search("str"/正则表达式):搜索字符串,只匹配一个满足条件的字符——返回下标
例子:var str="hello";
var result=str.search("h");
console.log(result);
结果:0
match(key/正则):匹配字符串——返回匹配字符组成的数组
例子:var str="hello";
var result=str.match('he');
console.log(result);
结果:Array [ "he" ]
replace('old'/正则,'new'):替换字符串
split(""/正则):切割,字符串转数组——返回切割后的新数组
例子:var str="hello world";
var result1=str.split("l"); //把l去掉,根据l进行切割
console.log(result1);
var result2=str.split("o"); //把o去掉,根据o进行切割
console.log(result2);
console.log(str.split("")); //每个字符代表一个数组元素
结果:Array(4) [ "he", "", "o wor", "d" ] //两个l的话是空字符串
Array(3) [ "hell", " w", "rld" ]
Array(11) [ "h", "e", "l", "l", "o", " ", "w", "o", "r", "l","d" ]
charAt():返回指定位置的字符
charCodeAt():返回指定位置的字符编码
1)例子:console.log("a".charCodeAt());
结果:97
2)也可以返回一个字符串中一个字符的编码
var num=10;
console.log(num);
console.log(typeof num);
console.log(num.toString());
//自动装箱 new Number(num);
//调用属性和方法 new Number(num).toString();
//自动拆箱 typeof num:number
console.log(typeof num.toString());
结果:10
number
10
string
----------Math对象,不是构造函数(new Math:错误!)
Math.min():返回一组数的最小值
Math.max():返回一组数的最大值
例子:console.log(Math.min(1,2,3,4,5,6));
结果:1
取整:Math.ceil():向上取整
Math.floor():向下取整(去掉小数点)
Math.round():四舍五入
随机数:Math.random():返回0-1之间的随机数,不包含1
例子1:console.log(Math.random());
例子2:var arr=["hello","world","h",1,2,3];
console.log(arr[Math.floor(Math.random()*6)]); //[]里是数组下标,0~5
结果:随机数组元素
其他:Math.abs():绝对值
sin()
cos()
log()
例子:----------前世今生小游戏
写旧名字数组,里面是对象
获取用户输入的名字 //prompt:显示提示对话框
分情况讨论:2/3~4/大于5,请输入正确的格式
获取新姓
通过新姓获取旧名数组(如果旧名数组存在,如果不存在弹出没有匹配的旧名)
从旧名数组随机选一个
拼起来,弹框弹出
函数——通过姓找名
//firstName:旧姓
//lastName:旧名 lastNames:旧名集合
//nowFirstName:新姓
老师的:
var nameArr=[{
firstName:'王',
lastName:["安石",'昭君','羲之','维']
},{
firstName:'李',
lastName:["白",'世民','元霸','清照']
},{
firstName:'张',
lastName:["三丰",'无忌','飞','良']
},{
firstName:'欧阳',
lastName:["修",'峰','克','娜娜']
}];
//1.获取用户所输入的名字
var nowName=prompt("请输入您的今生姓名:");
//控制台:确认:输入的内容
取消:null
if(nowName){
if(nowName.length<=3){
//2.获取新姓
var nowFirstName=nowName.substr(0,1);
//3.获取旧名数组
var lastNames=findLastNameByFirstName(nowFirstName);
if(lastNames){
//4.随机选一个旧名
var index=Math.floor(Math.random()*lastNames.length);
alert("您前世的姓名为:"+nowFirstName+lastNames[index]);
}
else{
alert("没有匹配您的前世姓名");
}
}
else if(nowName.length>3 && nowName.length<6){
var nowFirstName=nowName.substr(0,2);
var lastNames=findLastNameByFirstName(nowFirstName);
if(lastNames){
var index=Math.floor(Math.random()*lastNames.length);
alert("您前世的姓名为:"+nowFirstName+lastNames[index]);
}
else{
alert("没有匹配您的前世姓名");
}
}
else{ //如果长度大于6
alert("请输入正确格式的姓名");
}
}
function findLastNameByFirstName(firstName){ //通过姓找名函数
newArr=nameArr.filter(function(item,index,nameArr){ //新数组=旧名字库筛选(只剩下合适的)
return item.firstName==firstName}); //如果旧名字库的姓==姓,就返回
return newArr[0].lastName; //新数组里只有一个对象所以是0,返回这个对象里所有的旧名
}
十五、面向对象——实现多个对象的集合
基础模式
工厂模式(创建对象的过程放工厂)
构造函数模式(对象细分)
原型模式(公有属性&方法放在原型对象中)
继承()
借用构造函数(封装)
1.基础模式
每个对象{}都是一个new Object()
var web2101=[{
name:'',
age:20,
gender:'men',
tel:xxxx,
address:'',
专业:xxx
},
{
name:'',
age:20,
gender:'men',
tel:xxxx,
address:'',
专业:xxx
},
{
name:'',
age:20,
gender:'men',
tel:xxxx,
address:'',
专业:xxx
},....];
2.工厂模式
属性名没改,属性值改了
优点:创建对象过程放工厂,不用new Object,只需调用工厂函数(调用时执行,执行时new一个Object)
缺点:对象不能细分;浪费内存(内置函数)
解决2的问题:将共有函数声明在工厂函数外部,在函数内部将指针指向共有函数(缺点:外部其它函数也能调用)
say方法在构造函数外部,也是双向指向的过程
function createStudent(name,age,gender){
var obj=new Object(); //创建一个新的Object类的对象
obj.say=function(){}; //共有的属性
obj.name=name; //=传进来的name属性
obj.age=age;
obj.gender=gender;
return obj;
}
var stu1=createStudent("lisi",20,'men'); //把具体的值给了obj对象
var stu2=createStudent('tom',30,'women');
例子:可以把say方法声明在工厂外部,工厂内的say方法指针指向外部函数
//解决方法:工厂外部:function say(){alert("say----");};
function createStudent(name,age,gender){
var obj=new Object(); //1001 //1002
obj.say=function(){ //1001.say //1002.say
alert("say----"); //解决方法:把say声明在外部后(去掉里面的say):obj.say=say;
}
obj.name=name;
obj.age=age;
obj.gender=gender;
return obj;
}
var stu1=createStudent("lisi",20,"men"); //虽然调用的都是say方法,但是在不同的内存地址
var stu2=createStudent("tom",25,"men");
console.log(stu1);
console.log(stu2);
console.log(stu1.say==stu2.say);
结果:见下图
false(不是同一个引用地址) //解决方法:true
工厂里:obj.clazz="web2101"; //比较的是字符串类型,保存的地址在栈区里
obj.say=function(){}; //引用数据类型,每个函数在堆区中有2个内存空间,stu1和stu2的内存空间(浪费)
stu1.clazz==stu2.clazz; //true
stu1.say==stu2.say; //false
例子的结果:
3.构造函数模式(对象细分)
缺点:公有属性/方法 外置——除了工厂函数可调用,其他也能调用
new Object()
new Array()
new Date()
function Student(name,age,gender){ //Student构造函数
this.name=name; //此时this被new调用,想往new里放属性=向this里放属性
this.age=age;
this.gender=gender; //不用return,通过new关键字创建,会自动将this值指向创建出来的内存空间
} //--------------开头的new不用写,结尾的return不用写
var stu1=new Student('lisi',20,'men');
例子:function Student(name,age,gender){
this.name=name; //传进来的参数
this.age=age;
this.gender=gender;
}
var stu1=new Student("lisi",20,"man");
console.log(stu1);
console.log(stu1.constructor); //细分实例对象的结果
结果:见下图
缺点:
例子:function Student(name,age,gender){
this.name=name; //传进来的参数
this.age=age;
this.gender=gender;
this.say=function(){ //say给了this,this也是new来的
alert("say---");
}
}
var stu1=new Student("lisi",20,"man"); //第一次new有一个新的内存空间,给了function里的this
var stu2=new Student("tom",21,"woman");
stu1.say();
stu2.say();
console.log(stu1.say==stu2.say); //实例对象的构建改成构造函数模式
结果:弹框say---
弹框say---
false //把say放外边才能为true
解决方法:function say(){
alert("say---");
}
function Student(name,age,gender){
this.name=name; //传进来的参数
this.age=age;
this.gender=gender;
this.say=say;
}
var stu1=new Student("lisi",20,"man"); //第一次new有一个新的内存空间,给了function里的this
var stu2=new Student("tom",21,"woman");
stu1.say();
stu2.say();
console.log(stu1.say==stu2.say); //实例对象的构建改成构造函数模式
结果:弹框say---
弹框say---
true //把say放外边才能为true
4.原型模式(公有属性&方法放在原型对象中)
例子:
function Student(name,age,gender){
this.name=name;
this.age=age;
this.gender=gender;
}
Student.prototype.say=function(){ //把say方法声明到了原型对象中
alert("say---");
}
var stu1=new Student("lisi",20,"man");
var stu2=new Student('tom',21,"woman");
stu1.say();
stu2.say();
console.log(stu1.say==stu2.say);
结果:弹框say---
弹框say---
true
例子1:function Student(name,age){
this.name-name;
this.age=age;
}
var stu1=new Student("lisi",20);
console.log(stu1.constructor);
结果:function Student(name, age)
例子2:function Student(name,age){
this.name-name;
this.age=age;
}
Student.prototype.money="money";
Student.prototype.work=function(){
alert("work---");
};
var stu1=new Student("lisi",20);
stu1.work();
console.log(stu1.money);
console.log(stu1.constructor);
结果:弹框work---
money
function Student(name, age)
例子3:function Student(name,age){
this.name=name;
this.age=age;
}
Student.prototype.money="money";
Student.prototype.work=function(){
alert("work---");
};
Student.prototype={
constructor:Student,
enjoy:function(){
alert("enjoy---");
},
color:"red"
}
var stu1=new Student("lisi",20);
console.log(stu1.constructor); //指向Object
结果:function Student(name, age)
5.继承
子类的原型对象指向父类的实例对象
父类的实例对象指向子类的构造函数——使子类的constructor属性指向子类的构造函数
Poor.prototype=new Rich();
Poor.prototype.constructor=Poor;
例子:function Rich(name,age){ //先创建了Rich构造函数
this.name=name;
this.age=age;
}
Rich.prototype.enjoy=function(){ //Rich的原型对象中有enjoy属性
alert("enjoy---");
}
Rich.prototype.money=["card1","card2"," card3"]; //Rich的原型对象中有money属性
var r1=new Rich("terry",20); //实例对象r1
function Poor(name,age,gender){ //声明了Poor构造函数
this.name=name;
this.age=age;
this.gender=gender;
}
Poor.prototype=new Rich(); //----------子类的原型对象指向父类的实例对象
Poor.prototype.constructor=Poor; //----------父类的实例对象指向子类的构造函数
Poor.prototype.work=function(){ //Poor的原型对象中有work属性
alert("work---");
}
var p1=new Poor("lisi",20,"man"); //实例对象p1
//----------------------------------------
console.log(p1.money); //穷人家孩子能不能拿到钱
console.log(p1.constructor); //穷人家孩子的爸爸是谁
console.log(r1.money); //富人家孩子能不能拿到钱
console.log(r1.enjoy); //富人家孩子还能不能有enjoy属性
console.log(r1.constructor);
结果:见下图
6.借用构造函数
同样的代码写两遍最好进行封装——借用父类构造函数
声明Rich和Poor函数时,同样的d代码写了两遍
Rich.call(this,name,age);
Person
Student
Teacher
例子:
function Rich(name,age){
this.name=name;
this.age=age;
}
Rich.prototype.enjoy=function(){
alert("enjoy---");
}
Rich.prototype.money=["card1","card2"," card3"];
var r1=new Rich("terry",20);
function Poor(name,age,gender){
/*this.name=name;
this.age=age;*/
Rich(name,age); //调用new Poor()时传进来的name,age //要看Rich是被谁调用的,被window调用,此时name和age赋给了window
//-----------所以写成Rich.call(this,name,age); //所有的this指向new Poor()里的new
this.gender=gender; //这个this指向new出来的新空间
}
Poor.prototype=new Rich();
Poor.prototype.constructor=Poor;
Poor.prototype.work=function(){
alert("work---");
}
var p1=new Poor("lisi",20,"man"); //调用new Poor() //Poor里的this值指向new
//----------------------------------------
console.log(p1);
结果:Object { gender: "man" } //name和age赋给了window,所以p1里只有gender
结果:Object { name: "lisi", age: 20, gender: "man" }