JS CORE

第一章

错误处理:

错误: 程序运行过程中,导致程序无法正常执行的现象(即bug)

现象: 程序一旦出错,默认会报错,并强行退出

错误处理: 即使程序出错,也保证程序不会强行退出的一种机制

为什么: 避免程序强行中断,导致极差的用户体验

何时: 只要希望即使程序发生错误,也保证不强行退出

如何(用于调用函数时):

try{

  可能出错的语句(执行语句)

}catch(err){                                /*只有发生错误时,才执行*/

  错误处理代码: 1.保存数据;2. 提示用户;3. 记录日志         /*console.log(String(err))*/

}

其中:err是错误对象: 错误发生时,自动创建的,记录错误信息的对象

性能问题: 1. 放入try catch中的代码,即使不出错,效率也比正常代码略低

          2. 程序出错都会创建错误对象(error),占用更多内存

解决: 如果可提前预知错误的原因,建议用if...else...(没有err)来代替try catch

优点: 1. 不影响程序执行效率;2. 节约内存

主动抛出错误:

什么是: 在本来程序不出错的情况下,为了以防万一,主动新建一个错误,并抛出

何时: 在协作开发中,函数的定义者向函数的使用者抛出错误,用以告知对方错误的使用了函数

如何:throw new Error("错误提示");/*放在 函数/catch 中*/

笔试:js中错误的类型: 6种

SyntaxError:语法错误

ReferenceError:引用错误: 要找的变量不存在

TypeError:类型错误: 错误的调用了API或错误的使用了()或[]

RangeError:范围错误: 参数的取值超范围

URIError,EvalError;

Uncaught SyntaxError: Unexpected identifier

ReferenceError: 变量名 is not defined            //可能是因为在严格模式下,没有声明变量

Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

/*块范围声明(let、const、function、class)还不支持外部严格模式,必须启用严格模式*/

var,let,const的区别:

var 定义的变量可以修改,如果不初始化会输出undefined,不会报错

let 制造一个'块级作用域'(if/else/for/while/单独一个{},必须写{})(JavaScript中没有块级作用域)

    在 {} 中用let定义的变量仅能在块内使用,对函数外部无影响

const 定义的变量值无法修改,而且必须初始化,范围限于声明它的块中,IE11及以上才支持

(非)严格模式:输出从未声明的变量时会返回: ReferenceError//没有找到对象,在全局输出局部变量时

函数必须调用,才会改变函数外的变量。注意局部变量和全局变量(调用全局变量时,改变的是全局变量)、原始类型和引用类型

函数(不论全局还是局部)若无return a;则返回undefined,即函数的值为undefined。有return a,函数(一般要接住)才有值(a也能是函数)

return的作用: 返回函数外,返回函数的值

如果一个函数没有用new,也没有用.调,它的this只能指向window

_______________________________________________________________________________________________

1.Function创建函数: 3种:

定义好的函数只要加(),就会调用,如 y=fn();

① 声明:

function 函数名(参数列表){函数体;return 返回值}

特点: 会被声明提前(没有赋值,函数体提前)

② 直接量:

var 函数名=function(参数列表){函数体;return 返回值}

特点: 不会被声明提前(声明提前,但赋值不会提前)

揭示:函数名其实是变量,函数定义是一个引用类型的对象,函数名通过函数对象的地址引用着函数

③ 用new(用的很少):

var 函数名=new Function("参数1", "参数2", ..., "函数体;return 返回值")

强调: 无论是参数名还是函数体,都必须放在""中,变量放在外面

2.重(chong)载(overload):

什么是: 相同函数名,不同参数列表的多个函数,在调用时,可根据参数的不同,自动选择对应的函数执行

为什么: 减少API的数量,减轻调用者的负担

何时: 一项任务,如果根据不同的参数,执行不同的操作流程时

问题:js默认不允许多个同名函数同时存在,即不支持重载语法

后果: 最后一个函数会覆盖之前所有函数

解决(3步):

① 仅定义一个函数,不要写参数列表

②arguments: 函数内自动创建的,接收所有传入函数的参数值的类数组对象/*argument: 参数*/

函数名.length表示函数定义时参数的个数(可写在函数外),arguments.length指外部调用时传参的个数

  类数组对象: 长的像数组的对象

  VS 数组: 相同:1. 下标, 2. .length, 3.for遍历

           不同: 类型不同 ——— API不通用

