对象的特性:es6
1.惟一标识性,即便彻底不同的对象,内存地址也不一样,因此他们不相等正则表达式
2.对象具备状态,同一个对象可能处在不一样状态下数组
3.对象具备行为,即对象的状态可能由于他的行为产生变迁浏览器
Js直到es6以前,有对象的概念,可是没有类的概念。安全
对象的分类:闭包
1.内建对象app
- 用Es标准中定义的对象,在任何的Es的实现中均可以使用(好比:Math,String,Number,Boolean,Function...)dom
2.宿主对象函数
-用Js运行环境提供的对象,目前来说主要是指用浏览器提供的对象(BOM,DOM)(console.log/document.write)工具
3.自定义对象
-开发人本身定义的对象
-建立对象
在对象中保存的值称为属性
对象的属性值能够是任何数据类型,也能够是个函数(删除对象的属性:delete obj.name)
当函数做为对象的属性时,咱们称这个函数为这个对象的方法,调用这个函数就是调用对象的方法,仅仅是名称上的区别
枚举对象中的属性 使用for..in语句(语法:for(var 变量 in 对象)
//对象中有几个属性就会执行几回,每次执行时,会将属性的名字赋值给变量
使用工厂方法建立对象
-经过该方法能够大批量的建立对象
-使用工厂建立的对象,使用的构造函数都是Object,因此致使建立的对象都是Object这个类型,就致使咱们没法区分出多种不一样类型的对象
function creatDog(name,age){
使用构造函数建立对象
-构造函数就是一个普通的函数,建立方式和普通函数没有区别,
-不一样的是构造函数习惯首字母大写
-构造函数和普通函数的区别就是调用方式的不一样,普通函数是直接调用,而构造函数须要使用new关键字来调用
function creatPerson(name,age){
this.name=name;
this.age=age;
this.say=function(){
alert('hello'+name);
}
}
var obj=new creatPerson("Jeo",23);
var obj2=new creatPerson("Rose",14);
obj.say();
构造函数的执行流程:
1.当即建立一个新的对象
2.将新建的对象设置为函数中this,在构造函数中可使用this来引用新建的对象
function Person(){
alert(this);
}
var per=new Person();//object,就是新建立的对象:per
3.顺序执行代码
4.将新建对象做为返回值返回
function Person(){
}
var per=Person();
console.log(per);//undefined,做为普通函数调用,没有返回值
var per1=new Person();
console.log(per1);//object
- 使用同一个构造函数建立对象,咱们称为一类对象,将一个构造函数称为一个类
- 将构造函数建立的对象,称为该类的实例
使用instanceof能够检查一个对象是不是一个类(构造函数)的实例
-语法:对象instanceof构造函数(是:true)
全部的对象都是Object的后代
建立一个Person构造函数
- 在Person构造函数中,为每个对象都添加了一个say方法,
- 目前咱们的方法是在构造函数内部执行建立的,也就是构造函数每执行一次就会建立一个新的say方法(即每一个实例的say()都是惟一的
解决方法:
- 将say()方法定义在全局做用域
function creatPerson(name,age){
this.name=name;
this.age=age;
this.say=fun;
}
function fun(){
alert('hello:'+this.name);
}
var obj=new creatPerson("Jeo",23);
var obj2=new creatPerson("Rose",14);
obj.say();
缺点:
-将函数定义在全局做用域,污染了全局做用域的命名空间
-定义在全局做用域中也很不安全
解决方案:
原型prototype
咱们所建立的每个函数,解析器都会向函数中添加一个属性prototype
-若是函数做为普通函数调用prototype没有任何做用
-当函数经过构造函数调用时,它所建立的对象中都有一个隐含的属性
-指向构造函数的原型对象,咱们能够经过__proto__来访问该属性
-原型对象就至关于一个公共区域,全部同一个类的实例均可以访问到这个原型对象
-咱们能够将对象中共有的内容,统一设置到原型对象中
-当咱们在访问对象的一个属性或方法时,它会事先在对象自身中寻找,若是有则直接使用,若是没有则会去原型对象中寻找,若是找到则直接使用
之后建立构造函数时,能够将这些对象共有的属性和方法,统一添加到构造函数中的原型对象中,这样不用分别为每个对象添加,也不会影响到全局做用域,就可使每一个对象都具备这些属性和方法
function Hello(){
}
Hello.prototype.a="hello";
var hel1=new Hello();
//hel1.a="我是hel1";
console.log(hel1.a);
当程序这样运行时控制台输出 hello
当程序去掉注释时,会输出 “我是hel1”
故修改say()方法,变成原型对象的方法
function creatPerson(name,age){
this.name=name;
this.age=age;
}
creatPerson.prototype.say=function(){
alert("hello:"+this.name);
}
var obj=new creatPerson("Jeo",23);
var obj2=new creatPerson("Rose",14);
obj.say();//hello:Jeo
检查一个对象是否含有某个属性(in),若对象中没有,原型中有则也返回true
检查一个对象是否含有某个属性(hasOwnProperty),只有对象自身含有属性时,才会返回true
function Test(){
}
Test.prototype.name="我是原型中的名字";
var test=new Test();
alert("name" in test);//true
----------------------------------------------
原型对象也是对象,因此它也有原型(原型链)
- 当咱们使用一个对象的属性或方法时,会先在自身中寻找,自身中若是有,则直接使用,若是没有则去原型对象中寻找,若原型对象中有,则使用,若没有则去原型对象的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,若在Object中依然没有找到,则返回undefined
var Person=function(name,age){ this.name=name; this.age=age; } Person.prototype.getAge=function(){ return this.age;} var per=new Person('Jeo',18); console.log(per.getAge());//18
关于原型链中一些结论:
__proto__
指向 Function.prototype
;prototype
指向 instance.__proto__
;(实例的)__proto__
指向 Object.prototype
;prototype
属性;ob.__proto__
, 也就是访问该对象的构造函数的原型 obCtr.prototype
,若仍找不到,会继续查找 obCtr.prototype.__proto__
,像依次查找下去。若在某一刻,找到了该属性,则会马上返回值并中止对原型链的搜索,若找不到,则返回 undefined。
针对上述结论:分别理解这两个代码:
Js中的继承分为两种接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际方法,因为函数没有签名,在ECMAScript中没法实现接口继承,ECMAScript只支持实现继承,并且其实现继承主要是依靠原型链来实现的。
原型链:
是实现继承的主要方法,其基本思想是利用原型让一个引用类型继承另外一个引用类型的属性和方法。其中,每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针
原型继承:经过__proto__并借助prototype来实现
var Person=function(name,age){
this.name=name; this.age=age; } Person.prototype.getAge=function(){ return this.age;} var per=new Person(Jeo,18); console.log(per.getAge());//18
首先这段代码里,per.__proto__指向Person.prototype,经过原型来构造函数,
var Person=function(name,age){ this.name=name; this.age=age; } Person.prototype.getAge=function(){ return this.age;} //var per=new Person(Jeo,18); //console.log(per.getAge());//18 function Work(name,age,job){ Person.call(this,name,age); this.job=job; } //Work.prototype=Person.prototype; (1) Work.prototype=Object.create(Person.prototype);(2)
Work.prototype.constructor=Work;//调整constructor,以避免constuctor错误
var per=new Work('Jeo',18,'doctor'); console.log(per);
咱们发现用这种方法实现了原型链的继承,在f12中调试能够看到以下
执行(1)中代码获得第一个Work的状况,执行(2)获得第二,她们的原型对象是不一样的
垃圾回收
-程序运行过程当中会产生垃圾(这些垃圾积攒过多之后,会致使程序运行的速度过慢,因此咱们须要一个垃圾回收的机制,来处理程序运行过程当中产生的垃圾)
-当一个对象没有任何的变量或属性对它进行引用,此时,咱们将永远没法操做该对象(此对象就好似一个垃圾,这种对象过多会占用大量的内存空间,致使程序运行变慢,因此这种垃圾必须进行清理
- 在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,咱们不须要也不能进行垃圾回收的操做
-咱们须要作的只是将再也不使用的对象设置为null
函数的返回值:
由return返回
自执行函数:
//自执行写法1 (function T(){ alert(1) })() //自执行写法2 var T1=function(){ alert(1) }(); //传值 var para1={a:1;b:2,c:'Ok'} var T1=function(obj){ alert(obj.a) }(para1); //若是不用自执行方式,就得调用 function T(){ alert(1) } T();//调用
数组(Array)
属性:length,constructor,prototype
-数组也是一个对象
-它和咱们普通对象功能相似,也是用来储存一些值的
-不一样的是普通对象是使用字符串做为属性名的,而数组是使用数组来做为索引操做元素
-索引:
从0开始的一个整数就是索引
-数组的存储性能比普通对象要好,在开发中咱们常常食用数组来存储一些数据
//建立数组对象
//使用构造函数建立数组时,也能够同时添加元素,将要添加的元素做为构造函数的参数传递,元素之间用,隔开
var arr=new Array();//var arr=new Array(1,2)
//使用typeof检查一个数组时,会返回Object,读取数组中的元素,语法:arr[0],若是读取不存在的索引,他不会报错而是返回undefined
使用字面量来建立数组:语法[](使用字面量建立数组时,能够在建立时就指定数组中的元素
var arr=[];//var arr=[1,2];
-获取数组的长度(语法:数组.length)
- 修改length:若是修改的length大于原长度,则多出部分会空出来,若是修改length小于原长度,则多出的元素会被删除
- 向数组的最后一个位置添加元素:(语法:数组[数组.length]=值
- 数组中的元素能够是任意的数据类型(也能够是对象,函数)函数也是对象
push():
-该方法能够向数组的末尾添加一个或多个元素,并返回数组的新长度
-能够将要添加的元素做为方法的参数传递,这些元素会自动添加到数组的末尾
pop():
-该方法能够删除并返回数组的最后一个元素,并将删除元素做为返回值返回
unshift():
-向数组的开头添加一个或多个元素,并返回新的数组长度
-向前面插入元素后,其余元素索引会依次调整
shift():
-能够删除数组的第一个元素,并将删除的元素做为返回值返回
Js中提供forEach()方式遍历数组(兼容ie8以上的浏览器)
- 须要函数做为参数,像这种函数,由咱们建立但不禁咱们调用的,咱们称为回调函数,数组有几个元素,函数就会执行几回,每次执行时,浏览器会将遍历的元素以实參形式传递进来,咱们能够来定义形參来读取这些内容
-浏览器会在回调函数中传递三个参数:
-value:当前正在遍历的元素
-index:当前正在遍历的元素的索引
-obj:当前正在遍历的数组(obj)
slice(start,end)
- 从数组中提取出指定元素,不会改变原数组,而是将截取到的元素封装到一个新数组中返回
- 参数:start:截取开始位置的索引,包含开始索引
end:截取结束位置的索引,不包含结束索引
(第二个参数能够不写,此时会截取从开始索引日后的全部元素)
(索引能够传递一个负值,若是传递一个负值,则从后往前计算)-1:倒数第一个;-2:倒数第二个
splice(start,num,args)(删除,添加,替换)
-能够用于删除数组中的指定元素,使用splice()会影响到原数组,会将指定元素从原数组中删除,并将被删除的元素做为返回值返回
-参数:start:开始位置的索引,num:表示删除的数量,args:能够传递一些新的元素,这些元素将会自动插入到开始位置索引前面
数组去重问题: var arr=[1,2,3,2,1,3,4,2,5]; var arr1=arr.sort(); var res=[]; for(var i=0;i<arr1.length;i++){ if(arr1[i]!==arr1[i+1]){ res.push(arr1[i]); } }
------------------------------------------------
concat()
- 能够链接两个或多个数组(元素),将新的数组返回,不会对原数组有影响
Join()
- 该方法能够将数组转换为一个字符串,该方法不会对原数组产生影响,而是将转换后的字符串做为结果返回,在Join()中能够指定一个字符串做为参数,这个字符串会成为数组中元素的链接符,默认为,
reverse()
-该方法用来反转数组,会直接修改原数组
sort()
- 能够用来对数组中的元素排序,会修改原数组,默认会按照Unicode编码排序
(即便对于纯数字的数组,使用sort()排序时,也会按照Unicode编码来排序,因此对于数字进行排序时,可能会获得错误的结果,咱们能够本身来指定排序的规则)
- 咱们能够在sort()添加一个回调函数,来指定排序规则,回调函数中须要定义两个形參,浏览器将会分别使用数组中的元素做为实參去调用回调函数,使用哪一个元素不肯定,但确定是在数组中a必定在b前面
-浏览器根据回调函数的返回值决定元素的顺序
若返回一个大于0的值,则元素会交换,若返回一个小于0的数,则元素位置不变,若返回等于0,则认为两个元素相等,也不交换位置
var arr=[5,7.2,3,1]; arr.sort(function(a,b){//升序排列 /* if(a>b) return 1; if(a<b) return -1 if(a=b) return 0;*/
return a-b; }) alert(arr);
call()和apply()
function fun(){
alert('hell');}
fun.apply();
fun.call();
fun()
这三者执行效果同样
-------------------------------------
function fun(){
alert(this.name);
}
- 这两个方法都是函数对象的方法,须要经过函数对象来调用
- 当对函数调用call()和apply()都会调用函数执行
- 在调用call()和apply()能够将一个对象指定为第一个参数 ,此时这个对象将会成为函数执行时的tihs
- call()方法能够将实參在对象以后依次传递,apply()方法须要将实參封装到一个数组里统一传递
arguments
在调用函数时,浏览器每次都会传递进两个隐含的参数
- 函数上下文对象 this
- 封装实參的对象arguments
- arguments是一个类数组对象,它能够经过索引来操做数据,也能够获取长度
- 在调用函数时,咱们所传递的实參都会在arguments中保存
- arguments.length能够用来获取实參的长度
- 咱们即便不定义形參,也能够经过arguments来使用实參
只不过比较麻烦
arguments[0]:表示第一个实參
arguments[1]:表示第2个实參
- 它里面有一个属性叫作callee
这个属性对应一个函数对象,就是当前正在指向的函数的对象
function fun(){ console.log(arguments instanceof Array);//false console.log(Array.isArray(arguments));//false }
Date对象
- 在Js中使用Date对象来表示一个时间
建立一个Date对象 若是直接使用 构造函数建立一个Date对象,则会封装为当前代码执行的时间 var d=new Date() console.log(d);//Thu Feb 14 2019 13:35:00 GMT+0800 (中国标准时间) 建立一个指定的时间对象 须要在构造函数中传递一个表示时间的字符串做为参数 日期格式 月/日/年 时:分:秒 var d=new Date('12/03/2016 21:21:30') console.log(d);//Sat Dec 03 2016 21:21:30 GMT+0800 (中国标准时间)
Math
-Math和其余对象不一样,它不是一个构造函数
它属于一个工具类不用建立对象,它里面封装了数学运算相关的属性和方法
好比
Math.PI 表示圆周率
console.log(Math.abs(-1)) //1
console.log(Math.ceil(1.2))//Math.ceil对一个数进行向上取整,小数位只要有值就自动进1
console.log(Math.floor(1.9))//Math.floor对一个数进行向下取整,小数位会被舍掉
console.log(Math.round(1.9))//Math.round对一个数进行四舍五入取整
Math.random() 生成一个0-1之间的随机数,(不包含0和1)
// 生成一个0-x之间的随机数
Math.round(Math.random()*x)
//生成一个1-10之间的随机数
Math.round(Math.random()*9+1)
//生成一个2-10之间的随机数
Math.round(Math.random()*8+2)
生成一个x-y之间的随机数(包含x,y)
Math.round(Math.random()*(y-x)+x)
包装类
基本数据类型:String Number Boolean Null Undefined
引用数据类型:Object
在JS中提供了三个包装类,经过这个三个包装类能够将基本数据类型的数据转换为对象
三个包装类:(浏览器底层本身使用)
String():将基本数据类型字符串转化为String对象
Number():将基本数据类型的数字转换为Number对象
Boolean():将基本数据类型的布尔值转换为Boolean对象(对象专程boolean值都是true)
注意:⚠️
- 在实际开发应用中不会使用基本数据的对象,若是使用基本数据类型的对象,在作一些比较时可能会带来一些不可预期的结果
- 方法和属性只能添加给对象,不能添加给基本数据类型
当咱们对一些基本数据类型的值去调用属性和方法时,浏览器会临时使用包装类将其转换为对象,而后再调用属性和方法
建立一个字符串
- 在底层字符串是以字符数组的形式保存的
var str="Hello world" console.log(str.length);//11 console.log(str[0])//H
length属性:获取字符串的长度
charAt():返回字符串中指定位置的字符 根据索引获取指定的字符
str.charAt(9)//l
charCodeAt():返回字符串中指定位置的字符编码(Unicode编码)
fromCharCode():根据字符编码获取字符 调用方式:经过String.fromCharCode()调用
concat():用来链接两个或多个字符串
indexOf():用来检索一个字符串中是否含有指定内容,
-若是字符串中含有该内容,则会返回其第一次出现的索引
-若没有找到指定的内容,则返回-1
-能够指定一个第二个参数,用来指定开始查找的位置
lastIndexOf:
该方法的用法和indexOf()同样,不一样的是indexOf是从前日后找,而lastIndexOf是从后往前找
-能够指定一个第二个参数,用来指定开始查找的位置
slice()
- 能够从字符串中截取指定的内容
- 不会影响原字符串,而是将截取到的内容返回
- 参数:
第一个,开始位置的索引(包括开始位置
第二个,结束位置的索(不包括结束位置)(若是省略第二个参数,则会截取到后面全部
- 也能够传递一个负数做为参数,负数的话是从后面开始计算(-1:倒数第一个,-2:倒数第二个)
substring()
- 能够用来截取一个字符串,和slice()相似
- 不一样的是这个方法不能结束负值,若传递了负值,则默认为0
- 并且还会自动调整参数的位置,若是第二个参数小于第一个,则自动交换
substr()
- 用来截取字符串
- 参数:
1.开始索引的位置
2.第二个为字符串截取的长度
split():
- 能够将一个字符串拆分为一个数组
var str='abc,bcd,efg,def' var result=str.split(','); console.log(result[0]);//result是一个数组,result[0]=abc 逗号就会被舍去
正则表达式:
- 用于定义一些字符串的规则(计算机能够根据正则表达式,来检察一个字符串是否符号规则
- 获取将字符串中符合规则的内容提取出来
/** * 建立正则表达式的对象 语法: var 变量=new RegExp(”正则表达式“,”匹配模式“) 使用typeof检察正则对象,会返回object
test():检察一个字符串是否符合正则表达式的规则
若是符合则返回true,不然返回false
在构造函数中能够传递一个匹配模式做为第二个参数
能够是:
i 忽略大小写
g 全局匹配模式 */ var reg=new RegExp('a','i')//检察字符串中是否含有a console.log(reg);//返回/a/
使用字面量来创造正则表达式(使用字面量来创造正则表达更加简洁,使用构造函数建立正则表达是更灵活
语法: var 变量=/正则表达式/匹配模式
var reg=new RegExp('a','i')//reg=/a/i
建立一个正则表达式,检察一个字符串中是否有a或b
reg=/a|b/ //|表示或者
建立一个正则表达式,检察一个字符串中是否有字母
[]里面的内容也是或的关系 [ab]===a|b [a-z]表示任意小写字母
[A-Z]表示任意大写字母
[A-z]任意字母
检察一个字符串中是否含有abc或者adc或者aec
reg=/a[bde]c/
[^ ]:除了
split()不管是否指定全局,都会全局匹配
- 能够将一个字符串拆分为一个数组
- 方法中能够传递一个正则表达式做为参数,这样方法会根据正则表达式去拆分字符串
var str='12a23jg23o4jg45jn6' var result=str.split(/[A-z]/); console.log(result);// ["12", "23", "", "23", "4", "", "45", "", "6"]
search()即便设置全局匹配也没效果
- 能够搜索字符串中是否含有指定内容
- 若是搜索到指定内容,则会返回第一次出现的索引,若是没有搜索到则返回-1
- 它能够接受一个正则表达式做为参数,而后会根据正则表达式去检索字符串
var str='abc aef bac abe abf' var result=str.search(/ab[A-z]/) console.log(result);//0
match()
- 能够根据正则表达式,从一个字符串中将符合条件的内容提取出来
- 默认状况下,只会找到第一个符合要求的内容,找到后就会中止检索
咱们能够设置正则表达式为全局匹配模式(能够为一个正则表达式设置多个匹配模式,且顺序无所谓
- 将匹配的内容封装到一个数组中返回,即便只查询到一个结果
replace()
- 能够将字符串中指定内容替换为新的内容
-参数:
1.被替换的内容,能够接受一个正则表达式做为参数
2.新的内容
- 默认自会替换第一个
var str='12a23jg23o4jg45jn6' var result=str.replace(/[A-z]/gi,''); console.log(result);//1223234456
建立一个正则表达式检察一个字符串中是否含有aaa
量词:
- 经过量词能够设置一个内容出现的次数
- {n}正好出现n次
- 量词只对它前面的一个内容起做用
- {m,n}出现m-n次(包含m,n)
- {m,}出现m次以上
- +:表示{1,}
- *:表示{0,}
- ?:{0,1}
检察一个字符串中是否以a开头 ^ 表示开头 $ 表示结尾
若是在正则表达式中同时使用^,$要求字符串必须彻底符合正则表达式
reg=/^a$/ //就是a
建立一个正则表达式,用来检察一个字符串是不是一个手机号
reg=/^1{3-9}[0-9]{9}$/
. 表示任意字符
逻辑与和逻辑或
1在条件判断中使用她们
2在赋值操做中,咱们有时也会使用她们
Var A=1||2:首先验证1是真仍是假,若真,把1赋值给A,若为假,把2给A
Var A=1&&2:首先验证1是真仍是假,若真,把2给A,若假,把1给A
Function fn(x)
{//给形式参数赋值默认值:验证传递参数值,若是没有传递实參,其默认值为零
if(x===undefined)//三个等号,undefined(false,(0)) {x=0} if(typeof x===’undefined’) {x=0} x=x||0(没有上述严谨,if这种是没传值,才会赋值默认值,这种是不传值或者传递的值是假,都让它等于零) } function fn(callback){ If(typeof callback===‘function’){ Callback();} Callback &&callback();//上面if判断的简写版(不严谨):默认callback要否则就传函数,要否则就不传 } Fn(function(){})//把一个函数做为值传递给形參,这种机制叫作回调函数
3逻辑与和逻辑或的混合应用模式
(逻辑与的优先级大于逻辑或)
console.log(0||1&&2||0||3&&2||1)//2
4逻辑或的实战应用:形參赋值默认值(初始化形參)
//es6新语法规范中能够直接给形參设置默认值
Function fn(x=0){}fn();
//若是x没有传递值(undefined也是没有传递值),默认值是零,一旦传递值,无论传递的是啥,都是按照传递的值处理的
var a=9;
function fn(){
a=0;
return function(b){
return b+a++;}}//函数返回值,就将做用域销毁,若返回地址则不销毁
var f=fn ();
console.log(f(5));
console.log(fn()(5));//进入fn函数,而后将5赋值给b
console.log(f(5));
Console.log(a)//5 5 6 2
<body> <input type="button" value="btn1"> <input type="button" value="btn2"> <input type="button" value="btn3"> <script> window.onload=function(){ var oBtn=document.getElementsByTagName('input');//指定标签名的对象集合 for(var i=0;i<oBtn.length;i++){ oBtn[i].onclick=function(){ alert(i); } } }//循环运行完了,可是btn是点击的时候才触发 </script> </body>
缘由:做用域链的这种配置机制引出了一个反作用,即闭包只能取得包含函数中任何变量的最后一个值
解决方案: 经过匿名函数强制让闭包行为符合预期,以下:
window.onload=function(){ var oBtn=document.getElementsByTagName('input'); for(var i=0;i<oBtn.length;i++){ (function(i){ oBtn[i].onclick=function(){ alert(i); } })(i); } }
或者用Es6中的写法
window.onload=function(){ var oBtn=document.getElementsByTagName('input');//指定标签名的对象集合 for(let i=0;i<oBtn.length;i++){ oBtn[i].onclick=function(){ alert(i); } } }
或者直接添加index属性:
window.onload=function(){ var oBtn=document.getElementsByTagName('input');//指定标签名的对象集合 for(let i=0;i<oBtn.length;i++){ oBtn[i].index=(i+1); oBtn[i].onclick=function(){ alert(this.index); } } }