JavaScript高级知识四

1. ***OOP

 new: 4件事:

  1. 创建空对象

  2. 自动设置新对象继承构造函数的原型对象:

    child.__proto__=constructor.prototype

  3. 调用构造函数

    3.1将构造函数中的this指向正在创建的新对象.

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

  4. 返回新对象的地址给变量

*****继承:

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

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

   构造函数: 优: 可代码重用

             缺: 无法节约内存,反复创建同一个方法的多个副本

 何时: 只要同一类型的多个子对象间,拥有相同的属性值或方法定义时,都要用继承的方式来节约内存,重用代码

 如何:

  原型对象(prototype):

   什么是: 专门保存同一类型的所有子对象共有成员的父对象

   何时: 只要js中实现继承,都要使用原型对象

        今后只要同一类型所有子对象共有的成员,都必须集中保存在原型对象中。

   如何:

    创建: 不用创建:

         买一赠一: 定义构造函数同时,已经附赠了一个原型对象

    设置继承关系: 自动设置:

      new的第二步: 自动设置新对象继承构造函数的原型对象——原型对象中的成员,子对象无需重复创建就可直接使用

    使用原型对象:

     向原型对象中添加共有属性或方法

       构造函数.prototype.共有成员名=值/function(){ ... }

  自有属性和共有属性:

   自有属性: 仅当前对象自己所有

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

     获取: 子对象.属性名

     修改: 自有属性: 只能用子对象.属性名=值

           共有属性: 必须通过原型对象修改:

             构造函数.prototype.共有属性=值;

   判断是否自有属性:

     var bool=obj.hasOwnProperty("属性名")

     判断obj中是否包含指定的自有属性

     如果返回true,说明指定属性是obj独有的自有属性

     如果返回false,2种:

       1. 自己没有,但原型中有

       2. 自己和原型中都没有

  内置对象的原型对象:

   内置对象: ES标准中规定的,浏览器厂商已经实现的对象

   包括: 11个

    String, Number, Boolean —— 包装(box)类型

    Array, Date, Math, RegExp

    Error

    Function Object

    Global(被window代替)

   包装类型:

    什么是: 专门封装一个原始类型的值,并提供操作原始类型值的API 的对象

    为什么: 原始类型的值本身,什么功能都没有。

    何时: 只要试图对原始类型的值调用函数时,都会自动使用包装类型

    如何: 不用自己使用

     自动应用:

      每当试图使用原始类型,访问属性或方法时,引擎会自动创建包装类型的对象,保存原始类型的值

      调用的方法和属性,其实是包装类型对象提供的

  内置对象由2部分组成:

   1. 构造函数: 专门用于创建当前类型的子对象

    比如: Array, Date, RegExp, String, ...

   2. 原型对象: 专门保存当前类型所有子对象共用的API

   问题: 旧浏览器不支持新标准的API

 

  原型链:

   什么是: 由多级父元素逐级继承形成的链式结构

   保存: 所有对象中的属性和方法(都用.访问)

   控制着: 属性和方法的使用顺序,共享范围:

     共享范围: 原型链中,处于越上层的位置,共享范围越广。

   vs 作用域链:

      保存着所有变量(不需要.,直接访问)

      控制着变量的使用顺序: 先局部后全局

 鄙视: 如何判断一个对象是不是数组类型,有几种方式

   typeof肯定不行: typeof只能区分原始类型的值,对象,函数。无法进一步区分对象的具体类型

   1. 判断原型对象:

     如果一个对象的父对象是Array.prototype

     var bool=father.isPrototypeOf(obj)

         //判断father是否是obj的父对象

         //obj.__proto__==Array.prototype

     强调: 不但检查直接父元素,且检查整个原型链。只要任意一级为指定父元素,就是同类型。

   2. 判断构造函数:

     如果一个对象的原型对象的constructor属性为Array

     var bool=obj instanceof Array

           //判断obj是否是Array类型的实例

                          //obj.constructor==Array

     强调: 检查整个原型链上的constructor属性。只要有一级constructor是指定构造函数,就是同类型

   3. 判断对象的class属性:

    每个对象内部都有一个隐藏的class属性

    用于记录对象创建时的类型名

    在创建对象时,一旦确定,后续不随继承关系改变而改变。

    问题1: 无法直接通过.访问class属性

    解决: 唯一的获取class的方法:

      Object.prototype.toString 输出 "[object class]"

                                        Array

                                        Date

                                        ...

    问题2: 每种类型的子对象,调用toString()的输出结果各不相同

      原因: 多态(重写),每种类型的原型对象中,都根据自身的需要重写了Object.prototype.toString中原始的toString方法。

    解决: 抢

      要抢的函数.call(主语)

         => 主语.函数()

    Object.prototype.toString.call(obj)==="[object Array]"

    最严格的判断,不随继承关系改变而改变

   4. ES5:

    var bool=Array.isArray(obj);

      专门判断obj是不是数组类型

      强调: 原理就是第三种方式,严格判断

 鄙视: 何时将函数定义在原型对象中,何时将函数定义在构造函数上

  实例方法: 必须先创建子对象,才能用子对象调用的方法

    比如: var arr=[ ... ];

          arr.sort()   arr.push()   arr.reverse()

    实例方法,都保存在当前类型的原型对象中

    何时: 如果要求,只能当前类型的子对象,才能调用的方法。

  静态方法: 不需要创建子对象,就能直接调用的方法

    比如: String.fromCharCode()

          Array.isArray()

    静态方法,都直接定义在构造函数对象上。

    何时: 如果不要求使用方法的对象类型时,什么对象都能用!

多态:

 什么是: 同一个函数,不同情况下调用,表现出不同的状态

 包括: 重载和重写

   重写(override):

     什么是: 在子对象中定义和父对象同名的成员

     为什么: 从父对象继承来的成员,不一定都是好用的!

     何时: 只要觉得从父对象继承来的成员,不好用! 就可在子对象中定义同名自有成员。——结果: 每次都优先使用自有的成员,不再使用父对象的成员

     如何: 在子对象中定义和父对象同名的成员。

 

自定义继承: 3种:

 1. 只修改一个对象的父对象:

   Object.setPrototypeOf(child,father)

   设置child继承father

   //child.__proto__=father;

 2. 同时修改多个子对象的父对象:

   构造函数.prototype=father;

   强调: 时机: 在创建子对象之前,就更换!

 3. 两种类型间的继承:

  问题: 两种类型间拥有部分相同的属性和方法定义

  解决: 抽象一个父类型

   1. 定义抽象父类型: 2部分

     父类型构造函数: 保存相同的属性结构

     父类型原型对象: 保存相同的方法定义

   2. 让子类型继承抽象父类型: 2步:

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

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

      错误1: 直接调用父类型构造

        Flyer(...); //this->默认window

         this.fname=fname;

        window.fname=fname;

       原因: 一个函数,不用new,不用.调用,其中的this,默认指window

      错误2: new Flyer(...) 创建一个新对象,另起炉灶,和原对象无关了

      错误3: this.Flyer(...) 构造函数根本不在原型链上

      正确: 抢!

        Flyer.call(this,fname,speed)

          =>this.Flyer(fname,speed)

        call相当于用外部正确的this,代替了Flyer中原本错误的this!

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值