③ 函数内,根据arguments中参数的个数或类型,动态决定执行不同操作

if(arguments.length==n)...;else       /*参数的.length(个数)为n时,执行if后的语句*/

问题: 是否还需要参数

答:需要: 1. 参数用于提示调用者如何正确使用函数

         2. 参数名一般都比arguments简洁且见名知义

3.匿名函数:

匿名函数,若不改变this的指向(call、apply、bind),则this都指向window

什么是:定义函数时,没有指定函数名的函数

何时:2种: 只用一次的函数,都不要写名

为什么:

①节约内存,及时释放:

  垃圾回收: 垃圾回收器程序会自动释放不被任何变量引用的对象

  垃圾回收器: 专门检查并回收不再被使用的对象的小程序

②划分临时作用域,避免产生全局变量污染

如何: 2种

① 回调: 自己创建函数后,不调用,传递给其它函数,让其它函数使用

比如: arr.sort(function(a,b){ return a-b })

        str.replace(reg,function(kw){return 替换值})

        btn.addEventListener("事件名",function(){...})

注:回调函数可以单独拿出来定义,在调用时不要加括号

② 自调: 定义函数后,立刻调用自己,调用后立刻释放

如何:(function(){...})()

           包围函数的一对括号将其转换为一个表达式,紧跟其后的一对括号调用了这个函数

           可以不加一元运算符,但前面的js语句需加分号(;)

若前面刚好有个函数没有以;结尾,那么在匿名函数自调时会发生错误(可在前面加个;)

       +function(){...}()             /*不常用,+易与运算符混淆*/

       其它: 在匿名函数附近使用括号或一些一元运算符,用来引导解析器

何时:不希望产生任何全局变量污染时,都可将代码封装在匿名函数中,自调执行

优点: 划分临时作用域,避免创建全局变量

_______________________________________________________________________________________________

4.作用域(scope)和作用域链(scope chain)

什么是作用域: 变量的使用范围,也是一个变量的实际存储位置

包括2种作用域:

1. 全局作用域: window

  保存: 全局变量

  优点: 随处可用,可重复使用

  缺点: 易造成全局污染

2. 函数作用域(AO):

  保存: 局部变量

  优点: 仅函数内可用,不会被污染

  缺点: 不可重用

函数的生命周期:

① 程序开始执行前: 调用浏览器主程序,创建全局作用域对象window

② 定义函数:

  在全局创建函数名变量

  在window外创建函数对象保存函数定义

  函数名变量使用地址引用函数对象

  函数对象的隐藏属性scope指回函数诞生的作用域window

③ 调用函数:

  在ECS中添加本次函数调用的记录

创建本地函数调用所需的函数作用域对象AO(活动对象)

  在AO中创建局部变量(var 声明的和参数变量)

  AO的隐藏属性parent指向父级作用域对象

  变量使用顺序: 优先使用函数作用域AO中的局部变量

                局部没有,才去父级作用域找

④ 调用后:

  ECS中的本函数调用的记录出栈

  导致函数作用域AO没人引用,被释放

  导致AO中的局部变量一起释放

作用域链(scope chain):由多级作用域对象,逐级引用形成的链式结构

2个职责: 1. 保存所有变量: 全局变量都保存在window中,局部变量都保存在AO中

         2. 控制变量的使用顺序: 先局部,再全局

_______________________________________________________________________________________________

5.闭包(closure):

什么是: 既重用变量,又保护变量不被污染的一种机制

为什么: 全局变量和局部变量都有优缺点:

全局变量: 优: 可反复使用,随处可用

          缺: 易被污染

局部变量: 优: 仅函数内可用,不会被污染

          缺: 不可重用

何时:只要希望既重用变量,又保护变量不被污染,就只能用闭包

如何: 3步:

① 外层函数,包裹受保护的变量和操作变量的内层函数

   每次执行函数都将受保护的变量的值保存在闭包中(这个变量是局部变量)

② 外层函数将内层函数返回                                   /*return function(){...}*/

③ 使用者调用外层函数,获得返回的内层函数对象

笔试:闭包如何形成: 外层函数的函数作用域对象(AO)无法释放

缺点: 比普通函数占用更多内存空间———多的是外层函数的作用域对象AO

解决: 如果闭包不再使用,就要及时释放

将引用内层函数的变量赋值为null,导致内层函数对象先释放,使外层函数的AO一并释放

