JS CORE

作者: fastwe | 来源:发表于2018-11-26 22:04 被阅读0次

    第一章

    错误处理:

    错误: 程序运行过程中,导致程序无法正常执行的现象(即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()             //父类的方法

    相关文章

      网友评论

          本文标题:JS CORE

          本文链接:https://www.haomeiwen.com/subject/gjfcqqtx.html