可看w3school官网、MDN Web网站进行学习
推荐书籍:JavaScript高级程序设计、JavaScript权威指南
JavaScript:
它是一种弱类型脚本语言,可以对浏览器事件做出响应,给页面添加动态效果,增加用户体验。还可以进行表单验证,减轻了服务器的压力。javaScript在客户浏览器运行时,不需要进行编译运行,因为每一个浏览器都会携带一个js编译器。
JavaScript = ECMAScript + Bom + Dom
可参考w3school中javascript学习文档: https://www.w3school.com.cn/js/index.asp
模块一:ECMAScript(JavaScript语法标准):
1.变量
在es5中,使用 var 声明变量。由于js是一种弱类型脚本语言,所以变量的数据类型会随着变量值的改变而改变
例:
var a = 1;
console.log(typeof(a)) //number
a = false;
console.log(typeof(a)) //boolean
//当使用var进行变量声明后,没有进行初始化,那么打印出来的结果就为undefined
var a;
console.log(a) //undefined
2.数据类型
ES5中6种数据类型 + ES6 1种数据类型(Symbol ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。在ES5中对象属性名都是字符串,这容易造成属性名的冲突,所以引入了该数据类型)
其中ES5中六种数据类型可分为两类:基本数据类型 + 引用数据类型
undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)
基本数据类型:
数字 number NaN属于number类(表示 not a number)型
字符串 string
布尔 boolean
空 null
未定义 undefined
引用数据类型:
对象 Object
数组 Array
函数 Function
正则表达式 RegExp
…
3.操作符
a. 算数运算符:+、-、*、/、%
b. 赋值运算符:=、+=、-=、/=、%=
c. 比较运算符:>、>=、<、<=、== 、!= 、 === 、!==
注:== 和 ===是两种不同的等于,通过例子观察:
例:
var a=1;
var b='1';
console.log(typeof(a)); // number
console.log(typeof(b)); // string
console.log(a == b); //true
console.log(a === b); //false
console.log(a !== b); //true
结论:
== :双等,比较的是两个变量的值是否相等
===:三等,先比较两个变量的数据类型是否相等,如果数据类型
相同,那么才会去比较他们的值,否则直接返回false
d. 逻辑运算符:&&、||、!
(1) &&:逻辑与。表示当表达式返回值【两个】都为true时,才为true,否则返回false
(2) ||:逻辑或。表示当两个表达式其中【一个】返回为true,就返回true,否则返回false
(3) !: 逻辑非,取反操作。
e. 三目运算符:表达式一?表达式二:表达式三
解释:当表达式一中返回的值为true,则执行表达式二,否则执行表达式三
例:
var a = 1;
var b = 3;
console.log(a>b ? a : b) ; //3
f. 一元运算符:++、–、+、-(+、- 不是算术运算符中的±含义)
注:+、- 是对变量进行类型转换的
var a = 'hello';
console.log(-a); //NaN
console.log(typeof(-a)); //number
g. 类型运算符: typeof()、instanceof()
注:
typeof() 主要用来检测基本数据类型,如果使用该方法进行引用数据类型监测的时候,返回值并不精确,都是Object。
instanceof 主要用来判断某个对象实例是否属于某个引用数据类型的
isNaN(变量名):可以用来检测一个变量是否不是一个数字,返回一个布尔类型的值。NaN: not a number
var str = 'abc';
console.log(typeof(str)) //string
var arr = new Array();
console.log(typeof(arr)) //Object
console.log(arr instanceof Array) //true
var str = 'hello world';
isNaN(str); // true
var a = 1;
isNaN(a); // false
h. 拼接运算符:+
console.log("hello "+“dear”);
4.基本数据类型之间的转换
1)其他数据类型转换为数字类型(+、-、构造函数 Number())
string --> number
例:
var str = '123';
console.log(typeof(str)); //string
console.log(+str); //123
console.log(typeof(+str)); //number
console.log(typeof( Number(str))); //number
var num = Number( 'hello world');
console.log(num); // NaN
console.log(typeof(num)); // number
boolean --> number
例:
var a = true;
var b = false;
console.log(Number(a)); //1
console.log(Number(b)); //0
null、undefined --> number
例:
var a = null;
var num = +a;
console.log(num); //0
var a = undefined;
var num = +a;
console.log(num); //NaN
parseInt 取整,parseFloat 取浮点数
console.log(parseInt(1.123)); //1
console.log(parseFloat(1.123)); //1.123
2)其他数据类型转换为字符串类型(String()、toString() )(null、undefined不可以调用)
var a = 1;
var str2 = String(a);
var str3 = a.toString();
console.log('str2',typeof(str2)); //string
console.log('str3',typeof(str3)); //string
3)其他数据类型转换为布尔类型(!!、Boolean())
1.数字类型转布尔类型
var a = 1;
var b = 0;
console.log(!!a); //true
console.log(Boolean(a)); //true
console.log(!!b); //fasle
2.字符串类型转布尔类型
var str1 = 'hello';
var str2 = '';
console.log(!!str1); //true
console.log(!!str2); //false
3.null、undefined转布尔类型: 返回值都为false
5.流程控制语句
分支语句(if-else、switch-case)
循环语句(for(){}、while(){}、do-while)
6.对象
所谓万物皆对象,对象它是一种复杂的数据类型,即引用数据类型,在对象中可以定义多个属性和方法。方法是对象上执行的动作,它以函数定义方式存储在属性中。
1).创建对象规则:
(1)在{ }中定义属性和方法;
(2)一个对象当中可以包含多个属性和方法(方法是一个特殊的属性)
(3)属性名和属性值之间使用冒号:分隔
(4)属性与属性之间使用逗号,分隔
(5)如果属性名包含特殊字符(空格),需要使用引号
(6)属性值一般是具体的值(常量),也可以是变量
(7)最后一个属性值后面不需要加逗号
例:
var name = 'xixi';
var obj = {
name:name, //属性值使用外部变量的值
age:22,
gender:'female',
phone:12345678911,
sayHello:function(){
console.log('你好')
},
'hello wolrd':function(){}
}
2).创建对象:
(1)对象字面值
例:
var obj1 = {}
var obj = {
name:'xixi',
gender:'female'
}
(2)Object构造函数
例:
var obj = new Object();
obj.name = 'xixi';
obj.gender = 'female';
3).访问对象中定义的的属性和方法:
(1)点访问符 .
console.log(obj.gender); //female
(2)中括号访问符 [ ]
console.log(obj[‘gender’]); //female
(3)访问对象中的方法
注:
使用() 访问对象中的方法时,是执行方法中的代码,是否有返回值得看是否有return;
不使用() 访问对象中的方法,是返回函数定义
例:
var obj = {
phone:13412741213,
sayHello:function(){
console.log('sayHello');
}
'hello wolrd':function(){
console.log('hello world')
}
}
var res1 = obj.sayHello;
console.log(res1); //[Function: sayHello]
var res2 = obj.sayHello();
console.log(res2); //undefined 在sayHello函数中由于没有return 返回值,所以输出undefined未定义
console.log(obj['hello wolrd']); //[Function: hello world] 访问含特殊字符的属性名
4).this关键字
(1)如果在单独使用时,那么 this 指的是全局对象 [object Window]:
var x = this;
(2)在函数定义中,引用该函数的“拥有者”,函数的拥有者默认绑定 this。在函数中,this 指的是全局对象 [object Window]。
function myFunction() {
return this;
}
(3)调用对象中的函数,this指的是“拥有”该函数的对象obj
var name = 'xx';
var obj = {
name:name,
gender:'female',
sayHello:function(){
console.log(this); //{name:'xx',gender:'female',[Function: sayHello]}
}
}
obj.sayHello();
(4)在 HTML 事件处理函数中,this 指的是接收此事件的 HTML 元素:
5).删除对象属性:
delete 对象.属性名;
delete obj.gender;
console.log(obj); //{ name: ‘xixi’ }
6).序列化、反序列化
JSON 是一种存储和交换数据的语法。
JSON属于文本,我们可以把JavaScript对象转换为文本,发送给服务器,也可以把从服务器收到的JSON转换为JavaScript对象。通常是从web服务器读取数据,然后在页面中显示数据的。
JSON.stringify()、JSON.parse()
a. 序列化:将存储数据在 JavaScript对象,使用JSON.stringify()方法把该对象转换为 JSON,然后将其发送到服务器。
例:
var obj = {
name:'xixi',
gender:'female'
}
var str = JSON.stringify(obj);
console.log(str); // '{"name":"xixi","gender":"female"}'
console.log(typeof(str)); // string
b. 反序列化:将存储数据在 JavaScript对象,使用JSON.stringify()方法把该对象转换为 JSON,然后将其发送到服务器。
例:
var str = '{"name":"xixi","gender":"female"}';
var obj = JSON.parse(str);
console.log(typeof(str)); //string
console.log(obj); //{ name: 'xixi', gender: 'female' }
console.log(typeof(obj)); //object
7).对象遍历
//key表示当前对象的所有属性名,每次从obj中获取一个属性名赋值给key
for(var key in obj){
console.log(key);
console.log(obj[key]); // 打印所有的属性值
}
8).in关键字( prop in obj )
in运算符能够检测左侧操作数(prop)是否是右侧操作数(obj)的成员,左侧操作数是一个字符串,右侧操作数是一个对象
console.log(‘name’ in obj); // true
console.log(‘sayName’ in obj); // false
7.函数
0)函数的作用
能够对代码进行复用,只要定义一次代码,就可以多次使用它。能够多次向同一函数传递不同的参数,以产生不同的结果。
使用函数可以封装具有某些功能的代码,执行特定功能
使用函数封装创建对象的模板(即构造函数)面向对象
1)函数定义
在JavaScript中函数是通过关键字function进行定义
1.使用函数声明:
function sayHello(形参){
函数体
}
2.使用函数表达式:
var 函数名 = function(形参){
函数体
}
3.Function()构造器:
var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);
2)函数调用
函数名(实参);
函数名.call(this,实参列表);
函数名.apply(this,实参数组);
例:
function sayMessage(name,gender){
console.log(name)
console.log(gender)
}
sayMessage('xx','female');
sayMessage.call(this,'xx','female');
sayMessage.apply(this,['xx','female]);
注意:
a. 加()访问和不加()访问的区别
//1.使用()访问方法时,是执行方法中的代码,由于函数中没有return,所有没有返回结果
var res = sayMessage();
console.log(res); //undefined
//2.不使用()访问对象中的方法,是返回函数定义
var res = sayMessage;
console.log(res); //[Function: sayMessage]
b. console.log与return的区别
1.使用console.log的时候,返回的是一个undefined
2.使用return的时候,调用了函数会有返回值
示例1:
function sayHello(){
console.log('hello world');
}
var obj = {
say:sayHello() //由于sayHello函数没有使用return,所以该函数没有返回值
}
console.log(obj.say); // undefined
示例2:
function sayHello(){
return 'hello world';
}
var obj = {
say:sayHello()
}
console.log(obj.say); //hello world
3)函数参数
function add(a,b){
console.log(a); //2
console.log(b); //3
console.log(arguments); //{ '0': 2, '1': 3, '2': 4 }
return a+b;
}
var result = add(2,3,4);
console.log(result); //5
1. 函数接收的参数叫做 形参 (a,b)
2. 函数接收参数的真正所在—arguments 类数组对象
在JavaScript 函数中有一个名为 arguments的内置对象(接收参数的真正所在)。是当前函数接收的所有参数存储的地方
[Arguments] { ‘0’: 2, ‘1’: 3, ‘2’: 4 }
3. this的指向性问题:this的取值与函数的调用方式有关
示例1:
function sayAge(){
console.log(this);
}
var obj1 = {
name:'xx',
sayName:function(){
console.log(this.name);
}
}
var obj2 = {
name:'zhangsan',
sayName:function(){
console.log(this.name);
}
}
sayAge(); // this指向当前global对象
obj1.sayName(); // xx this指向obj1对象
obj2.sayName(); // zhangsan this指向obj2对象
结论:
如果函数使用了 () 调用,那就看一下括号前面是不是函数名,如果是,再看函数名前面有没有对象
有对象,this指向该对象
没有对象 :在nodejs中,this指向global对象 ;在浏览器中,this指向window对象
示例2:
var pig = {
words:'哼哼',
sound:function(){
console.log(this.words);
}
}
var dog = {
words:'汪汪'
}
pig.sound(); // 哼哼
pig.sound.call(dog); // 汪汪
//通过使用call,可以将原本指向pig的this,指向了dog
结论:(更改this指向)
如果通过call、apply来调用,this的指向为用户手动指向的对象
4)函数声明的提升
0. 什么叫提升?
函数的声明和变量的声明会从它们在代码中出现的位置被移动到当前作用域的最上方,进行执行,这个过程叫做提升
1. 变量声明提升
a = 1;
var a;
console.log(a); // 1
提升==>
var a;
a = 1;
console.log(a);
console.log(b); // undefined
var b = 2;
=>
var b;
console.log(b);
b = 2;
2 函数的提升
info();
function info(){
var c = 3;
console.log(c);
}
=>
function info(){
var c = 3;
console.log(c); // 3
}
info();
3. 函数表达式的提升
fun();
var fun = function(){
var d = 4;
console.log(d);
}
=>
var fun;
fun();
fun = function(){
var d = 4;
console.log(d);
}
//会报错fun is not a function
4. 函数优先 : 函数声明和函数表达式都会被提升,但是函数声明是在函数表达式之前被提升,也叫函数优先
var foo = function(){
console.log(2);
}
function foo(){
console.log(1);
}
foo();
=>
function foo(){
console.log(1);
}
var foo;
foo = function(){
console.log(2);
}
foo(); // 2
5)值传递和引用传递
值传递 : (var a=1; var b=a;b++; ) 不会改变a中的值
引用传递 :
var obj2 = obj;
obj2.age++;
console.log(obj); // { name: 'xx', age: 10, gender: 'female' }
console.log(obj2); // { name: 'xx', age: 10, gender: 'female' }
存储:
1) 基本数据类型保存在栈内存当中,它们的值都有固定的大小,通过按置访问
2) 引用数据类型是保存在堆内存中的对象,值的大小不确定,栈内存当中存放的是该对象的访问地址,JavaScript不允许直接访问堆内存中的值,因此操作的实际都是对象的引用
注:堆内存中,同一个值可以被多个引用地址指向,但是同一个引用地址不能同时指向多个堆内存中的值
6)闭包: 指一个函数有权访问另一个函数作用域中的变量,闭包可以让你从内部的函数访问到外部函数中的变量
形式:函数中包含另一个函数
示例:
function fn1(){
var name = 'xx';
function fn2(){ //fn2就是一个闭包
console.log(name); //使用外部函数中声明的变量
}
fn2();
}
fn1();
7)立即执行函数、匿名函数
( function ( 形参 ) { 函数体 } ) ( 实参 );
8.数组
(0) 数组的特点
(1) 数组定义
数组字面量
var arr1 = [];
var arr2 = [1,‘hello world’,null,undefined,function(){},{name:‘xpf’}];
Array构造函数
var arr3 = new Array();
console.log(‘arr3’,arr3); // []
var arr4 = new Array(3,4);
console.log(‘arr4’,arr4); // [3,4]
注:如果传递的是一个数字,则会按照该数字创建指定项数的数组,但是没有内容,也就是只定义了数组的长度
var arr6 = new Array(3);
console.log(‘arr6’,arr6); // arr6 [ < 3 empty items> ] 等同于==> var arr = [ , , , ];
问题:只希望创建一个包含一个数字的数组,该如何实现?
方案1:使用数组字面量去创建 : var arr = [3];
方案2:使用ES6中新增的Array.of()方法
let arr = Array.of(3);
console.log(arr); //[3]
(2) 数组访问
数组名[索引],索引:从0开始
注意:如果指定索引的位置上没有值,返回undefined
var arr = [‘hello’,‘world’,‘xpf’];
console.log(arr[3]); // undefined
(3) 数组的属性
数组也是一个对象,length表示数组长度(即元素个数)
拓展:新增指定数值的项。length = 最后一项的索引index + 1
var arr1 = [‘hello’,‘world’];
arr1[arr1.length] = ‘张三’;
console.log(arr1); //[‘hello’,‘world’,‘你好’];
(4) 数组遍历
(5) 判断是否数组
Array.isArray(name)
拓展:Object.prototype 位于原型继承链的顶端,所以Object是所有类型对象的父类
instanceof 引用数据类型: 判断某一个变量是否某一个构造函数的实例
typeof 基本数据类型
var arr = [1,2,3,4];
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true
(6) 数组API
数组构造函数原型中的方法,数组实例都可以调用
Array.prototype.push() 从后往前添加、删除
Array.prototype.pop()
Array.prototype.shift() 从前往后删除、添加
Array.prototype.unshift()
Array.prototype…
添加、删除数组元素【进行添加、删除会改变原数组】
push( 新增元素 ) 在数组的最后添加元素;返回新增了元素之后的数组的长度
pop() 从数组的最后取出一个元素;返回被删除的元素
unshift(新增元素) 将元素添加到数组的最前面;返回新增了元素之后的新数组的长度
shift() 将数组中第一个元素删除,返回被删除的元素
排序【会改变原数组】
Array.prototype.sort() 默认进行升序排序
示例1:
var arr = [3,2,1,23];
console.log(arr.sort());
//结果:[ 1, 2, 23, 3 ] 结果达不到想要的效果
示例2: 使用比较器函数,也成为匿名函数
arr.sort(比较器函数);
var arr = [3,2,1,7,12,9];
console.log('排序前:',arr);
var result = att.sort(function(a,b){
if(a>b) return 1; //当a>b时返回1,从小到大排序
if(a
数组序列化 【不改变原数组】
序列化:将一个数组转换为字符串
toString() : 将数组转换为字符串,数组中的元素通过逗号连接
var arr = [1,2,3,4];
var result = arr.toString();
console.log(result); // 1,2,3,4
join() : 将数组转换为字符串,可有字符,表示使用什么进行拼接
var arr = [1,2,3,4];
var result1 = arr.join();
var result2 = arr.join('');
var result3 = arr.join(' ');
console.log(result1); // 1,2,3,4
console.log(result2); // 1234
console.log(result3); // 1 2 3 4
JSON.stringify() : 将数组转换为json字符串,返回转换后的json字符串
var arr = [1,2,3,4,5];
var result = JSON.stringify(arr);
console.log('原数组:',arr); // 原数组:[1,2,3,4,5]
console.log(Array.isArray(arr)); // true
console.log(result); // '[1,2,3,4,5]'
console.log(typeof(result)); // string
数组截取方法
Array.prototype.concat() 【不改变原数组】
Array.prototype.slice(); 【不改变原数组】
Array.prototype.splice(); 【改变原数组的值】
a. concat() : 将参数中的数组和使用该方法得数组合并为一个数组
参数:一个或多个数组
返回值:合并后的数组
b. slice() : 从使用了改方法的数组中截取一个子数组
参数:一个或者两个数字
返回值:返回截取到的子数组
一参:如果只传递了一个参数,截取到的就是索引从该位置开始之后所有的项,作为新数组,如果该值超过了原数组的最大索引,返回的将是一个空数组
两参:slice(a,b): a -> 起始位置 ,b -> 结束位置
如果传递的是两个参数,截取子数组的时候,包含起始位置,不包含结束位置
三参或多参是没有任何效果的
c. splice()
splice(begin,delNum,attr3…); 【begin:开始删除的索引位置;delNum:删除的个数;attr3:放到原数组被删除掉数据的位置】
含义:从使用了该方法的数组中删除、新增、修改操作
参数:一个或者多个
返回值:删除的元素组成的新数组
一参:
删除该位置之后的所有元素,被删除的元素组成一个新数组
示例:
var arr1 = [1,2,3,4,5];
var arr2 = arr1.splice(1);
console.log('arr1',arr1); // [1]
console.log('arr2',arr2); // [2,3,4,5]
两参:
删除索引为第一个参数之后,项数为第二个参数数值的元素,被删除的元素组成一个新的数组
示例:
var arr1 = [1,2,3,4,5];
var arr2 = arr1.splice(2,3);
console.log('arr1',arr1); // [1,2]
console.log('arr2',arr2); // [3,4,5]
三参:
删除索引为第一个参数之后,项数为第二个参数数值的元素,被删除的元素组成一个新的数组,同时将第三个参数放到被删除的位置上
示例:
var arr1 = [1,2,3,4,5];
var arr2 = arr1.splice(1,3,9);
console.log('arr1',arr1); // [1,9,5]
console.log('arr2',arr2); // [2,3,4]
5)数组迭代方法
forEach(function(){}) : 遍历当前数组
参数:function(item,index,arr){} : item表示当前元素、index表示当前索引、arr当前数组
每遍历一次,这个匿名函数就会被调用一次,forEach将当前遍历的,作为实参传递给这个匿名函数
every() : 判断一个数组中的所有元素是否都满足给定的条件,只要回调函数有一次的返回值为false,every方法都返回false
参数:function(item,index,arr){}
some() : 判断数组中是否有满足条件的元素,只要回调函数有一次的返回值为true,some方法都返回true
参数:function(item,index,arr){}
filter() : 筛选数组中满足条件的元素(过滤),只要有满足给定条件的元素时,返回这些元素组成的数组
参数:function(item,index,arr){}
var arr = [1,2,3,4,5];
var result = arr.filter(function(item,index){
return item > 3;
});
console.log(result); // [4,5]
map() : 使用给定条件处理数组(映射),返回一个处理后的数组
参数:function(item,index,arr){}
var arr = [1,2,3,4,5];
var result = arr.map(function(item,index){
return item > 3;
});
console.log(result); // [fasle,false,false,true,true]
var arr = [1,2,3,4,5];
var result = arr.map(function(item,index){
return item + 3;
});
console.log(result); // [4,5,6,7,8]
6)类数组对象转换为数组
如果使我们自己创建的类数组对象,想要转换为数组,那么一定要加上迭代器才能转换成功。[Symbol.interator]:Array.prototype[Symbol.interator]
var obj ={
0:'a',
1:'b',
length:2,
[Symbol.interator]:Array.prototype[Symbol.interator]
}
console.log([...obj]); // ['a','b']
9.正则表达式
可看正则表达式内容: https://www.w3school.com.cn/jsref/jsref_obj_regexp.asp
(1) 含义:当搜索文本中的数据时,可以使用搜索模式来描述搜索的内容,也就是说,正则表达式会去查找字符串中符合某个模式的部分
(2) 定义
a.构造函数模式
var reg = new RegExp(‘正则表达式’,‘正则表达式修饰符’);
b.正则表达式字面值
var pattern = /正表达式/正则表达式修饰符;
(3) 正则表达式原型属性
RegExp.prototype.xxx
RegExp.prototype.global 布尔值,表明这个正则表达式是否带有修饰符g
RegExp.prototype.ignoreCase 布尔值,表明这个正则表达式是否带有修饰符i
RegExp.prototype.multiline 布尔值,表明这个正则表达式是否带有修饰符m
RegExp.prototype.source 正则表达式的字符串表示
RegExp.prototype.flags 正则表达式修饰符的字符串表示
修饰符:
i: 执行对大小写不敏感的匹配
m: 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)
g: 执行多行匹配
(4) 正则表达式原型方法
RegExp.prototype.test()
RegExp.prototype.exec()
RegExp.prototype.macth()字符串方法
(5) 正则表达式
a. 字符类
\w 、\s 、\d 、 [0-9] …
b. 分组 : () 代表分组,在正则表达式中用()包裹起来的内容代表了一个分组
var str1 = 'I come from anhui';
var str2 = 'I come from hubei';
var pattern = /I come from (jiangsu|anhui|beijing)/img;
console.log(pattern.test(str1)); // true
console.log(pattern.test(str2)); // false
10.包装器 : 进行基本数据类型之间的转换
基本包装器:Number() String() Boolean()
除此之外:Math() Date() …
问题 :如何将一个字符串转换为数组? ‘hello’ -> [‘h’,‘e’‘l’,‘l’,‘o’]
方法一:for循环
var str = ‘helloworld’;
var result = [];
for(var i=0;i
}
console.log(result); // [‘h’,‘e’,‘l’,‘l’,‘o’,‘w’,‘o’,‘r’,‘l’,‘d’]
方法二:使用String()包装器的方法split()
var str = ‘helloworld’;
var result = str.split(’’);
console.log(result); // [‘h’,‘e’,‘l’,‘l’,‘o’,‘w’,‘o’,‘r’,‘l’,‘d’]
数组转字符串使用join()方法
String.prototype.xxx
length:获取字符串的长度(数量)
charAt(index): 获取指定索引上对应的字符
charCodeAt(index):获取指定索引处的字符编码
indexOf(val): 获取指定字符在字符串中首次出现时的索引,如果该字符不属于字符串,返回-1
问题:数组去重 --> 数组中也有indexOf()方法,可以返回数组中某个指定的元素首次出现时的索引
初步结果:arr.indexOf(arr[i]) != i时,将该元素删除
var arr = [1,2,3,1,2,5];
function norepeat(arr){
for(var i=0;i
split():把字符串分割为字符串数组
…
11.Math对象
Math.ceil() 向上舍入
Math.floor() 向下舍入
Math.round() 四舍五入
Math.random() 会产生一个随机数,0-1之间的小数
12.Date日期对象
实例化日期对象,使用构造函数
var date = new Date();
console.log(date); // 2020-04-27T06:06:51.271Z
此时间表示世界标准时间,我们中国属于东八区,需要加8小时才是我们的时间
Date对象的方法
getDate():返回一个月中的某一天(1-31)
getFullYear():返回一个表示年份的4位数字
getMonth():返回表示月份的数字(0-11),0表示一月,11表示12月,所以在使用该方法时,加一才是真正的月份数
getDay():返回一个星期中的某一天 (0-6),0表示周日,6表示周六
getHours():返回时
getMinutes():返回分
getSeconds():返回秒
getTime():返回一个时间戳,从1970年1月1日至今的毫秒数
toLocaleString():根据本地时间把Date对象转换为字符串,并返回
…
前后端交互日期问题
当出现时间数据时,就会出现前后端日期格式问题,所以需要前后端进行交流去统一日期格式。
问题1. 如何将标准时间转换为正常的时间格式? 2020-04-27 14:57:20
方法一:(原生js)
var date = new Date();
function timeFormat(dateStr){
var year = dateStr.getFullYear(); //获取年份
var month = (dateStr.getMonth() + 1).toString(); //获取月份
var day = dateStr.getDate().toString(); //获取日
var hour = dateStr.getHours().toString(); //获取小时
var minute = dateStr.getMinutes().toString(); //获取分钟
var second = dateStr.getSeconds().toString(); //获取秒
return year+'-'+month+'-'+day+' '+hour+':'+minute+':'+second;
}
var result = timeFormat(date);
console.log(date);
console.log(result,'---');
//可使用补全位数方法:padStart(2,'0') 2位数,不够补0
//var day = dateStr.getDate().toString().padStart(2,'0')
方法二:(第三方库moment.js)
var date = new Date();
var result = moment(date).format('YYYY/MM/DD hh:mm:ss');
console.log(result);
问题2. 如何将时间戳转换为正常时间格式?
var date = new Date();
var timeAll = date.getTime(); //获取时间戳
var result = moment(timeAll).format('YYYY/MM/DD hh:mm:ss'); //使用moment第三方库处理时间格式
console.log(result);
13.高级面向对象
目的:利用一种机制帮我们创建具有特殊功能的对象
引入:之前创建对象的方式,先创建对象obj,再去创建obj2,并且obj2中的属性名与obj一样,再去创建obj3、obj4…
问题:创建多个相似对象的时候会产生很多冗余的代码
---->
为了解决这样的问题,人们开始思考,能不能批量的创建对象?
13.1 .封装/创建对象的过程 【api的本质】
1. 工厂函数模式
提供了一个函数,每调用一次该函数,返回一个对象
示例:
function factory(name,gender){
var obj = {
name:name,
gender:gender,
sayMessage:function(){
console.log(this.name,this.gender)
}
}
return obj;
}
factory('xx','female');
var obj2 = factory('zhangsan','male');
console.log('obj1',obj1);//obj1 { name: 'xpf',gender: 'male',sayMessage: [Function: sayMessage] }
console.log('obj2',obj2);//obj2 { name: 'zhangsan',gender: 'male',sayMessage: [Function: sayMessage] }
obj1.sayMessage(); // xpf male
obj2.sayMessage(); // zhangsan male
需求:上面的代码创建的两个对象都是’人’,现在希望创建两个对象,一个是’人’,另一个是’狗’
var obj1 = factory('xpf','male');
var obj2 = factory('小黑','雄性');
console.log(typeof(obj1)); // object
console.log(typeof(obj2)); // object
问题:创建多个相似对象时,代码冗余的问题
1)、类型无法细分(由于使用了return {},所以创建出来的所有obj实例都是Object类型)
2)、函数会重复的创建,破坏了封装性
创建多个对象的时候,需要多次的调用factory函数,即每调用一次该函数,都会内存中开辟一块属于sayMessage的空间
2. 构造函数模式
系统内置构造函数(自带的api):Object、Array、Date、Math、Number、String、RegExp
自定义构造函数:
js中可以自定义构造函数,从而自定义对象的属性与方法
构造函数的首字母大写
//人的构造函数
function Person(name,gender){
this.name = name;
this.gender = gender;
this.words = function(){
console.log('嘻嘻');
}
}
//创建实例per1,per2
var per1 = new Person('xx','female');
var per2 = new Person('zhangsan','male');
console.log('per1',per1); //Person { name: 'tmx', gender: 'female', words: [Function] }
per1.words(); // 嘻嘻
per2.words(); // 嘻嘻
//狗的构造函数
function Dog(name,gender){
this.name = name;
this.gender = gender;
}
var dog1 = new Dog('小黑','雄性');
console.log('dog1',dog1); //Dog { name: '小黑', gender: '雄性' }
--->
function Dog(name,gender){
var obj = {}
obj.name = name;
obj.gender = gender;
}
现象:
1)、构造函数的首字母大写 --> 规范
2)、没有显式的创建对象
3)、将属性和方法赋值给了this对象
4)、没有return语句
本质:使用new关键字调用构造函数创建对象,实际上隐式执行了如下步骤
1)、创建一个对象
2)、将构造函数的作用域赋值给了这个对象(this指向该对象)
3)、执行构造函数中的代码(新增属性和方法)
4)、返回一个对象
区别:构造函数与普通函数的区别
1、构造函数也是一个普通函数,创建方式与普通函数一样(函数声明),但是构造函数的首字母大写
function Person(){}
function people(){}
2、调用方式不一样
普通函数的调用方式:直接调用 people()
构造函数的调用方式:使用new关键字调用 new Person()
3、返回值不一样
普通函数:因为没有返回值,结果为undefined
function people(){}
var peo = people();
console.log(peo); // undefined
构造函数:会立马创建一个对象,所以说返回值为空对象
function Person(){}
var per = new Person();
console.log(per); // Person {}
解决问题:解决了类型无法细分的问题
问题:函数会重复的创建/破坏了封装性。每个words方法都要在每个实例上重新创建一次,也就是说每次调用构造函数的时候,都会创建一个对象,而对象中又会每次的去创建一个words方法(函数)
3. 构造函数与原型结合的模式(真正解决方案)
属性保存在实例中,方法保存在构造函数的原型中
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
Person.prototype.words = function(){
console.log('哈哈哈');
}
var per1 = new Person('xpf',25,'male');
var per2 = new Person('zhangsan',30,'male');
console.log('per1',per1);
console.log('per2',per2);
per1.words();
per2.words();
console.log(per1.words === per2.words); // true
per1和per2都可以调用构造函数原型中方法words
13.2 .继承
当我们创建一个构造函数的时候,构造函数会获得一个prototype属性,该属性是一个指针,它会指向原型对象,原型对象中也包含一个属性constructor,该属性也是一个指针,指向构造函数,当我们使用该构造函数创建实例的时候,该实例也会获得一个属性[[Prototype]],该属性会指向原型对象
1. 原型链继承 (子构造函数的原型指向父构造函数的实例,子类构造函数原型构造器指向子类)
作用:让一个引用类型继承另一个引用类型的属性和方法
核心代码在子类构造函数声明之前定义:
Person2.prototype = new Person1();
Person2.prototype.constructor = Person2;
示例:
function Person1(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
Person1.prototype.money = function(){
console.log('哈哈哈!没钱 ');
}
var per1 = new Person1('zhangsan',12,'male');
var per2 = new Person1('lisi',10,'female');
console.log(per1);
console.log(per2);
per1.money(); //哈哈哈!没钱
per2.money(); //哈哈哈!没钱
Person2.prototype = new Person1();
Person2.prototype.constructor = Person2;
function Person2(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
var per3 = new Person2('xiaohong',10,'female');
var per4 = new Person2('xiaoming',8,'male');
console.log('per3',per3);
console.log('per4',per4);
per3.money(); //哈哈哈!没钱
2. 借用构造函数(不仅方法可以继承,属性也可以继承)
核心代码:
Person1.call(this,name,age,gender)
示例:
function Person1(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
Person1.prototype.money = function(){
console.log('哈哈哈,我很有钱!');
}
var per1 = new Person1('zhangsan',12,'male');
var per2 = new Person1('lisi',10,'female');
console.log(per1);
console.log(per2);
per1.money();
per2.money();
Person2.prototype = new Person1();
Person2.prototype.constructor = Person2;
function Person2(name,age,gender){
//借用构造函数
Person1.call(this,name,age,gender);
}
var per3 = new Person2('xiaohong',10,'female');
var per4 = new Person2('xiaoming',8,'male');
console.log('per3',per3);
console.log('per4',per4);
per3.money();