笔试(画简图):2步:

1.先找受保护的局部变量(避免被污染),并确定最终保存的值

外层函数的局部变量(var的或参数变量),受保护: 不会被全局的操作修改

就算局部变量循环,也只会有一个最终的值

2.再找操作变量的内层函数对象:3种情况:

① 直接return function

② 给全局变量赋值:全局变量=function

  ③ 将内层函数保存在数组/对象内,整体返回

特点:

外层函数声明局部变量并返回内层函数

内层函数操控(使用)局部变量

全局变量引用外层函数

一次外层函数调用,返回的多个内层函数,共用同一个受保护的变量

第二章*****************************************************************************************

1.面向对象OOP

事物的属性会成为对象中的属性: 属性就是保存在对象中的变量,用法和普通变量完全一样

事物的功能会成为对象中的方法: 方法就是保存在对象中的函数,用法和普通函数完全一样

  属性和方法统称为对象的成员

定义属性、定义方法{}用逗号,结尾    创建新对象、调用方法用分号;结尾

方法和函数的唯一不同之处: 方法始终与特定对象关联并与其配合使用

delete Obj[key]//删除对象成员key,无法删除变量、函数(无法删除数组元素,会变为undefined)

'name' in obj       //判断对象中是否拥有某个属性(包括继承属性),返回Boolean

obj.hasOwnProperty("a")    //判断对象是否有某个自有属性(不包括继承属性)

什么是面向对象编程: 程序中都是用对象结构来描述现实中一个具体事物

  对象: 内存中集中存储一个事物的属性和功能的程序结构

为什么: 便于维护和使用数据

何时: 今后只要维护的数据量或种类多时,都要用对象的方式,集中管理每个事物的属性和功能

如何:三大特点: 封装,继承,多态

封装:创建一个对象

什么是封装: 将一个事物的属性和功能集中保存在一个对象中,再起一个统一的名字

为什么封装: 让每个数据都有其专门的归属,便于维护和查找事物的属性和功能

何时封装: 只要使用面向对象,都要先将事物的属性和功能集中定义在在对象中,再使用

如何封装: 3种:

只创建一个单独的对象: 2种

1.对象直接量:

var obj={/*创建一个新对象*/

属性名:属性值,

... : ...,

  方法名:function(参数列表){ },           //旧写法

  方法名(参数列表){this.属性名...},       //ES6新写法

  方法名(...){...}

}

何时使用直接量: 如果创建对象时就已经知道对象的成员

对象自己的方法如何访问对象自己的属性:

错误: 对象名.属性名, 一旦对象名修改,方法内的对象名要同时修改,不便于维护(但语法无误)

正确: 在方法内使用关键词this自动指代当前对象本身: this.属性名

this: 能够自动获得正在调用的 当前函数.前 的对象的关键词

为什么: 不带this的普通变量,无法进入当前对象内查找属性,默认在作用域链中找

何时:只要对象的方法,想访问自己的属性,都必须加this

this可翻译为: 当前对象的属性                  .读作的

如何访问对象的成员:

如何访问对象的属性: 对象.属性名或对象["属性名"]

如何调用对象的方法: 对象.方法名()或对象["方法名()"]

2.用new:2步:

①先创建空对象: var obj=new Object();    //可以不加括号/new,也可把Object换成其它构造函数

②向空对象中添加新属性和方法:

 obj.属性名=值;//修改: 对象.自有属性名=新值

 obj.方法名=function(){...this.属性名...}

何时使用: 创建对象时,暂时不知道对象中的成员

强调:js中的对象创建后,可在任何时候,添加任何新属性和方法

如何: 只要尝试给不存在的属性和方法赋值,对象会自动创建该属性

js中对象的本质: 对象其实就是关联数组,只不过用法更简单

VS 关联数组:① 下标: obj["成员名"] <=> obj.成员名(若成员名是变量,可写为obj[变量])

            ② 都可随时添加新属性

③遍历: for(var key in obj){ obj[key] }

3.用构造函数(constructor)反复创建多个相同结构的对象:

构造函数: 描述一类对象统一结构的函数,还用于将一个新的空对象装修成想要的结构并存入数据

何时: 只要反复创建多个相同结构的对象时,都要先用构造函数定义一类对象的统一结构

如何:2步:

①定义构造函数:  创建函数的3种方法都可以定义构造函数(在函数内定义属性和方法要用this)

