JavaScript

克隆

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容