克隆
var lilei={
sname:"Li Lei",
sage:11,
address:{city:"北京",street:"万寿路"}
};
function clone(obj){
var newObj=new Object();
for(var key in obj){
//key:属性名
//obj[key]: 属性值
//如果obj[key]不是对象,才直接复制属性值
if(typeof obj[key]!="object")
newObj[key]=obj[key];
else//否则,就将子对象再次克隆一份
newObj[key]=clone(obj[key]);
}
return newObj;
}
var lilei_clone=clone(lilei);
//var lilei_clone=lilei;
console.dir(lilei_clone);
console.log(lilei_clone==lilei);//false
//比的是地址
console.log(
lilei_clone.address==lilei.address
);//false
lilei_clone.address.city="西安";
console.log(lilei.address.city);
2.面向对象OOP ***
什么是对象:
程序中描述现实中一个具体事物的程序结构
本质:程序中同时存储一个事物的多个数据和函数的存储空间
什么是面向对象:
程序中,都是用对象来描述现实中一个具体事物,
再按需调用对象的功能或修改对象的属性。
为什么:
便于大量数据的维护和使用
何时:
只要管理多个事物,都必须用对象管理!
今后几乎所有开发都用面向对象方式
如何:
三大特点: 封装,继承,多态
1.封装:
什么是:
用对象结构保存显示中一个具体事物的属性和功能:
事物的属性,会成为对象的属性
事物的功能,会成为对象中的函数(方法)
为什么:
便于维护每个对象各自的属性和功能
何时:
只要使用面向对象的思想,第一步,都是封装对象
如何:
如何封装对象: 3种
JS中中对象的本质:
对象底层就是关联数组
对象就是关联数组的简写方式
1. 用{}直接量:
var obj={
属性名:值,
属性名:值,
... : ...,
方法名(){//ES6可省略 :function
... ...
}
}
问题: 对象自己的方法如何动态访问自己的属性值?
解决:
错误1: 直接使用属性名!
报错: 找不到属性名变量
原因: 所有不加点的变量,只能在作用域链中找。
无法自动进入对象中。
错误2: 用对象名.属性名
问题: 对象名仅是普通变量,随时可能更改。不便于维护!
正确: **** this.属性名
什么是this: AO中自动定义的一个关键词
自动指向当前正在调用函数的.前的对象的关键字
为什么: 不受对象名的影响
总结:
只要对象自己的方法,要访问对象自己的属性,必须用this.属性名
补充: 事件处理函数中,也可用this自动获得触发事件的.前的元素对象本身。
访问对象中的成员: 属性和方法
属性: 其实就是保存在对象中的普通变量
比如: obj.属性名
方法: 其实就是保存在对象中的普通函数
比如: obj.方法名()
2. 用new创建: 2步:
var obj=new Object();//{}
obj.属性名=值; 或 obj["属性名"]=值; //属性名固定时
obj[动态生成]=值; //如果属性名需要动态获得(变量,表达式);
obj.方法名=function(){ ... this ... };
揭示本质: ***js中一切对象,其实都是关联数组***
***对象其实就是关联数组的简化用法!***
问题:一次只能创建一个,如果反复创建多个相同结构的对象时,代码繁琐,不便于维护!
解决: 构造函数
对象 VS 数组 都可以用for in 遍历,
3. 用构造函数反复创建多个相同结构的对象:
什么是构造函数:
1. 定义同一类型的所有对象的统一结构
何时:
只要反复创建同一类型相同结构的多个对象时,都用构造函数
如何: 2步:
1. 定义构造函数:
function 类型名(属性参数列表){
this.属性名=属性参数;
this.方法名=function(){
... this.属性 ...
}
}
2. 用构造函数反复创建多个对象:
var obj=new 类型名(属性值列表)
new: 4件事:
1. 创建新的空对象:
2. 自动设置新对象,继承构造函数的原型对象
3. 调用构造函数,
3.1new自动修改this指向正在创建的新对象
3.2通过强行赋值向对象中添加新属性
4. 返回新对象地址,保存到变量中
如何访问对象的成员: 成员=属性+方法
obj.属性名 用法和普通变量完全一样!
obj.方法名 用法和普通函数完全一样!
问题: 每个对象都创建一个方法的副本,浪费内存!
解决:
DAY05============================================================
正课:
1. ***面向对象:
继承, 多态
2. ****ES5
1. ***面向对象:
问题: 放在构造函数中的方法定义,会被反复创建副本,浪费内存!
解决: 继承
1、继承:
1.什么是:
父对象的成员,子对象无需重复创建,就可直接使用
2.为什么:
代码重用, 节约内存!
构造函数:
优点:可代码重用
缺点:无法节约内存,会反复创建同一个方法的多个副本
3.何时:
只要类同一型的多个子对象,需要相同的属性值或方法定义功能时
4.如何:
js中的继承都是自动继承原型对象
5.原型对象:prototype
什么是:
专门保存同一类型的所有子对象共有成员的父对象
何时:
只要JS中使用继承,即多个子对象需要相同的属性值或功能时,都要使用原型对象
如何使用: 2步:
1. 创建: 自动创建!买一赠一!
只要创建一个构造函数,都附赠一个空的原型对象
2. 继承: 自动继承!
new的第2 步:
自动设置新对象,继承构造函数的原型对象
child.__proto__=构造函数.prototype
原型对象中的成员,子对象无需重复创建就可以使用
如何向原型对象中添加共有成员:
类型名.prototype.新成员=值/function(){...}
成员的访问顺序:
优先使用自有成员
自己没有,才去父级原型对象中查找
自有属性和共有属性:
自有属性: 保存在对象本地,仅当前对象自己所有
共有属性: 保存在公共的父级原型对象中,所有子对象共享的属性
获取时: 没有差别: 子对象.属性名
修改时: 自有属性: 子对象.属性名=值;
共有属性必须通过原型对象修改:
类型名.prototype.共有属性名=值;
判断是否自有属性:
var bool=obj.hasOwnProperty("属性名");
判断obj中是否包含指定的自有属性
如果返回true,说明指定属性是obj独有的自有属性
如果返回false:
1.自己没有,但原型中有
2.自己和原型都没有
6.内置对象(类型)的原型对象:
1.什么是内置对象:ES标准中规定的,浏览器厂商已经实现的对象
包括:11个
String Number Boolean--包装(box)类型
Array Date Math RegExp
Error
Function Object
Global(被window代替)
7.鄙视:包装类型
什么是:专门封装一个原始类型的值,并提供操作原始类型值的API的对象
为什么:原始类型的值本身,什么功能都没有,什么也做不了
何时使用:只要试图对原始类型的值调用函数时,都会自动使用包装类型
如何使用:
1、不用自己使用,自动应用
每当试图使用原始类型,访问属性或方法时,引擎会自动创建包装类型的对象
保存原始类型的值,原始类型调用的属性和方法,其实是包装类型对象提供的
过程:
..0.00试图对原始类型的值调用任何函数时:
1. 判断原始类型的类型名
2. 自动创建对应的包装类型对象,其中保存要操作的原始类型值
3. 调用包装类型对象,提起定义好的API
4. API调用后,包装类型对象自动释放!****************
鄙视: var str="hello";
str.len=10; //向str上添加一个新的属性,值为10
console.log(str.len);//输出str上的len属性值:?
原理: str.len=10; -> new String(str).len=10;
//执行后,new String()没人要,释放了!
console.log(str.len); -> console.log(new String(str).len);
解决: var str=new String("Hello");
str.money=10;
//因为new String()始终被str变量引用,不释放!
console.log(str.money);//10
8、内置对象
其实每种对象,都有两部分组成:
1、构造函数: 专门负责创建当前类型的子对象(妈)
比如:Array Date RegExp...
除了:Math(自己就是对象,不是函数) Window(不用new,本来就有)
2、原型对象: 专门负责保存当前类型所有子对象共有的API(爹)
问题: 旧浏览器不支持新标准的API或浏览器中的API不够用!
解决: 为浏览器添加想要的API
如何: 2步:
1. 先判断当前浏览器是否支持该API:
其实就是判断当前浏览器的指定类型的原型对象中是否包含想用的API
如何: if(typeof 类型名.prototype.API !="function")
2. 向指定类型的原型对象中添加API
类型名.prototype.API=function(参数列表){
... ...
03-Array-prototype-indexdOf.html
04-.html
}
9.原型链:
什么是: 由多级父元素逐级继承,形成的链式结构
作用: 存储必须用.才能访问的 所有对象可用的属性和方法
控制属性和方法的使用顺序和使用范围
顺序: 先自有,再共有
使用范围: 原型链中越靠上的成员,共享范围越大
vs 作用域链: 存储所有不需用.就可直接访问的变量
控制着变量的使用顺序: 先局部,后全局
顶级父类型: Object, 原型对象: Object.prototype
放在Object.prototype中的成员,所有对象都可使用
比如: toString() getOwnProperty()
顶级作用域: window——全局作用域对象
鄙视: 如何判断一个对象是不是数组类型!共几种方式!
错误:
typeof: 只能区分原始类型的值,对象和函数
无法进一步细致区分对象的类型名(具体类型)
正确:
1. 判断爹(原型对象)
如果一个对象的父对象是Array.prototype
var bool=(父对象father).isPrototypeOf(子对象obj);
//判断父对象father是否是子对象obj的爹 true->是
Array.prototype.isPrototypeOf(obj1),//false
不但检查直接父元素,且检查整个原型链,
只要任意一级为指定父元素,就是同类型
2. 判断妈(构造函数)
如果一个对象的原型对象的constructor属性为Array(构造函数)
obj.constructor==构造函数(Array)
问题: constructor是隐藏属性,不推荐使用:
变通: var bool=obj instanceof 构造函数(Array)
obj1 instanceof Array,//fales
//返回布尔类型,判断obj是否是Array类型的实例 true->是
检查整个原型链上的constructor属性,
只要有一级constructor是指定的构造函数,就是同类型
强调: 以上两种方式都不仅检查直接父(母)类型,且检查整个原型链。
3. 验DNA:
每个对象内都隐藏着一个class属性
class属性保存了对象创建时的最初类型名,
一旦确定,后续便不随继承关系改变而改变
问题1: class隐式属性 obj.class 拿不到,会返回undefined
唯一正确办法: 只有Object.prototype中最原始toString() 才能输出class
Object.prototype.toString
返回值:
[object class属性]
Object属性
Array属性
Date属性
问题2:
每种类型的子对象,调用toString()的输出结果各不相同
原因:多态(重写)使用子对象.toString(),容易被父对象中的toString()重写
解决: 用call+强行调用!
要抢的函数.call(主语);
=> 主语函数()
**Object.prototype.toString.call(obj)**
//在运行时临时相当于obj.toString()
判断以上 Object.prototype.toString.call(obj)=="[object Array]";//true|false
最严格的判断,不随继承关系改变而改变
4. isArray()
专门判断任何一个对象是不是Array数组类型 ES5
如何: var bool=Array.isArray(obj);
其实内部原理使用的就是第三种方式——严格的验证!
鄙视:
何时将函数定义在原型对象中,何时将函数直接定义在构造函数上
答:
实例方法:必须先创建子对象,才能用子对象调用的方法
何时: 如果要求,只能当前类型的子对象,才能调用的方法。
实例方法,都直接定义在当前类型的原型对象中,继承使用
arr.sort arr.push
Array.prototype.sort()//原型对象中
Array.prototpye.push()//原型对象中
静态方法: 不需要创建子对象,就能直接调用的方法
何时: 如果不要求使用方法的对象类型时,任何类型对象都能用!
静态方法,都直接定义在构造函数对象上。
String.fromCharCode()//
Array.isArray()//构造函数中
3.多态: 同一个函数在不同情况下调用,表现出不同状态
包括2种:
1. 重载(overload):
2. 重写(override):
什么是:(爹手机不好用,自己买个好的再用)
如果子对象觉得父对象成员不好用!可在子对象本地定义同名成员,覆盖父对象成员。
为什么:
因为从父对象继承来的成员不一定都是好用的!
何时:
只要觉得从父对象继承来的成员不好用,就可以在子对象中重写同名的自有成员!
每次都优先使用自有成员,不再使用父对象的成员
如何:
只要在子对象中定义和父对象同名的成员
原理:
成员的使用顺序: 先自有,再共有
自定义继承关系-3种:
1. 只修改一个对象的父对象: 认干爹
设置child继承father
//原 child.__proto__=father;
问题: __proto__是内部隐藏属性
Object.setPrototypeOf(child,father);
2. 同时修改多个(所有)子对象的父对象: 妈嫁豪门
其实就是修改构造函数的原型对象:
构造函数.prototype=father;
强调:
时机: 在创建子对象之前,就更换!
----------------------------------6----------------------------------------
3. 两种类型间的继承:*****(inherits_extends图)
问题: 两种类型间拥有部分相同的属性结构和方法定义
解决: 定义抽象父类型
如何: 3步:
1. 定义抽象父类型:
父类型构造函数: 保存所有子类型中共有的相同的属性结构
父类型原型对象: 保存所有子类型中共有的相同的方法定义
2. 让子类型继承抽象父类型
1、在子类型构造函数中,借用父类型构造函数
2、让子类型原型对象,继承父类型原型对象
错误:
直接调用父类型构造函数
原因:
任何函数,如果不用new 不用. 直接调用构造函数,
其中this默认都指window!!!
错误:
new Flyer(...)创建一个新对象,另起炉灶,和原对象无关了
错误:
this.Flyer(....)构造函数根本不在原型链上
正确: 只要函数调用时,this不是想要的,都用call替换!
父类型构造函数.call(this/*正确的*/,参数......);
call相当于用外部正确的this,代替了原本错误的this
function Flyer(fname,speed){//this->原本是window
this.fname=fname;
this.speed=speed;
};
Flyer.prototype={
fly(){
console.log(this.fname+"以时速"+this.speed+"飞行");
}
};
function Plane(fname,speed,score){//中this是正确的
Flyer.call(this/*正确的*/,fname,speed);
this.score=score;
};
Plane.prototype={
getScore(){
console.log("击落"+this.fname+"得"+this.score+"分");
}
};
Object.setPrototypeOf(
Plane.prototype,Flyer.prototype
);
var f16=new Plane("f16",1000,10);
f16.fly(); f16.getScore();
DAY06============================================================
正课:
ES5:***
1. 严格模式:
2. ***对对象的保护
数据属性, 访问器属性, 防篡改
3. Object.create()
4. **call/apply/bind
5. 数组API
1. 严格模式: "use strict";
什么是:
比传统js运行机制要求更严格的模式
为什么:
普通js中有很多广受诟病的缺陷
何时:
今后所有项目的开发,都必须在严格模式下进行
如何启用严格模式:
2种:
1. 为整个js文件或script标签 启用严格模式:
在js文件或script标签内开头第一行: "use strict";
何时: 从0开始的新项目,都要整个JS文件和script标签启用严格模式
2. 仅在单个函数内启用严格模式:
在函数内的第一行:"use strict";
何时: 旧项目改造,要逐个功能向严格模式迁移时
要求:规则
1. 禁止给未声明的变量赋值:
给未声明的变量赋值,会自动创建在全局,造成全局污染
function test(){
"use strict";
foo = 'bar'; // Error
}
2. 将静默失败升级为错误:
静默失败: 即执行不成功,又不报错!
3. 不建议使用arguments.callee
arguments.callee:专用于在函数内部递归调用当前函数本身
禁用arguments.callee:等效于禁止使用递归
今后所有递归都可用循环代替
//f1=1,f2=1,f3=f(n-1)+f(n-2)
function fib(n){
if(n<3) return 1
else{
//return arguments.callee(n-1)+arguments.callee(n-2);
var f1=1, f2=1, fn;
for(var i=3;i<=n;i++){
fn=f1+f2;
f1=f2;
f2=fn;
}
return fn;
}
}
console.log(fib(100));
4. 普通函数调用和匿名函数自调中的this不再指向window(避免了全局污染)!
返回undefined
2. 对对象的保护:
为什么:
js中普通的对象对自己的属性和结构,没有任何验证和保护的办法。
何时:
今后所有对象都要对自己的属性提供一定保护
如何:
1. 保护属性
ES5规定: 对象的属性分为2大类:
1、命名属性: 可用.直接访问到的属性
又细分为2类:
1. 数据属性: 直接存储属性值的属性
如何保护: 每个数据属性不再是一个简单的变量
而是一个拥有四大特定的小对象。
a、获取一个属性的四大特性:
var attrs=Object.getOwnPropertyDescriptor(obj,"属性名");
返回值: {
1.value: 实际存储属性值,
2.writable: true/false, 控制是否可以修改属性值 false-只读
3.enumerable: true/false, 控制能否可用for in遍历到
但是,仅控制for in 用.依然可以访问到!
4.configurable: true/false, 控制:
1. 控制能否可删除当前属性
2. 控制能否修改其它特性的值
**一旦该为false,不可逆!**
总是伴随其它特性的修改,充当双保险
}
b、如何设置修改四大特性保护数据属性:
Object.defineProperty(obj,"属性名",{
要修改的特性:值,
... : ...,
})
问题: 一次只能修改一个属性的四大特性
解决: 同时修改多个属性的四大特性:
Object.defineProperties(obj, {
属性名:{
四大特性:值,
... : ...
},
属性名:{
四大特性:值,
... : ...
}
...
});
说明: 如果要修改的属性不存在,则自动创建
坑: 自动创建的属性,四大特性默认值都为false
问题:
数据属性的特性无法用自定义规则保护自己
只能用固定的三种特性保护属性,无法用自定义规则灵活保护属性
解决:访问器属性
2. 访问器属性:
什么是: 不直接存储属性值,仅提供对另一个(其它)数据属性的保护。
何时:
1、只要用自定义规则保护属性时
2、为对象添加虚拟/计算属性时
如何定义: 2步:
1. 先定义一个隐藏的数据属性被保护,起别名,实际存储数据
问题:
使用enumerable隐藏的属性,防for in,但防不住.
别人可用eric._age绕过访问器属性,直接篡改受保护的属性。
解决:
闭包: 为访问器属性封装专门的变量
1. 在构造函数中定义局部变量_xxx实际存储属性值
2. 去掉访问器属性中的this.
2. 定义访问器属性,从受保护的数据属性中读取或修改数据
Object.defineProperties(eric,{
受保护的属性(别名):{//自动创建的属性,四大特性默认值都为false,可手动修改
1.value: 值
2.writable:false , 只读
3.enumerable: false,不遍历,隐藏的
4.configurable: false, 不删除修改
},
原名:{//访问器属性
get(){return this.受保护的数据属性},
set(val){//val会自动获得要赋的新值
如果val符合自定义规则
赋值this.受保护的数据属性=val
否则
throw new RangeError("报错,且不赋值");
},
enumberable:true,
configurable:true
},
})
如何使用:
使用时不要用隐藏的数据属性,要用访问器属性
在试图获取属性值时,自动调用get
在试图修改属性值时,自动调用set
参数val自动获得等号右边的新值
除此之外:访问器属性的用法和普通属性完全一样!
2、内部属性:
不能用.访问的属性:
ex: class _ _proto_ _
问题:仅保护单个属性,还没有保护住对象的结构
解决:保护结构
2. 保护结构:(防篡改)
3个级别:
1. 防扩展: 禁止向对象中添加新属性:
如何: Object.preventExtensions(obj);
原理:
每个对象内都有一个隐藏的内部属性extensible,默认true
preventExtensions将extensible改为false
判断是否防止扩展 Object.isExtensible(obj);
2. 密封: 即禁止扩展,又禁止删除!
如何: Object.seal(obj);
原理:
即修改对象的extensible为false
又自动修改每个属性的configurable为false!
3.冻结:禁止对对象的结构和属性值做任何修改
如何: Object.freeze(obj);
原理:
修改对象的extensible为false
自动修改每个属性的configurable为false!
自动将所有属性的writable改为false
判断是否冻结 Object.isFreezen(obj);
08-freeze.html
3. Object.create()
创建子对象,继承父对象,扩展自有属性
什么是:
基于现有父对象,创建他的子对象,并为子对象扩展新的自有属性
何时:
没有构造函数,只基于父对象,也想创建子对象继承父对象时
如何:
var child=Object.create(father/*可选对象,{
//和Object.defineProperties一样
属性名:{四大特性},
属性名:{四大特性},
... : ...
});
var father={bal:1000000000,car:"infiniti" };
var hmm=Object.create(father,{
//defineProperties
bao:{
value:"LV",
writable:true,
enumerable:true
},
phone:{
value:"iPhoneX 512G",
writable:true,
enumerable:true
}
});
console.dir(hmm);
4. call/apply/bind:
相同作用:
将函数中不是想要的this替换为指定想要的对象
何时:
只要函数组中的this不是想要的,都可以用这三个函数进行替换
不同:
.call/.apply:
强行*调用*一个函数,并*临时*替换函数中的this为指定对象
.call: 要求传入函数的参数必须单独传入
.apply: 要求传入函数的参数必须放在数组中整体传入
apply可先打散数组参数为单个元素,再传参
fun.call(obj,参数列表)
fun.apply(obj,参数值数组)
.bind:
基于一个现有函数,*创建*一个一模一样的新函数,
并*永久*绑定this为指定对象
var newFunction=fun.bind(obj,参数值列表);
一旦绑定,就不能被call和apply再作用
总结:
如果是临时*调用*一个函数,用call/apply
需要"创建"一个新函数,并永久绑定this时
所有回调函数中的this,要想替换都用bind
因为回调函数不是立刻执行,且不止执行一次!
function calc(base,bonus1,bonus2){
console.log(
this.ename+"的总工资是:"+(base+bonus1+bonus2)
);
}
var lilei={ ename:"Li Lei" };
var hmm={ ename:"Han Meimei" };
//临时借用:每次调用时,都临时替换this为指定对象。调用后,this和对象不再相关
calc.call(lilei,10000,2000,3000);
var arr=[4000,5000,6000];
calc.apply(hmm,arr);
//定制专属的: 永久绑定this为指定对象,并永久绑定部分参数值
var lilei_calc=calc.bind(lilei,10000);
//this base
lilei_calc(2000,3000);
lilei_calc(1000,3000);
//lilei_calc.call(hmm,5000,6000); 此时抢不了 还是李磊的
------------7----------------------------------------------
5. 数组API:
indexOf()已学
1. 判断: ——了解
every(): 判断数组中是否所有元素是否*都*符合条件要求
some(): 判断数组中是否包含符合条件要求的元素
如何: 仅以every()
arr.every(function(elem,i,arr){
//回调函数会在每个元素上自动调用一次
//每次调用时
//elem:自动获得当前元素值
//i :自动获得当前位置
//arr :自动获得当前.前的数组对象(原对象地址)->类似this
return 针对当前元素执行的判断条件
});
执行过程:
every会遍历每个元素,反复调用回调函数,
只有所有函数调用都返回true后,整体结果才返回true
/******************************************************/
<script>
if(typeof Array.prototype.every!=="function")
Array.prototype.every=function(fun){
document.write("调用自己的函数");
for(var i=0;i
if(!fun(this[i],i,this))
return false;
else
return true;
}
};
var arr1=[1,2,3,4,3,2,1];
var arr2=[2,4,6,8,10];
//由偶数组成
document.write(
arr1.every(function(elem,i,arr){
return elem%2==0;
})
);
document.write("<br>"+
arr2.every(function(elem,i,arr){
return elem%2==0;
})+"
"
);
//升序排序
document.write("升序"+
arr1.every(function(elem,i,arr){
return i
})+"
"
);
document.write("升序"+
arr2.every(function(elem,i,arr){
return i
})
);
</script>
/******************************************************/
2. 遍历API: 对数组中每个元素执行相同的操作
forEach(): 对原数组中每个元素执行相同操作
map(): 依次取出原数组中每个元素,执行相同操作后,返回新数组中。
如何:
arr.forEach(function(elem,i,arr){
arr[i]=新值;
});
arr.map(function(elem,i,arr){
return 新值;
})//return的新值会放入新数组中相同位置
<script>
if(typeof Array.prototype.forEarch!=="function")
Array.prototype.forEarch=function(callback){
document.write("调用自己的函数");
for(var i=0;i
if(this[i]!=="undefined")
callback(this[i],i,this)
}
}
if(typeof Array.prototype.ma!=="function")
Array.prototype.ma=function(callback){
document.write("<br>调用自己的函数");
var c=[];
for(var i=0;i
if(this[i]!==undefined)//稀疏数组
c[i]=callback(this[i],i,this);
}
return c;
}
var arr=[1,2,3,4,5];
arr.forEarch(function(elem,i,arr){
//将当前元素值*2
//elem*=2;不行,因为安置传递,修改的时副本
arr[i]*=2;//可以arr时原地址,不会错,arr的i可以
//arr[i]=elem*2;可以,原理同上
});
//值接修改原对象
var ar=[1,,3,4,5];
document.write(arr);
var nar=ar.ma(function(elem){
return elem*2;
});
document.write("<br>map"+nar);
document.write("<br>map"+ar);
</script>
3. 过滤和汇总:
1.过滤:
选取出原数组中符合条件的元素,组成新数组返回
原数组保持不变
var subs=arr.filter(function(elem,i,arr){
return 判断条件
}); //如果当前判断为true,则放入新数组返回
/*************************************************************/
<script>
var a=[1,2,3,4,5,6];
var c=a.filter(function(elem,i,arr){
return elem%2==0;
});
console.log(a);
console.log(c);
</script>
/*****************************************************/
2.汇总:
将数组中每个元素统计汇总,组成新值返回
var result=arr.reduce(
function(prev,elem,i,arr){
//prev: 保存截止到目前,临时的汇总值
return prev+elem;
},
base);// 以base值为基数,累加arr中每个元素值
/*************************************************************/
<script>
var cla1=[1,3,5,7,9];
var sum=cla1.reduce(
function(prev,elem,i,arr){
return prev+elem;
}
)
console.log(sum);//25
var cla2=[2,4,6,8,10];//30
sum=cla2.reduce(
function(prev,elem,i,arr){
return prev+elem;
},
sum//25
);
console.log(sum);
</script>
/*******************************************************/
DAY07============================================================
正课:
ES6:在不改变原理的基础上,纯简化了代码
块作用域
参数增强
箭头函数
模板字符串
结构
OOP
for of
promise*****
1. 块作用域:
let: 代替了var
为什么:
传统js中声明提前破坏了程序正常的执行顺序
let特点:
1、不会被声明提前
let会检查在当前作用域内,let变量之前,不允许提前使用该变量
2、相同作用域内,禁止重复let同一变量
3、仅在当前块作用域内有效
问题:
块内的变量即使不执行,也会被声明提前出块作用域,造成外部污染
解决:
let增加了块级作用域:{块级作用域}
if else else if for while do...while switch...case...
原理:
自动使用匿名函数自调方式,包括块 内的代码
何时:
只要声明变量,都要用let(希望代码块内的变量不要影响外部的变量时)
/*****************************************************/
<script>
//console.log(a);undefined
var a=5;
//console.log(a);5
//console.log(b); 报错
letb=5;
//console.log(b);
function fun(){
//console.log(b);//报错
letb=500;
console.log(b);//500
}
fun();
console.log(b);//5
</script>
<script>
var t=0;
function conn(){
console.log("连接成功");
t+=0.3;
}
function query(){
var t;
t+=0.8;
var err=false;
if(err){//块不是作用域
//var t=new Date();
lett=new Date();
console.log("出错了"+t.toLocaleString());
}
console.log("查询完成");
}
conn();
query();
console.log(t);
</script>
var btns=document.getElementsByTagName("button");
for(let/*匿名var*/ i=0;i
/*匿名(function(i){*/
btns[i].onclick=function(){
alert(i+1);
}//函数不调用不执行
/*匿名})(i);*/
}//i=4
btns[0].onclick();//alert(i);
btns[0].onclick();//alert(i);
btns[0].onclick();//alert(i);
btns[0].onclick();//alert(i);
/*************************************************************/
2. 参数增强: 3种:
1、默认值default: ES6中可对参数指定默认值。
调用时,如果没有传入参数值,则默认使用提前指定的默认值
比如: Array.prototype.indexOf=function(elem,fromi=0){
//fromi=fromi||0;
}
强调: 有默认值的参数,必须放在参数列表的最后
2、剩余rest:——代替arguments
当传入函数的参数个数不确定时,可用...接住剩余的一切参数
何时: 只要参数个数不确定,代替arguments
为什么: arguments的3大问题:
1. 总是获得全部参数,不能有选择的获得部分
2. 是类数组对象,不是纯正的数组,不能使用数组API
3. 名字太长
今后,只要代替arguments获得不确定个数的参数值时,都用rest语法
如何:
在函数定义时的参数列表中:
function fun(其它固定参数, ...自定数组名)
优:
1. 可有选择的获得部分参数
2. 是纯正的数组,能使用数组API
3. 可自定义名称
总结: 今后都用rest代替arguments
强调:
rest的参数数组,必须放在参数列表结尾
将类数组对象转为数组:
var arr2=arr1.slice(啥也不写)--复制数组
var arr=Array.prototype.slice.call(arguments);
/*标准做法:
var arr=
Array.prototype.slice.call(arguments);//复制一个类数组对象为数组
arr=arr.slice(1);*/
/*简写1
var arr=Array.prototype.slice.call(arguments,1);
*/
//简写2
var arr=[].slice.call(arguments,1);
3、散播spread: ——代替apply
在函数调用时,用...打散数组类型的参数为单个元素,再传入函数
为什么:
apply的主要目的是替换函数中的this,只不过可以顺便打散数组类型参数。
何时:
如果函数本身需要多个参数单独传入,而需要传入的确是数组时
如何:
在调用时,传入参数时用"...数组"打散数组参数,单个元素分别传入
function fun(...数组)
3. 箭头函数: 简化回调函数
何时:
今后所有回调函数和匿名函数都可用箭头函数简化
如何:
1. 去function换=> //放在参数后面
2. 更简化: 如果只有一个参数,可省略() //没有参数不可以省略
3. 更简化: 如果只有一句话,可省略{}
强调: 如果只有一句话,则结尾;不要!
更简化: 如果仅有一句return,则可省略return
特点: 箭头函数内外共用同一个this
特例: 如果希望内外this不通用时
比如:btn.onclick=function(){...this->btn...}
()=>{...this->btn...}//错误
e=>{...e.target->btn...}//正确
4. 模板字符串:
什么是: 支持内置表达式的字符串拼接
——简化了大段字符串复杂拼接
何时:
今后,只要拼接的字符串中包含要计算的表达式,就用模板字符串简化
如何:
1. 整个模板字符串必须用` `包裹
2. 在` `内支持 换行 "" '' 而不会发生字符串冲突
3. 如果需要拼接动态计算的表达式,则用${}包裹
DAY08======================================= ====================
正课:
1. 解构
2. for of
3. class
4. ***Promise
1. 解构:
什么是: 将一个对象或数组中的成员,分别赋值给多个单独的变量——简化批量赋值
何时: 只要将一个对象或数组中的成员,分别赋值给多个单独变量时
如何: 2种:
1. 数组解构:
var arr=[1,2,3];
var [a,b,c]=arr;
console.log(a,b,c);//1 2 3
强调: 数组解构靠下标对应
匹配:下标对下标
2. 对象解构:
将对象中的属性值,拆解后,赋值给多个变量
var obj={属性1:变量1,属性2:变量2,属性3:变量3}
var {x:变量1,y,:变量2,z:变量}=obj;
//ES6中,当属性名和变量名相同时(x:x冒号左右相同),可省略简写:{x,y,z}
ex:
var date={y:2017,m:9,d:21};
var {y:year,m:month,d:date}=date;
console.log(year,month,date);
强调: 对象解构靠属性名对应
3.参数结构:
函数调用时结构:
定义函数时: function fun({y:y,m:m,d:d}){...}
调用时: var date={y:2017,m:9,d:21};
fun(date)
2. for of: 简化版的for循环
如何: for(var p of arr)
p可直接获得arr中每个元素值
何时: 代替for循环,遍历下标为数字的数组或类数组对象
强调:
不能遍历关联数组和对象,因为下标不是数字,
只能遍历数字下标和类数组对象
for in 专门遍历关联数组
缺点:
1. 只能获得元素值,无法获得当前位置(无法获得下标)——要用下标时,不能用for of
2. 只能从前向后逐个遍历,不能有选择的遍历
3.如果数组中时原始类型的值,则elem是按值传递,得到的副本,无法直接修改原始值
3. class类型:
什么是:
封装一类对象统一结构和API的 程序结构——简化js中的面向对象
为什么:
传统的js类型定义方式不符合封装的特点
1.简化类型定义——封装:
class 类型名{
constructor(形参列表){
this.形参名=形参,
... ......
}
方法名(){
this.形参+....
}
}
如何:
1. 用class 类型名{}包括之前的构造函数和原型对象方法
2. 构造函数名升级为class名, 构造函数更名为constructor关键词
3. 原型对象方法不用写类型.prototype和function
直接写在class中的函数,自动添加prototype中
03-class.html******
2.简化继承:
1. class 子类型 extends 父类型
类似于:
Object.setPrototypeOf(
子类型.prototype, 父类型.prototype
);
2. 借用父类型构造函数: super(参数...)
不用call,不用this!
其中: super特指父类型构造函数,且自动用当前正确this替换父类型构造函数中的this
super.父类型原型方法()
04-inherits_extends.html*****
3.访问器属性:
get 属性名(){ return this._属性名;}
set 属性名(val){
if(判断)
this._属性名=val;
否则
throw new RangeError("报错,且不赋值");
}
05-get-set.html******
4.静态方法:
什么是: 不需要实例化对象,就可直接访问的成员
何时: 只要一个方法,不需要实例化也能使用时
原理: 相当于直接定义在构造函数对象上的方法
如何: static 方法(){...}
4、Promise ***承诺
什么是:
对传统回调函数的规范写法————规范回调函数的使用
何时:
如果回调函数,必须等待主函数执行完,才能执行时
只要定义在回调函数参数的函数时,都要用Promise
为什么:
callback hell
1、如何: 2步:
0. 前一个函数定义不要在参数上写callback
1. 前一个函数定义中: 用一个巨大的Promise对象包裹函数的内容,并将Promise对象返回
Promise的参数是一个巨大的回调函数:
1. 参数: callback: 用于接收将来承诺要做的后续函数
2. 函数体: 包括原正常执行的逻辑,并在逻辑中决定何时调用callback
2. 调用前一个函数时,可用.then传入下一项任务的函数对象作为回调函数
1.、定义接收回调函数的主函数
function fun(){
return new Promies(function(callback){
...
callback();
...
})
}
1. 去掉参数中的callback
2. 用return new Promise(function(){
原函数逻辑
})
3. 将callback写在Promise对象的参数函数中的参数列表中
2. 调用主函数执行,并传入下一个要执行的回调函数
fun()//return Promise
.then(callback)
如何:
1. 主函数fun不再接收任何回调函数参数
2. 在主函数调用后用.then(callback),将callback传给fun中的Promies对象的callback参数。
2、错误处理: 2步
1. 其实: promise的函数参数,还有第二个回调函数参数,用于在出错时调用 then catch
return new Promise(function(resolve,reject){
正常逻辑中:
如果正确执行, 调用resolve()
如果出错,调用reject("错误信息"/错误对象)
})
强调:
如果前一个函数调用了reject相当于抛出一个错误,不处理,程序就闪退
2. 错误处理:
在调用时,最后一个then的结尾追加
.catch(function(err){//err接住reject的参数
错误处理代码
})
07-promise.html************
2、异常处理: .then() .catch(fun)
return new Promise(function(resolve,reject){
//函数体
//如果执行成功
//调用resolve()
//否则
//调用reject()
})
3、等待多个任务都完成后才执行:
如何: Promise.all([ 函数1(), 函数2(), .......]).then(end)
1. 数组中的多个函数,并行!
2. 数组中最晚的任务执行后,自动调用end
3、
Promise.all([
支持Promise的函数(),
... ... ,
]).then(function(){ 后续任务 })
================================================================
封装AJAX