function 类型名(属性参数列表){      /*在构造函数中,所有的属性名和方法名前都要加this.*/

 this.属性名=属性参数;            /*从属性参数列表 传值给属性名*/

  ... = ...;                        /*this指new的新对象*/

 this.方法名=function(){           //需要返回的方法不要传参数,参数从this.*获取

    ...this.属性名...

} }

②用new调用构造函数创建新对象:

var obj=new 类型名(属性值列表); //创建"类型名"这种类型的对象 (同时也会执行这个构造函数)

                                       ()前的都是'类型名',()后的.后面的是'类型名'的成员

                                     //定义好的函数只要加(),就会调用,如 y=fn();

                                     //所有函数都可以用 new 实例化

new做了4件事:

1. 创建一个新的空对象

2. 让新的空对象继承构造函数的原型对象

3. 调用构造函数

   ① 设置构造函数中的this指向新的空对象

   ② 通过强行赋值的方式,为新对象添加新属性和方法

4. 返回新对象的地址保存在变量中

总结: 构造函数担当着两个角色

1. 图纸: 描述一类对象的统一结构

2. 装修队: 在空对象中添加固定的属性和方法

问题: 方法定义在构造函数内,每个新对象实例,都重复创建了一个完全相同的函数对象 ——— 浪费内存

总结: 构造函数: 优点: 代码重用        缺点: 无法节约内存

解决: 继承

_______________________________________________________________________________________________

继承:

什么是: 父对象的成员,子对象无需重复创建就可直接使用(子对象继承父对象的共有成员)

为什么: 代码重用,节约内存

何时: 如果多个子对象,拥有相同的属性值或方法定义时,只需要将相同的属性和方法定义集中定义在父元素中一份即可,所有子对象共用

如何: js中的继承都是继承原型对象

原型对象(prototype): 集中存储同一类型的子对象'共有属性和方法'的父对象

如何获得原型对象:

买一赠一: 创建构造函数同时,已经自动创建了该类型的原型对象。构造函数的prototype属性引用着所有子对象的父对象(即原型对象)

如何向原型对象中添加共有属性和方法:

构造函数.prototype.属性名=值

构造函数.prototype.方法名=function(){...}

强调: 原型对象中的方法,要想访问对象自己的属性,也必须加this.

总结:

每个子对象,值不同的属性,都要定义在构造函数中

所有子对象共有的相同方法和属性值,都要集中定义在原型对象中

共有属性和自有属性: 自有属性: 直接保存在对象本地的属性

                    共有属性: 保存在原型对象中,所有子对象共用的属性

相同: 获取属性值:对象.属性名

不同: 修改属性值:自有属性可直接通过子对象修改:子对象.自有属性名=值

共有属性只能通过构造函数的原型对象:构造函数.prototype.共有属性名=值

任何对象都有__proto__属性指向其父对象

任何函数都有prototype属性指向其原型对象

原型链:由多级父对象逐级继承形成的链式结构

保存着: 所有对象的属性和方法

控制着: 对象成员的使用顺序: 优先在对象本地找自有属性使用,自己没有才沿原型链向父对象查找

VS 作用域链: 由多级作用域对象逐级引用形成的链式结构

保存着: 所有的变量

控制着: 变量的使用顺序: 优先在函数作用域对象AO中查找使用,局部没有,才沿作用域链向父级作用域找

凡是不加.的变量,都在作用域链中找

凡是用.才能访问的属性,都在原型链中找

内置对象的原型对象:

每种内置类型都有一对儿构造函数和原型对象:

创建对象: 自动调用内置对象的构造函数

  比如: var arr=new Array();

        var now=new Date();

        var reg=new RegExp();

原型对象: 负责集中存储该类型可用的所有API

  比如: Array.prototype中的: .sort()  .push()  .slice()

  因为: Array.prototype:{

          sort(){...},

          push(){...},

          slice(){...},

          ...

        }

_______________________________________________________________________________________________

11个内置对象除Window(NodeJS中的Global)和Math(这两个对象属于对象类型,不是函数类型)均为构造函数

Number、String、Boolean、Function、Array、Date、RegExp、Error、Object

所有的构造函数均继承于Function.prototype(手动创建的构造函数一样,与内置对象在原型链上平级)

