严格模式 “use strict”
必须用var声明变量
禁止自定义的函数中的this指向window (自调用函数,就是定义一个构造函数,直接写函数,不使用new去创建一个函数,不使用new的时候函数的this指针指向window);
创建eval()作用域。【非严格模式下,eval()方法里面的参数可以直接相当于外部的全部代码,可以被执行,可能是后台返回的要执行的代码,有可能在传输途径下被篡改。严格模式下,eval的内部数据是私有的,不会污染全局的元素。】
对象不可以有同名属性。
ES5扩展
json对象扩展
JSON.stringify(obj/arr) //将原生的js对象(数组)转换为json对象(数组)
JSON.parse(json) //将json对象转换为js对象(数组)
object扩展
1、Object.create(prototype,[descriptors]);
//作用:以指定对象为原型创建新的对象
//为新的对象指定新的属性,对属性进行表述【value:指定属性值;wirtable:标识当前属性值是否可以被修改;configurable:标识当前属性是否可以被删除;enumerable:标识当前属性是否能用for-in枚举,后面三个都是默认为false】
var obj = {username:'shufang107',age:'21'};
var obj1;
obj1 = Object.create(obj,{
sex:{
value:'女',
writable:'true';
}
})
2、Object.definepropertise(object,descriptors);
//作用:为指定的对象定义扩展多个属性
//get():用来获取当前属性值的回调函数,就是通过get()方法可以获取扩展属性的值
//set():修改当前属性值触发的回调函数,并且实参是修改后的值。
//存取属性:setter,getter一个用来存值,一个用来取值。
var obj2 = {firstname:'huang',lastname:'shufang'};
Object.definepropertise(obj2,{
fullName:{
get:function(){ //获取当前属性的值,会自动调用
console.log("get()"); 用来检测调用了几次get方法,会发现惰性调用,只有在 使用了fullname方法之后才会调用这个方法。
return this.firstname+" "+this.lastname;
}
set:function(data){ //监听扩展属性,data的值就是传入的新的属性值,在扩展属性发上变化的时候才会被调用。
var names = data.split(" ");
this.firstname = name[0];
this.lastname = name[1];
}
}
})
console.log(obj2.fullName); //此时get方法会被调用一次;
obj2.fullName = "haha huanghuang"; //当fullName的值被修改的时候,set方法存在才可以被修改,如果没有set方法不会被修改。
consloe.log(obj.fulName); //此时的返回值是被修改的值。
3、对象本身两个方法
get propertyName(){} 用来得到当前属性值的回调函数;
set propertyName(){} 用来监听当前属性值变化的回调函数;
//把前面的扩展方法中set function(){} 换成 set fullName(){}
数组的扩展
Array.prototype.indexOf(value); //得到值在数组中的第一个下标,相同值返回的也是第一个
Array.prototype.lastIndexOf(value); //得到值在数组中的最后一个下标
Array.prototype.forEach(function(item,index){}); //遍历数组
Array.prototype.map(function(item,index(){}); //遍历数组返回一个新的数组,返回加工后的值
Array.prototype.map(function(item,index(){}); //遍历过滤出一个新的数组,返回条件为true的值,留下的值满足过滤的条件。
var arr = [1,2,5,3,7,8,3,1,4];
console.log(arr.indexOf(1)); //返回0
console.log(arr.lastindexOf()); //返回7
arr.forEach(function(item,index){
console.log(item);
});
var arr1 = arr.map(function(item,index){
return item+10;
}); //创建一个新的数组arr1来承接新返回的函数。
var arr2 = arr.filter(function(item,index){
return item > 3;
})
函数的扩展
改变函数中this指向的对象 function.prrototype.bind(obj);
1、call():参数是一个一个直接放;
2、apply():参数放在数组里面来传递;
3、bind();参数传递方式与call()一样;但是这个方法将函数返回,而不会立刻执行这个函数。
var obj = {username:'shufang107'};
function foo(data){
console.log(this,data);
}
foo.call(obj,33);
foo.apply(obj,[33]);
var obj2 = foo.bind(obj,33);
//此时的obj2当前的obj函数;而不会立刻执行。
ES_6
let关键字
let 作用
1、与var类似,用于声明一个变量;
let特点
1、在块级作用域内有效
2、不能重复声明变量
3、不会预处理【预解析】,不存在提升
4、存在暂时性死区。在块级作用域下,也需要先声明在访问。1
js引擎机制的预处理:
1、变量声明:只声明不传值;
2、函数的预处理:函数有声明式函数【function Fn(){}】和赋值型函数【var Fn = function(){}】;
在var变量定义之前使用这个变量,因为存在预处理不会报错,但是值为undefined;
函数预处理是将声明式函数先提取出来,之后按顺序执行。
let应用
1、循环遍历加监听
2、使用let取代var是趋势
const关键字
const作用:
1、定义一个常量
const特点
1、不能修改
2、其他特点同let
const应用
1、保存不用改变的变量
变量的解构赋值
1、理解
从对象或数组中提取数据,并赋值给多个变量
//函数解构赋值
let obj = {username:'shufang107';age:21}
//普通赋值,此时是两部赋值
let username = obj.username;
let age = obj.age;
//解构赋值
let{username,age} = obj;
console.log(username); //打印出username的值
//注意:解构赋值let创建的变量一定是obj对象里面已经有的属性值,不可以写成 let{username,XXX} 此时的XXX得到的值是undefined;
//数组解构赋值
let arr = [1,2,4,5,7,8];
let[a,b] = arr;
console.log(a,b); //根据位置来获取值 1,2
let[,,a,b] = arr;
console.log(a,b); //得到4,5
//普通传递对象参数
function foo(obj){ //参数是一个obj对象
console.log(obj.username,obj.age);
}
//解构传参
function foo({username,age}){ //解构传参可以直接使用
consloe.log(username,age);
}
模板字符串
简化字符串的拼接
1、模板字符串必须用 ` `包含
2、变化的部分使用${XXX}定义;
let obj = {username:'shufang107';age:'21'};
let str = "我的名字:"+obj.username+" , 年龄是:"+”obj.age“; //普通拼接
let str = '我的名字:'$(obj.username),'年龄是:'$(obj.age);
简化对象的写法
1、可以省略同名属性的值
2、可以省略对象里面函数定义的function
let username = 'shufang107';
let age = 21;
let obj = {
username,
age,
getName(){ //普通的是getName = function(){...}
console.log(this.username);
}
}
箭头函数的详解
作用:定义匿名函数
基本语法:1、没有参数 ()=>console.log(“xxx”); //()可以省略,
2、一个参数 (i)=>i+2;
3、大于一个参数 (i,j)=> i+j;
4、函数体只有一条语句不用{}大括号,默认为函数的返回值;
5、函数体多条语句,需要用{}包围,需要手动return返回值;
使用场景:多用来定义回调函数
特点:
1、简洁
2、箭头函数没有自己的this,箭头函数的this不是调用的时候决定的,而是在定义的时候所处的对象就是他的this;
// 普通的函数是,什么元素调用这个函数,函数的this就指向这个元素。
3、扩展理解:箭头函数的this看外层是否有函数;
如果有:外层函数的this就是内部箭头函数的this;
如果没有:则this就是window;
每一个函数有有返回值,如果没有明确指定的时候默认为undefined;
//形参的情况
1、没有形参的时候,()不可以省略;
let fun1 = () =>console.log(“箭头函数”);
fun1(); //调用这个箭头函数
2、只有一个形参的时候,()可以省略;
let fun2 = a =>console.log(a);
fun2(1); //调用箭头函数
3、有两个及两个以上的形参的时候,()不可以省略
let fun3 = (a,b) =>console.log(a+b);
fun3(2,3);
//函数体的情况
1、只有一条语句或者表达式的时候,可以省略{}花括号,语句默认为返回值,但是运算语句加上{}之后就不是默认为返回值,需要手动return返回;
fun4 = (a,b) => a+b;
console.log(fun4(1,2)); //返回3;
fun4 = (a,b) => {a+b}; //加上大括号之后不是返回值了,执行上一句的时候是undefined;所以建议只有一条语句的时候不使用{};
2、两条或多条语句的时候,{}不可以省略//箭头函数的this指向
let btn = document.getElementById(“btn”); //获取按钮元素
btn.onclick = function(){
alert(“this”);
} //this指向HTML的button元素
btn.onclick = ()=>{console.log(this);} //此时的箭头函数外部没有function函数,所以this指向的是window;
let obj = {
name:“箭头函数”;
getname:function(){
btn.onclick = ()=>{console.log(this);} //此时的箭头函数外面有一个function,所以此时的this与外层函数this指向的对象是一样的。
}
getname2:() =>{
console.log(this); //此时的箭头函数外部没有函数,相当于 obj.getname2 = ()=>{console.log(this);},所以此时外部没有函数,this指向window;
}
}
三点运算符[…]
用途:rest(可变)参数
1、用在函数参数上,用来取代argument【函数的实参的一个伪数组,不可以使用数组的方法比如 forEach遍历】但是三点运算符只能是最后部分的形参参数
function fun(...values){
console.log(arguments); //此时返回的是一个伪数组,控制台显示[...]
console.log(values); //此时返回真的实参组成的数组
values.forEach(function(item,index)){
console.log(item,index); //values是一个函数实参形成的真的数组,所以可以调用数组的方法;
}
}
2、用在数组里面
let arr = [1,6];
let arr1 = [2,3,4,5];
arr = [1,...arr1,6]; //给arr函数从新赋值
console.log(arr); //[1,6]
console.log(...arr); //[1,2,3,4,5,6];
形参默认值
当不传入参数时默认使用参数里的默认值
function point(x = 1;y = 2){ //如果形参也没有指定一个值,则不传参数的时候是undefined function(x,y);
this.x = x;
this.y = y;
}
promise对象
理解:
1、promise对象 代表未来某个要发生的事件(通常是异步操作)
2、有了promise对象可以将异步操作以同步的流程表达出来,避免了层层嵌套的回调函数(“回调地狱【嵌套调用、几个不是嵌套的函数的复杂回调关系】”)
3、ES6的Promise是一个构造函数,用来生成promise实例
使用promise基本步骤:
1、创建promise对象
let promise = new Promise((resolve,reject) => {
//初始化promise状态为pending
//执行异步操作
if(异步操作成功){
resolve(value); //修改promise的状态为fullfilled
}else{
reject(errmsg); //修改promise的状态为reject
}
})
2、调用promise的then();
promise.then(function){
result => console.log(result),
errormsg => alert(errorMsg)
}
promise对象的3个状态:
1、pending:初始化状态
2、fullfilled:成功状态
3、reject:失败状态
应用:
1、使用promise实现超时处理
2、使用promise封装处理ajax请求
//创建promise对象
let promise = new Promise((resolve,reject) => {
//自动初始化promise状态:pending :初始化
console.log('111');
//执行异步操作,通常是发送ajax请求,开启定时器
setTimeout(() => {
console.log("333");
resolve();} //修改promise为fullfilled,
//如果异步操作成功返回的数据放在resolve的参数中,then中的函数就可以使用这个数据
2000)
})
console.log('222');
promise.then(() => { //then的两个参数是成功的回调
console.log("成功了。。。");
} , () => {//失败的回调
console.log("失败了。。。");
})
//实例练习
function getNews(url){ //ajax请求的函数,传入需要访问的url
let promise = new Promise((resolve,reject) => { //状态:初始化;执行异步任务;
let xmlHttp = new XMLHttpRequest(); //创建XMLHttpRequest的实例对象 xmlHttp;
xmlHttp.onreadystarechange = function(){
if (xml.readState === 4){
if(xmlHttp.status == 200){ //满足两个状态表示请求成功
console.log(xmlHttp.responseText); //打印当前返回的数据
resolve(xmlHttp.responseText); //修改promise的状态
}else{
reject('请求失败。。。'); //修改成失败的状态
}
}
}
xmlHttp.open('GET',url);
xmlHttp.send();
});
return promise; //因为promise创立在函数内部,只有在调用函数的时候才会被创建;
所以promise对象作为函数返回值才可以被外部使用这个promise对象。
}
getNews(url)
.then((data) => {
//发送请求获得新闻评论的内容,准备url
let commentsUrl = JSON.parse(data).commentrsUrl; //获取数据中的共同的url部分
let url = 'http://localhost:3000' + conmentsUrl;
//发送请求
return getNews(url); //将getNews()函数作为返回值,可以避免再次调用原来getNews()函数返回promise对象,之后进行无尽的循环调用,所以返回一个函数返回的
} , () => {
})
.then(() => {} , () => {}); //第二次使用的时候判断其食肉请求成功。
Symbol属性介绍
前言:ES5中的对象属性名都是字符串,容易造成重名,污染环境
symbol:
概念:ES6中的添加的一种原始数据类型symbol()
//原始数据类型:string,number,boolean,null,undefined,对象
特点:
1、symbol属性值对应的值是唯一的,解决命名冲突问题
2、symbol值不能与其他数据进行计算,包括字符串拼串
3、for-in,for-of遍历时不会遍历symbol属性。就是对象的属性遍历的时候跳过symbol属性;
使用:
1、调用symbol函数得到symbol值
//let symbol = Symbol();
//let obj = {};
//obj[symbol] = ‘hello’;
//symbol只是创建一个属性,obj[symbol]是将这个属性放到这个对象中
let targetData = {
[symbol.iterator]:function(){} //是对象的一个属性
}
2、传参标识
let symbol1 = Symbol();
let symbol2 = Symbol();
//没有参数的时候,虽然控制台打印出来的symbol1 和symbol2是一样的Symbol();但是实际上是不一样的
//console.log(symbol1 == symbol2); 返回false
let symbol1 = Symbol(‘one’);
let symbol2 = Symbol(‘two’);
//console.log(symbol1,symbol2)是 Symbol(‘one’),Symbol(‘two’) 通过参数来区别不同的Symbol;
3、内置Symbol值:此时symbol相当于一个对象;
除了定义自己使用的symbol 值之外,还有11个内置的symbol值;
symbol内置对象
iterator是一种接口机制,为各种不同的数据结构提供统一的访问机制
作用:
1、为各种数据机构提供一个统一的,简便的访问接口
2、使得数据结构的成员能够按照某种次序排列
3、ES6创造了一种新的遍历命令(for-of)循环,iterator接口主要提供for—of循环
工作原理:
1、创建一个指针对象(遍历器对象),指向数据结构的起始位置。
2、第一次调用next方法,指针自动指向数据结构的第一个成员
3、接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员
4、每次调用next指针返回的是一个包含value和done的对象{value:当前成员的值【遍历完之后是undefined】,done:布尔值【遍历完为true,没有遍历完是false】}
原生具备iterator接口的数据(可以使用for_of遍历)
扩展理解:
1、当使用for-of遍历目标数据的时候,该数据会自动去找Stmbol.iterator属性
//Array、argument、字符串、set容器、map容器
//模拟指针对象【遍历器对象】
function myIterator(arr){ //这个函数就是iterator接口
let nextIndex = 0; //记录指针的位置
return{
next:function(){
return nextIndex < arr.length ? {value:arr[nextIndex++],done:false}
}
}
}
let arr = [1,4,2,4,'asd']; //准备一个数据
let iteratorObj = myIterator(arr); //将函数的返回值赋值给一个对象
console.log(iteratorObj.next());
console.log(iteratorObj.next());
console.log(iteratorObj.next()); //重复调用这个方法,知道指针指向最后一个元素。
//将iterator接口不熟到指定数据的类型上,可以使用for-of去循环遍历
默认可以使用的数据类型:
//数组
let arr = [1,2,3,4,5]
for(let i of arr){
console.log(i);
}
//let str = 'abcdef';
for(let i for str){
console.log(i);
}
//遍历函数的argument伪数组
function fun(){
for(let i for arguments){
console.log(i);
}
}
//以上的for of遍历的数据结构中没有对象,所以对象需要使用for of 循环遍历的时候就要调用Symbol.iterator接口
//为对象添加这个iterator方法之后就可以进行遍历了
let targetData = {
[symbol.iterator]:function(){
let nextIndex = 0;
return function(){
next:function(){
return nextText < this.length ? {value:this[indexIndex++],done:false}:{value:undefined,done:ture};
}
}
}
}
generator函数简介
概念:
1、ES_6提供的解决异步编程的方案之一
2、generator函数是一个状态机,内部封装了不同状态的数据
3、用来生成遍历器对象
4、可暂停函数(惰性求值),yield 可暂停,next方法可以启动。每次返回的是yield后的表达式的结果
特点:
1、function 与函数名之间有一个星号(*)
2、内部用yield表达式来定义不同的状态;
function* generatorexample(){
let result = yield ‘hello’; //状态就是 hello
yield ‘generator’; //状态是generator
}
3、generator函数返回的是指针对象(iterator指针,调用next方法才开始执行),不会执行函数内部的逻辑;
console.log(MG.next()); //{value:开始执行,done:false};
//next方法返回的是遍历器iterator 返回的对象
4、调用next 方法函数内部逻辑开始执行,遇到yield表达式之后停止执行,next方法返回{value:yield后的表达式结果、undefined,done:false/true}
5、暂停后再次调用next方法会从上一次的yield表达式开始执行。
6、yield语句返回结果通常为undefined,调用next方法时候传入的参数会作为启动时候yield语句的返回值。
//下面的例子是使用generator方法对promise方法发送请求的修改
async函数详解及应用
概念:
真正解决异步回调的问题,同步流程表达异步操作
本质:
是Generator语法的升级
语法:
async function foo(){
await 异步操作;
await 异步操作;
}
特点:
1、不需要像generator去调用next方法,当前的异步操作完成之后自动往下执行;
2、返回的总是promise对象【generator方法也是返回promise对象】,可以用.then()方法执行下一步操作;
3、async 取代generator函数符号*,await取代generator函数的yield
4、语法上更加明确,使用简单。
//同样异步获取新闻内容例子
//下面是发送请求的函数
async function getNews(url){
return new Promise((resolve , reject) => {
$.ajax({
method:'GET';
url, //ES6中对象的属性与传入的参数一样的话可以省略这个属性的值;
success: data => resolve(data), //resolve函数总是返回他的参数,所以将获取的data数据当成参数返回;
error:error => reject() //请求失败
})
})
}
// async函数
async function test(){
let result = await getNews("http://localgost:3000/news?id=1"); //await语句执行之后返回的是promise对象,如果没有参数的时候这个打印这个对象的值是undefined
//await语句执行后有传入参数,则这个promise对象的返回值是这个参数的值。
console.log(result);
result = await getNews('http://localgost:3000' + result.comments); //第二次发送请求,获取新闻的评论值。
}
test(); //调用这个async函数。执行异步操作。
class类使用详解
1、通过class定义类、实现类的继承
2、在类中通过constructor定义构造方法 //类定义的方法会放在calss的原型对象上,普通函数和构造函数都是放在原型对象上
3、通过new来创建类的实例
4、通过extends来实现类的继承
5、通过super调用父类的构造方法
6、重写从父类中继承的一般方法
class person{
constructor(name,age){
this.name = name;
this.age = age;
}
showname(){ //类中不需要使用function 来定义方法
console.log(this.name);
}
}
let person = new Person('shufang107',21); //定义一个person类
//子类继承父类
class oneperson extends Person{
constructor(name,age,salary){
super(name,age); //继承父类的构造函数时需要使用super方法且进行传参,不然后返货undefined;
this.salary = salary; //这个元素是子类自己所有的元素
}
showName(){ //子类的方法从写,就是父类上也有这个方法
//但是当子类和父类都有一个同名的方法的时候,会调用子类的这个方法二不去执行父类的同名方法。
//但是子类没有这个方法的时候去调用,会通过原型链去找父类的这个方法来执行
}
}
字符串、数组的扩展
//字符串扩展
inculdes(str):判断是否含有指定的字符串
startsWith(str) :判断是否以指定的字符串开头
endWith(str):判断是否以指定的字符串结尾
repeat(count):将字符串重复指定的次数 var str = ‘we’;str.repat(3);//输出 wewewe
//数值的扩展
1、二进制与八进制的表示方法:二进制0b ,八进制 0o; //转换为10进制
console.log(0b1010); //10
console.log(0o34); //28
2、Number.isFinite(i); //判断是否是有限大的数
3、Number.isNaN(i); //判断是否为NaN
4、Number.isInteger(i); //判断是否为整数
5、Number.parseInt(str); //将字符串强制转换为数值类型
6、Math.trunc(i); //直接去除小数部分
//数组的扩展
1、Array.from(v); //将伪数组对象或可遍历的对象转换为真的数组
函数的参数、获取的页面元素等等
2、Array.of(v1,v2,v3); 将一系列值转换为数组
3、find(function(value,index,arr)){return true}; //找出第一个满足条件返回true的元素,判断的条件是函数体内部语句。
4、findIndex(function(value,index,arr)){return true}; //找出第一个满足条件返回true的元素的下标
对象方法的扩展
1、Object.is(v1,v2) //判断2个数据是否完全相等,按照字符串来判断
Object.is(0,-0); //false
Object.is(NaN,NaN); //true
console.log(0 == -0); //true
2、Object.assign(target,source1,source2…); //将源对象的属性复制到目标对象上
let obj = {};
let obj1 = {username:'shufang107',age:21}
Object.assign(obj,obj1,obj2);
3、直接操作_proto_属性; //可以将一个对象1设置为对象2的原型对象,此时对象2可以访问对象1的属性
let obj1 = {name : 'shufang107'};
let obj2 = {};
obj2._proto_ = obj1;
console.log(obj2.name); //可以得到obj1的属性值
深度克隆
let obj1 = {username:'shufang107' , age:21};
let obj2 = obj1; //对象1赋值给对象2赋=赋值是对象的引用,而不是这个对象的内存元素
//相当于赋值的是一个指向对象1的指针,所以赋值后对象1 和对象2操作元素会互相影响。
//但是如果不是对象类型的话,只是单纯的值类型或者字符串类型就不会影响,因为复制是新开辟一个内存地址存放复制的元素。
console.log(obj1);
拷贝数据
基本数据类型:
拷贝后会生成一份新的数据,修改拷贝以后的数据不会影响原来的数据
对象 、数组:
拷贝后不会生成新的数据,而拷贝的是引用,修改拷贝后的数据会影响原来的数据
拷贝数据的方法:
1、直接赋值给一个变量: //浅拷贝,会影响原数据
2、Object.assign(); //浅拷贝
3、Array.prototype.concat(); //浅拷贝,会影响数组里面的对象元素
let arr1 = [1,2,{name:‘shufang’}];
let arr2 = [4,5];
arr1.concat(arr2); //生成一个新的数组
Array.prototype.slice(); //浅拷贝
JSON.parse(JSON.stringfy()); //深度拷贝,但是元素里面不可以有函数
浅拷贝(对象、数组):拷贝的是引用,修改拷贝以后会影响原数据,使原数据不安全
深度拷贝:拷贝时生成新数据,修改数据后不会改变原来的数据
如何进行深度拷贝:
1、拷贝数据里面有对象:
继续遍历这个对象,直到拿到的是基本数据类型的时候才开始拷贝,此时就是深度拷贝
2、没有数组和对象
//知识储备
1、判断数据类型
typeof返回数据类型:string、Number、Boolean、Undefined、Object、function
Object.prototype.toString.call(obj)
// 使用Object.prototype原型链上的toString()方法将call绑定的元素转换为制服穿
for in循环:对象返回的是属性名,数组返回的是index下标
//定义检测数据类型的功能函数
function checkType(target){
return Object.prototype.toString.call(target).slice(8,-1);
//因为上面的toString方法返回的是字符串[Object Array],我们只需要后面的类型
}
function conle(target){ //初始化拷贝的数据类型
let result,targettype = checkedType(targrt); //判断变量result这个是最终克隆的数据
if(targettype === 'Object'){ //判断如果当前拷贝的是对象的话就先生成一个空对象
result = {};
}else if (targettype === 'Array'){ //同对象一样
result = [];
}else{
return target; //如果当前拷贝的不是对象和函数就直接返回这个元素。
}
//遍历目标数据,前面只是判断这个要复制的对象是什么,没有进行遍历,
for(let i in target){
//获取遍历数据结构的每一项值
let value = target[i];
//判断目标结构里的每一项的是否是对象/数组
if(checkType(value) === 'Object' || checkType(value) === 'Array'){
//如果是对象或者数组,继续遍历获取到value的值
result[i] = clone(value);
}else{
result[i] = value;//如果当前的元素不是对象或者数组,是基本数据类型
}
}
return result;
}
set容器map容器
set容器:
for of
使用set和for of 为数组去重