Function.prototype继承于Object.prototype(Window、Math、手动创建的对象也继承于Object.prototype。虽然Object.prototype是所有构造函数的父级对象,但Object仍然是函数)

所有的原型对象均继承于父级原型对象,最终继承于Object.prototype

所以可以强行调用: Object.prototype的toString方法来判断类型:

console.log(Object.prototype.toString.call(类型名))

修改继承的方式:

① call、apply、bind

② child.__proto__=father,不推荐,要使用 Object.setPrototypeOf(child, father)

③ 构造函数.prototype.属性名=值        构造函数.prototype.方法名=function(){...}

深度复制对象(引用不同的地址,互不影响)

newObj = JSON.parse(JSON.stringify(sourceObj))    //不能复制对象中的方法

newObj = Object.assign({}, obj1, obj2)    //浅拷贝(对象中的对象是直接引用的)

Object.create(null);                      //创建一个没有任何成员,且没有父对象的空对象

JSON.parse(obj, (key, value) => { return value })    //第二个参数可以在返回之前转换属性的值

JSON.stringify(obj, null, 2);        //将对象格式化JSON输出

  第一个参数: ① 是函数时,可以改变对象序列化中的行为

              ② 是包含String和Number的数组,可作为白名单,对对象过滤后再生成字符串

              ③ 是null或被省略,则所有的键值都被包含在生成的JSON字符串

  第二个参数: ① 若是Number(1-10),表示空格的数量

              ② 是String,则空格会替换为该字符串

              ③ 是null或被省略,不会显示空白符

_______________________________________________________________________________________________

解决浏览器兼容性问题: 旧浏览器无法使用新API

2步:

1. 判断当前类型的原型对象中是否包含想用的API

  比如: if(!"indexOf" in Array.prototype)

        其中in用于检查左边的成员名是否在右边的对象中或对象的原型链上

if(typeof 类型.prototype.API!=="function")

  比如: if(typeof Array.prototype.indexOf!=="function")

2. 如果没有,就向当前类型的原型对象中添加一个自定义的同名API

类型.prototype.API=function(){

this./*this: 代表当前类型(比如数组)对象*/

}

一、JavaScript继承是类继承还是原型继承

  是原型继承,尽管使用了new关键字,但只是一个语法糖,与类无关。JavaScript中没有类

二、prototype用来做什么

  prototype是个对象,只有函数有,用来存储对象的成员(属性和方法)的地方,是实现JavaScript原型继承的基础

三、__proto__用来做什么

  __proto__是个指向prototype的引用,用以辅助原型继承中向上查找的实现,是一个指向[[Prototype]]的引用

四、constructor用来做什么

  是对象上一个指向构造函数的引用,用来辅助instanceof等关键字的实现

_______________________________________________________________________________________________

多态:同一个函数在不同情况下,表现出不同的状态

包括:重载(overload)和重写(override)

重写(override): 如果子对象觉得从父对象继承的成员不好用,可在子对象本地定义同名自有成员,覆盖父对象的成员

为什么: 父对象继承来的成员,不一定都是想要的

何时: 只要父对象不是想要的,就可以修改继承关系,继承另一个对象

如何: 3种:

1.仅修改一个对象的__proto__属性指向新父对象:

  child.__proto__=father

问题: __proto__是内部属性,不推荐使用

解决: 使用Object.setPrototypeOf(child,father)

2.通过修改构造函数的原型对象,批量修改所有子对象的父对象:

构造函数.prototype=father

时机: 在开始创建子对象之前,就要换

3.两种类型间的继承:

何时: 如果多个类型之间存在部分相同的属性结构和方法定义时,就可抽象出一个公共的父类型

如何:

①抽象出公共父类型:

  父类型的构造函数中定义相同的属性结构

  父类型的原型对象中定义相同的方法

②让子类型继承父类型:

让子类型的原型对象继承父类型的原型对象

Object.setPrototypeOf(子类型.prototype,父类型.prototype);

③在子类型的构造函数中借用父类型的构造函数

  错误: 直接调用: 父类型构造函数(参数值...)

    原因: 直接调用函数时,函数中的this默认指向window,而不是当前新对象

  正确: 用call强行调用,并替换this为指定对象:

父类型构造函数.call((正确的)this,其它参数...);

call:专门用于强行替换函数内不正确的this为想要的对象

  何时: 只要函数中的this不是想要的,就可用call换成任意对象

    比如: fun.call(obj,参数值...)    调用fun,替换fun中的this为obj

第三章*****************************************************************************************

1.ES5:

ECMAScript: ECMA组织制定的JavaScript语言的国际标准,规定了JS语言的核心语法

ES5是ECMAScript的第五个版本(第四版过于复杂废弃了),IE8部分此版本

保护对象:

什么是:① 保护对象的属性和属性值始终有意义

       ② 防止篡改对象的结构

为什么:① 对象的属性,默认可随意赋值

       ② 对象可随意添加、删除属性

何时: 严格来说,今后所有对象,都要有自我保护的抵抗力

如何: 分为保护属性和防篡改

保护属性: 保护对属性值的修改

对象属性分为:

命名属性: 可通过.直接访问的属性

    分为: 数据属性: 直接保存属性值的属性

          访问器属性: 不直接存储属性值,仅提供对其他数据属性的保护

内部属性: 无法通过.直接访问的属性

数据属性的四大特性:

value:实际存储属性值

writable:true/false控制属性是否可修改属性值

enumerable:true/false控制属性是否可被for in遍历(false会跳过),仅控制遍历,无法控制用.访问

configurable:true/false控制是否可删除该属性,控制是否可修改其它两个特性

强调: configurable经常作为前两个属性的双保险,且一旦设为false,不可逆

获取四大特性:

Object.getOwnPropertyDescriptor(obj,"属性名")

设置1个属性的四大特性:

Object.defineProperty(obj,"属性名",{

  要修改的特性:特性值,

  要修改的特性:特性值,

  ... ...

})

问题: defineProperty一次只能修改一个属性

解决: 同时修改多个属性的特性:

Object.defineProperties(obj,{

  属性名:{ 要修改的特性 },

  属性名:{ 要修改的特性 },

  ... : ...

})

添加属性: 可用defineProperty添加新属性

          只要defineProperty要修改的属性不存在,就会自动添加

强调: 用defineProperty添加的新属性,四大特性默认值都为false

而用.添加的新属性,四大特性默认值都为true

问题: 无法使用自定义逻辑保护属性

解决: 访问器属性

_______________________________________________________________________________________________

访问器属性: 不直接存储属性值,仅提供对其他数据属性的保护

何时: 只要使用自定义的规则保护属性值

为什么: 数据属性的四大特性,保护规则是固定的,无法自定义

如何定义: 2步:

①定义一个隐藏的数据属性,用于实际存储属性值

②再定义一个访问器属性,保护隐藏的数据属性:

Object.defineProperty(obj,"属性名",{/*或用defineProperties,不能通过直接量或.创建*/

 get(){                                  /*在试图获取属性值时自动调用*/    

    return this.隐藏的数据属性;           /*返回受保护的数据属性值*/

 },

 set(val){          /*在试图修改属性值时自动调用,参数val会自动获得要修改的新值*/

    if(...)                /*验证val是否符合规则*/

      ...                  /*将val赋值给受保护的属性*/

    else ...               /*否则*/

      throw new Error      /*主动抛出错误*/

 },

enumerable:true,          /*设置四大属性*/

configurable:false

})

如何使用: 只要定义了访问器属性,就优先使用访问器属性,而不用受保护的数据属性

          访问器属性的用法和普通属性用法完全一样

          但是: 在取值时,自动调用get()

                在赋值时,自动调用set(),val会自动获得要赋的新值

内部属性: 无法通过.直接访问的隐藏属性

          比如: __proto__

_______________________________________________________________________________________________

防篡改: 阻止对对象结构的修改

3个级别:

①防扩展: 禁止添加新属性

Object.preventExtensions(obj)

  原理: 每个obj内部都有一个隐藏属性: Extensible,默认为true

        preventExtensions将obj的Extensible改为false

②密封: 在防扩展的基础上,进一步禁止删除现有属性(两个不要一起用)

Object.seal(obj)

  原理: 将obj的Extensible改为false

        将所有属性的configurable都自动改为false

③ 冻结: 在密封基础上禁止修改一切属性值(过于严格)

Object.freeze(obj)

  原理: 修改obj的Extensible为false

        将所有属性的configurable都改为false

        还将所有属性的writable都改为false

_______________________________________________________________________________________________

Object.create(): 本质上是创建一个新的子对象

什么是: 基于一个现有父对象,创建一个新的子对象继承当前父对象,并扩展新属性

何时: 今后如果没有构造函数的情况下,也想创建子对象

如何:

var child=Object.create(father,{      /*若不用扩展自有属性,father后的内容不必写*/

  自有属性:{

    value:值,

    writable:true,

    enumerable:true,

    configurable:true,

  },

  ... : {

    ...

  }

});

强调: 只要添加到对象中的属性,四大特性默认为false,必须显式写为true

原理:① 创建一个空对象

     ② 让新对象自动继承father

     ③ 为新对象扩展新的自有属性

_______________________________________________________________________________________________

call/apply/bind:

共同:为了替换函数中不想要的this

何时: 只要函数中的this不是想要的 (函数不加括号,只在call/apply/bind右边加括号)

call和apply:

什么是:强行调用一个函数并临时替换函数中的this为指定的新对象

call:  要求传入函数的参数必须单独传入,逗号分隔

第1个参数是要指定的this,第2,3...个是要替换的参数

apply: 要求传入函数的参数,必须放入数组中整体传入

       apply可自动打散数组类型的参数,单个传入

第1个参数是要指定的this,第2个参数是一个数组

bind:  基于一个现有函数创建一个功能完全相同的新函数,并永久绑定this为指定对象

       还可永久绑定部分固定的参数值

替换回调函数中的this时,都用bind

比如: var newFun=fun.bind(obj)    //接收新参数,函数后添加

             newFun(参数1,...);          //调用函数

强调: 被bind永久绑定的this,不能再被call/apply临时替换

_______________________________________________________________________________________________

数组API:

判断: 判断数组中的元素是否符合要求

返回值:bool(可判断是否满足条件)

①every: 判断数组中所有元素是否都满足要求

var bool = arr.every(function(val,i,arr){  //回调函数: 当前元素值:val;当前元素位置:i;arr:当前数组

  return 判断条件

});

②some: 判断数组中是否包含满足条件的元素

var bool = arr.some(function(val,i,arr){

  return 判断条件

});

强调:数组API的回调函数中this默认->window,所以,不能用this指代当前元素值,但可用如arr[i]或val

遍历: 对数组中每个元素执行相同的操作:

①forEach: 对原数组中每个元素执行相同的操作

arr.forEach(function(val,i,arr){    //没有返回值

  arr[i]=新值;                      //对当前元素执行的操作,直接修改原数组,只能使用arr[i]

})

②map: 取出原数组中每个元素,执行相同操作后,再放入新数组返回

var arr2 = arr1.map(function(val,i,arr){        //返回一个新数组

  return 对当前元素操作后的新值(放入新数组中)        //不修改原数组,使用arr[i]=..可修改原数组

})

过滤和汇总:

过滤: filter: 复制原数组中符合条件的元素,组成新数组

var subArr=arr.filter(function(val,i,arr){

  return 判断条件        //筛选出arr中符合判断条件(为true)的元素值,放入新数组返回

})

汇总: reduce: 将数组中所有元素,统计出一个汇总结果

var r=arr.reduce(function(prev,val,i,arr){       //prev: 截止目前的临时汇总值

  return prev+val

},startVal);                           //startVal: 表示汇总开始的基数,可不写(默认为0)

将arr数组中每个值累加后,求和

强调: reduce不一定非要从0开始累加,可从任意startVal(也可以是其它数组)开始累加

_______________________________________________________________________________________________

严格模式:

什么是: 比普通js运行模式要求更严格的运行机制

为什么: 解决普通js运行模式中广受诟病的缺陷

何时: 今后都要在严格模式下开发

① 新项目, 必须全部启用严格模式

② 旧项目, 逐个函数向严格模式迁移

如何: 2种:

① 整个代码段启用严格模式:

在<script>标签或js文件的开头加入:"use strict";

② 仅对单个函数启用严格模式

仅在function内,函数体的顶部加入:"use strict";

要求:

1. 不允许对未声明的变量赋值

2. 静默失败升级为错误

3. 不推荐使用arguments.callee来实现递归

_______________________________________________________________________________________________

2.ES6(框架广泛采用,又称为ECMAScript 2015):

模板字符串: 对字符串拼接的简化(2015年首次发布,IE Edge不支持)

何时: 如果字符串中包含需要动态执行的表达式或回车换行时

如何:3件事

① 用``反引号(ESC键的正下方)包裹字符串

② 字符串中的变量和表达式都要放在${...}中

③ 模板字符串中支持:  换行,变量,表达式(),注释也会被解析

let:

1. 专门声明仅在当前块中有效的局部变量

  块: js中只要一个{}就是一个代码块

      let声明的变量,仅在{}内有效,不会被提前到{}外

2. 防止声明提前现象

声明提前: 在开始执行程序前,引擎会将var声明的变量和function声明的函数,提前到"当前作用域"顶部集中优先创建,再开始执行程序            /*但是赋值留在原地*/

何时:今后强烈建议用let代替var

强调:let必须配套严格模式使用

_______________________________________________________________________________________________

箭头函数: 对所有回调函数的终极简写

何时: 今后,几乎所有的回调函数,都要用箭头函数简化

如何:

1.所有回调函数都可:去 function(参数) 改为 (参数)=>

2.如果函数体只有一句话: 可省略{}

如果这一句话还是return,可省略return

3.如果只有一个参数:可省略()

但是,如果没有参数,必须保留空()

特点:箭头函数可让内外this共用同一个对象————不再需要bind替换

特殊: 如果不希望内外共用this,就不能用箭头函数(或者用e.target -> 当前单击的元素对象)

比如事件处理函数:

  elem.addEventListener("click",function(){ this -> 当前单击的元素对象,不共用 })

  elem.addEventListener("click",()=>{ 致使this -> 不是elem })

变通解决:

elem.addEventListener("click",e=>{ e.target->elem })    /*利用冒泡*/

特点:

① 箭头函数没有this

② 箭头函数没有arguments

③ 不能通过 new 关键字调用

④ 没有 new.target

⑤ 没有原型

⑥ 没有 super

_______________________________________________________________________________________________

for of: 简化for循环遍历:

何时: 直接获得每个元素值时

如何:

for(var i=0;i<arr.length;i++){ arr[i] }       /*arr[i]: 当前元素*/

简写为:

for(var val of arr){ val }            /*val: of会依次取出arr中每个元素的值,保存到val*/

局限:

①只能遍历索引数组和类数组对象,不能遍历关联数组和对象(只能用for in循环遍历)

② 无法获得下标

③ 只能逐个遍历所有,不能控制循环的开始和结束以及步调

④按值传递: 如果数组中保存的是原始类型的值,修改val,不会影响数组元素(val是数组元素值的副本)

何时:仅遍历元素值,不关心下标时,才可用for of简写

_______________________________________________________________________________________________

class: 对 面向对象 的简化

如何定义类型:

①用一个 class 类型名{}结构包裹原来的 构造函数和原型对象方法

②修改构造函数的'function'为'constructor',其余保持不变

③可省略开头的'类型.prototype'与方法名后的'=function'

直接定义在class中的函数直接量,会自动保存在当前类型的原型对象中

定义父类:

class Flyer{

  constructor(fname,speed){

    this.fname=fname;

    this.speed=speed;

  }

  fly(){ }        //fly <=> Flyer.prototype.fly

  get 访问器属性名(){ return this.受保护的其他属性 }    //添加访问器属性,在构造函数的平级

  set 访问器属性名(val){

    if(条件) this.受保护的属性=val

    else 报错

  }

}

继承: 不再设置Object.setPrototypeOf

①在'class 类型名'后添加'extends 父类型'名

② 在子类型构造函数中不允许直接用call调用父类型构造函数,可使用super(属性参数值列表),不加this

子类:

class Plane extends Flyer{             //让Plane继承Flyer

  constructor(fname,speed,score){

    super(fname,speed);  //super:关键字,指父类型的构造函数,自动将子类型的this传入父类构造函数中,不允许用call

    this.score=score;

  }

  getScore(){ }

}

使用:

var obj = new Plane('fname',10,30)    //也可以new父类: var obj = new Flyer('fname',10)

obj.getScore()        //子类的方法

obj.fly()             //父类的方法

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

推荐阅读更多精彩内容

  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,055评论 0 13
  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,621评论 2 17
  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 8,618评论 0 3
  • 一念周沙界,日用万般通。 湛然常寂灭,常展自家风。 ——宋 龙册晓荣
    过客如风阅读 503评论 0 0
  • 自打五月份转了新的岗位后,工作突然没有了那么大压力。 之前的工作就是努力干业绩,是那种一个月三十天休一天就是满足了...
    呼呼姑凉阅读 626评论 2 2