js高级——面向对象

JavaScript高级第一天

JavaScript基础知识复习

JavaScript的基本组成

* ECMAScript  语法规范
* DOM    操作dom元素的api
* BOM    操作浏览器对象的api

JavaScript数据类型

简单数据类型
* string
* number
* boolean
* undefined
复杂数据类型
* Object
* Array
* Date
* RegExp
* Function
* String
* Number
* Boolean
* null
* Math
  -首字母大写的都是构造函数
  -变量不可能为null值,除非手动去设置,在解除对象占用(引用)的时候会用到null

部分关键字的使用

* in
    - 判断属性是否存在于对象中
        -语法:属性名 in 对象
         其中属性名是字符串
        -注意:in操作数组的时候判断的是索引值是否存在
    - for in  遍历对象的 键
* typeof 判断对象的类型  返回值是string类型的  引用类型中,除了function其他的对象都是object类型
* delete
    - 删除对象的属性
    - 删除未使用var声明的变量
    - 返回值为boolean 表示是否删除成功
    - 注意:删除的属性如果不存在,返回true
    - 删除的如果是原型中的属性,返回true 但是删除不成功
* break continue
    - break 用来终止循环
    - continue 用来跳出当前循环,继续下次循环
* === 和 ==
    - === 要判断数据类型和值是否相等
    - == 值判断值是否相等
* || 和 &&
    - 表达式1 || 表达式2  如果 表达式1 就 返回 表达式1 否则 返回 表达式2
    - 表达式1 && 表达式2  如果 表达式1 就 返回 表达式2 否则 返回 表达式1

值类型和引用类型

* 值类型: 存储的是数据本身的变量就是值类型的数据
* 引用类型:存储的是数据的地址的变量就是引用类型的数据,数据自己在内存中单独存储

* 值类型的赋值:直接将存储的数据复制一份赋值给新的变量 两个变量独立存在互不影响
* 引用类型赋值:将存储的数据的地址复制一份赋值给新的变量
两个变量指向同一个对象,相互影响

* 值类型做函数的参数:函数内部的实参和形参只是做简单的赋值操作,两个数据独立存储于内存
中,在函数内部对形参进行修改,不会影响外面的变量
* 引用类型做函数的参数:将实参存储的地址赋值给了形参,在函数内部,形参同样指向该对象,所以在函数内部对形参进行修改,会影响到外面的变量
* 注意:如果在函数内部重新创建对象,为该形参赋值,那么两个对象将不再有关系,修改其中一个,另外一个不会受影响

对象的动态特性

* 对象的动态特性:在对象创建出来后,为对象添加新的属性和方法
* 方法:点语法 通过[]的形式添加([]内为字符串)
* 注意:如果使用不是字符串类型,会隐式转换成字符串类型

调试工具的使用

增删改查

异常处理

* 异常的最大的特征:一旦发生异常,后面的代码都不会再执行
* 注意:语法异常无法捕获,解析到语法错误就会停止,不会再执行
* 异常处理语句 try catch finally
```js
    try{
        //可能出现异常的代码
    }
    catch(e){
        //e就是出现异常的异常信息
        //出现异常后的处理代码
    }
    finally{
        //不管有没有出现异常,都会执行的代码
        //一般用来释放资源
    }
```
* 如何手动抛出异常:  throw  任何东西,  catch中会抓到该东西

面向对象的基本介绍

面向对象是什么?

面向对象是一种思维方式.
    是将解决问题的关注点放到解决问题所需要的一些列对象上。

面向过程是什么?

面向过程是一种思维方式.
    是将解决问题的关注点放到解决问题的详细的步骤上。

面向过程和面向对象的关系

面向对象是对面向过程的封装!!!

什么是对象?

万物皆对象

JavaScript中什么是对象

键值对儿的集合就是对象

itar 敲tab就可以出现for循环

JavaScript高级第二天

面向对象的三大特性

* 封装
* 继承
    自己没有的,拿别人过来用,就是继承
    将另个对象的属性和方法 拿过来使用 就是继承
* 多态
    使用父类的引用(指针)来指向子类的对象(JavaScript中用不到)
    使用多肽来隐藏不同
    父类的属性和方法供所有的子类共享,但父类不能访问子类的属性和方法

创建对象的四种方式

* 使用字面量创建对象
 ```js
    var o = {key:value, key:value...}
 ```
 用一个创建一个,不能复用,造成代码冗余,资源浪费
* 使用内置构造函数创建对象
 ```js
    var o = new Object();
    var o = new Array();
 ```
 创建出来的对象都是空的对象,要手动的去为对象添加属性。造成代码重复
* 封装简单的工厂函数(不推荐使用)
 ```js
 function createObj(){
      var obj = {};
      obj.xx=xxx;
      return obj;
 }
 ```
* 自定义构造函数
```
function 构造函数名{
    this.xxx=xxx;
    //....
}
```
什么是构造函数?
构造函数也是函数,但通常用来初始化对象

0.构造函数名首字母要大写
1.构造函数一般和new关键字一起使用
2.构造函数返回值默认为新创建对象 如果手动返回基本数据类型或者是null,不影响默认返回值,如果返回的是对象,那么新创建出来的对象将不会返回,取而代之的是return后面的对象

构造函数(constructor)的执行步骤
1.使用new关键字创建对象
2.调用构造函数,将new创建出来的对象赋值给构造函数内的this
3.使用this给新创建出来的对象增加成员
4.默认返回新创建出来的这个对象(普通的函数,如果不写返回语句,返回的是undefined)

实例化:通过构造函数创建对象的过程
实例:通过构造函数实例化出来的对象就是该构造函数的一个实例

原型

构造函数存在问题
构造函数中的方法,每新创建一个对象的时候,该对象都会重新的创建一次这个方法,每个独享独占一个方法
但是该方法内容完全相同,所以造成资源浪费

1.解决办法1
将构造函数内的方法,进行提取,放在构造函数外面,在构造函数内部进行引用赋值
那么创建出来的对象,都会指向构造函数外面的这个函数,达到共享的目的
问题:全局变量增多,造成全局变量污染,代码结构混乱,不容易维护

2.解决办法2
使用原型

原型

原型是什么?
在构造函数创建出来的时候,系统会默认的创建并关联一个对象,这个对象就是原型,原型对象默认是空对象
默认的原型对象中会有一个属性constructor指向该构造函数
原型的作用
<!-- 原型对象中的成员,可以被使用和它关联的构造函数创建出来的所有对象共享 -->
原型中的属性和方法 可以被使用该构造函数创建出来的对象 使用
构造函数的原型对象中的成员,可以被该构造函数创建出来的所有对象访问 而且所有的对象共享该对象
原型对象的使用
1. 使用对象的动态特性,为原型对象添加成员
2. 直接替换原型对象

注意事项:
    直接替换原型对象,会导致替换之前创建的对象的原型和替换之后创建的对象的原型不一致
原型的使用该注意事项
1.使用对象访问属性的时候,会现在对象中查找,如果找到了就直接使用
如果没有找到,就去原型中查找
2.使用对象设置属性的时候,只会在对象本身中查找,不会去原型中查找,如果在对象本身中没有找到这个属性
则给该对象新增一个属性,如果在对象中有这个属性,修改这个属性
3.如果在原型对象中有引用类型的属性,那么使用对象进行修改该属性内容,则其他所有跟这个原型对象相关的对象都会受到影响
Person.prototype.car = {};
var p = new Person( );
p.car = {}; //这是修改属性
p.car.brand= ""; //这是修改属性的内容
4.一般情况下不会将属性添加到原型对象中
只会将需要共享的方法,添加到原型对象中
proto
1.这个属性不是标准属性,所以存在通用性问题
2.一般不推荐使用这个属性
3.调试的时候,可以使用这个属性
4.这个属性是原型中的属性

替换原型时候的注意事项: 在新替换的原型中,没有constructor属性,会影响三角结构关系的合理性 so,在新替换的原型中,手动添加constructor属性,以保证关系的合理性,赋值为关联的构造函数

JavaScript 高级第三天

继承

混入式继承

for in
使用for in遍历对象1的属性,将所有的属性添加到另外一个对象2上
这时候就可以称 对象2 继承自 对象1

原型继承

定义:利用原型中的成员可以被和其相关的对象共享这一特性,可以实现继承,这种实现继承的方式,就是原型继承

原型继承的实现:
* 利用对象的动态特性,为原型对象添加成员
* 直接替换原型对象
    1.替换前的对象,在替换之后,所有的成员都丢失
    2.替换原型对象的时候,需要手动去指定原型对象的construtor属性
* 利用混入的方式给原型对象添加成员

经典继承

    var 对象1 = Object.create(对象2);
这个时候,创建出来的对象1继承自对象2

Object.create方法存在兼容性问题
如何解决?
1.检测浏览器是否支持Object.create方法,如果不支持,直接手动给Object添加create方法
2.自定义函数,在函数内部判断浏览器是否支持Object.create方法,如果不支持,则手动创建对象返回,否则直接调用

```js
    function create(obj){
        if(Object.create){
            return Object.create(obj);
        }else{
            function F(){
            }

            F.prototype = obj;

            return new F();
        }
    }
```

原型链

什么是原型链

每个构造函数都有原型对象,每个对象都有构造函数,每个构造函数的原型对象都是对象,也就有构造函数
然后就形成一个链式的结构,我们称之为原型链

属性搜索原则:
    1.当访问一个对象的成员的时候,会现在自身找有没有,如果找到直接使用,
    2.如果没有找到,则去当前对象的原型对象中去查找,如果找到了直接使用,
    3.如果没有找到,继续找原型对象的原型对象,如果找到了,直接使用
    4.如果没有找到,则继续向上查找,直到Object.prototype,如果还是没有,就报错

原型继承是什么?

通过修改原型链的结构,实现继承的方式就是原型继承

对象和原型的成员关系

function Person(){};
var p = new Person();

p对象中包含的成员有:Person.prototype中的成员和自身拥有成员 Person.prototype中的成员有:Object.prototype的成员和自身的成员

p对象可以访问Person.prototype和Object.prototype中的所有成员

Object.prototype的成员

  • constructor 属性:指向和该原型相关的构造函数
  • hasOwnProperty 方法: 判断对象本身是否拥有某个属性
  • isPrototypeOf 方法:判断对象1是否是对象2的原型 对象1.isprototypeof(对象2)
  • properIsEnumerable 方法: 1.判断属性是否属于对象本身,2.判断属性是否可以被遍历
  • toString toLocaleString: 将对象转换成字符串 toLocalString转换成字符串的时候应用的本地的设置格式
  • valueOf 方法:在对象参与运算的时候,首先调用valueOf方法获取对象的值,如果该值无法参与运算,将会调用toString方法
  • proto 属性: 指向当前对象的原型对象

Function

3种创建函数的方式

* 直接声明函数 function fun(){}
* 函数表达式 var fun=function(){}
* new Function() var fun=new Function(){}

可以用Function来创建函数: 语法:

var 函数名 = new Function();  //创建一个空的函数
var 函数名 = new Function("函数体") //创建一个没有参数的函数
var 函数名 = new Function("参数1","参数2", "参数3",..."函数体")
//当给Fucntion传多个参数的时候,最后一个参数为函数体,前面的参数为创建出来的函数的形参
//Function接收的所有的参数都是字符串类型的!!!

如何解决使用Funciton创建函数时,代码过长的问题 1.可以使用字符串拼接 让代码换行 2.使用模板的方式,将代码写在模板标签内,获取该标签的内容 3.使用反引号(`) 引住字符串,那么就可以 换行了

arguments对象

arguments对象是函数内部的一个对象,在函数调用的时候,系统会默认的将所有传入的实参存入该对象 arguments.length 可以用来判断实参的个数 arguments.callee 指向函数本身

注意:不管有没有形参,实参都会被存入该对象

eval函数

可以将字符串转换成js代码并执行

注意:当使用eval解析JSON格式字符串的时候,要注意,会将{}解析为代码段 1.可以在JSON格式字符串前面拼接 "var 变量名 =" eval("var 变量名 =" + JSON格式的字符串);

2.可以在JSON格式字符串前后拼接() eval("("+JSON格式的字符串+")")

Function和eval有什么区别 共同点,都可以将字符串转换成js代码 不同点 1.Function 创建出来的是 函数 并不会直接调用,只有当手动去调用创建出来的函数的时候,才会执行 2.eval 把字符串转成代码之后,直接就执行了

静态成员和实例成员

###静态成员 通过构造函数去访问的属性和方法就是静态成员

###实例成员 通过对象(实例)去访问的属性和方法就是实例成员

实际:
把工具方法,作为静态成员
把跟对象相关的方法,作为实例成员

JavaScript高级第四天

原型相关知识复习

原型链

函数的原型链

可以把Funciton当做一个构造函数,其他构造函数都是这个Function构造函数的实例
再用对象原型链的方式,去分析这个原型关系

Function这个构造函数也有原型对象
Function的原型对象是一个空的函数
Function的原型对象的原型对象是Object.prototype--->null

Object构造函数 是 通过  Function 构造函数  实例化出来的
Function构造函数 也是 通过 Function 构造函数 实例化出来的(不要强行去理解)

instanceof 关键字

判断一个构造函数的原型是不是存在于该对象的原型链上

javascript中所有的对象 都会有  Object.prototype
所以 所有的对象 instanceof Object 都是true

歌曲列表管理案例

递归

自己调用自己

化归思想

化繁为简,化未知为已知

递归的两个要素

1.自己调用自己
2.有递归结束条件

JavaScript高级第五天

使用递归获取后代元素

作用域

什么是作用域(块级作用域,词法作用域)

变量起作用的范围

什么是块级作用域

JS中没有块级作用域,使用代码块限定的作用域就是块级作用域

JS中的作用域叫做 词法作用域

词法作用域

在代码写好的时候,就能确定变量的作用域,这种作用域就是词法作用域

动态作用域.(是词法作用域就不可能是动态作用域)

在js当中,只有函数能创造作用域

var num = 123;
function f1(){
    console.log(num);  //如果是动态作用域打印的就是456 如果是词法作用域 打印123
}
function f2(){
    var num = 456;
    f1();
}
f2();

词法作用域的规则:
    函数允许访问函数外的数据.
    整个代码结构中只有函数可以限定作用域.
    作用域规则首先使用提升规则分析
    如果当前作用域中有了该变量, 就不考虑外面的同名变量

变量提升

JS代码的运行分两个阶段
* 预解析阶段
    * 变量名和函数提升
        将var声明的变量名和function开头的函数进行提升
        提升到当前作用域的最上方
* 执行阶段

注意:
    1.变量和函数同名的时候
        只提升函数,忽略变量名
    2.函数同名的时候
        都提升,但是后面的函数会覆盖前面的函数
    3.函数表达式,只会提升变量名,不会提后面的函数

    4.变量提升只会将变量和函数提升到当前作用域的最上方
    ```js
     funciton foo(){
        var num =123;
     }
    ```
    5.变量提升是分块 <script> 的

    ```html
    <script>
    foo()
    function foo(){
        console.log("第一个script标签内的函数")
    };
    </script>

    <script>
    foo()
    function foo(){
        console.log("第2个script标签内的函数")
    }
    </script>
    ```
    6.条件式函数声明 能否被提升,取决于浏览器, 不推荐使用!!!
    ```
    foo();//会报错,因为未被提升
    if(true){
        function foo(){

        }
    }


    ```
    is not defined 没有定义
    undefined  定义了没有赋值

作用域链

只要是函数都有作用域,函数内部的作用域可以访问函数外部的作用域
当多个函数嵌套的时候,就会形成一个链式的结构,这个就是作用域链

绘制作用域链图的步骤

1.先绘制0级作用域链
2.在全局作用域中查找,变量和函数的声明,找到之后,将所有的变量和函数用小方格放在0级作用域链上
3.再从0级作用域链上的函数引出1级作用域链
4.再去每一个1级作用域链中查找变量和函数的声明,找到之后.....
5.以此重复,就画好了整个作用域链

变量的搜索规则

1.首先在访问变量的作用域中查找该变量,如果找到直接使用
2.如果没有找到,去上一级作用域中继续查找,如果如果找到直接使用
3.如果没有找到,继续去上一级作用域中继续查找,直到全局作用域
4.如果找到了就用,如果没有直到就报错

闭包

闭包是什么

一个封闭的对外不公开的包裹结构或空间

js中的闭包是函数

闭包的原理就是作用域访问原则

 上级作用域无法直接访问下级作用域中的变量

闭包要解决的问题

1、在函数外部访问不到函数内部的数据
2、要解决的问题就是需要在外部间接的访问函数内部的数据

闭包的基本结构

```js
function outer(){
    var data = "数据";
    return function(){
        return data;
    }
}
```

```js
function outer(){
    var data = "数据";
    var data1 = "数据1";
    return {
        getData:function(){
            return data;
        },
        getData1:function(){
            return data1;
        }
    }
}
```
```js
 function outer(){
        var data = "数据";
        return {
            getData:function(){
                return data;
            },
            setData:function(value){
                data = value;
                return data;
            }
        }
    }
```

闭包的作用

如果把数据放在全局作用域内,那么所有人都可以随意修改,这个数据就不再可靠。

闭包可以创建一个私有空间,在这个空间内部的数据,外部无法直接访问

外部空间想要访问函数内部的数据,只能通过闭包提供的指定的方法,在这个方法内部 可以设置一些校验规则,让数据变得更加的安全。

JavaScript高级第六天

线程(了解)

JS是单线程的!
JS中,分了三个任务
  1.渲染任务
  2.js的代码执行任务
  3.事件处理任务

JS代码的执行顺序
1.先把主任务(代码任务)执行完毕
2.再去执行次要的任务(包括setTimeOut和setInterval中的回调函数中的代码)

闭包练习

setTimeout的执行时机
    所有的主任务的代码执行完毕之后,去检查所有的setTimeout回调函数,如果到时间了就执行

用闭包来解决回调函数在调用的时候访问的是全局的变量
在闭包中创建一个变量,来单独存储当前的回调函数需要的数据,
在调用的时候就会去使用这个单独的数据,而不是去访问全局变量

注册点击事件的时候
点击事件在触发的时候访问的是全局的变量
在闭包中创建一个变量,来单独存储当前的事件处理函数需要的数据,
在调用的时候就会去使用这个单独的数据,而不是去访问全局变量

闭包缓存

缓存:将常用的数据进行存储,以提升性能

硬件缓存
浏览器缓存(网站静态页面缓存机制:将网页静态化,存储在服务器端)
CDN
内存型数据库

如何用闭包实现缓存
1、写一个闭包在闭包中创建一个对象,用来做缓存的存储对象
2、在闭包中创建一个对象,用来做缓存的存储对象
3、在闭包中创建一个数组,用来存储换中的键
4、返回一个函数,这个函数需要两个参数,一个是key 一个是value
5、在返回的函数中,判断传入的value是否为undefined
6、如果为Undefined 则表示是获取值,就直接返回在第一步创建的缓存对象中指定的键对应的值
7、如果不为Undefined 则表示是设置值
8、在缓存对象中设置指定的key的值为value
9、把key加入存储key的数组
10、判断key数组是不是超出了缓存大小限制
11、如果超出限制,删除数组第一个元素(使用shift),获取到删除的key
12、使用删除的key删除缓存对象中存储的值(delete)

使用缓存解决斐波那契数列的性能问题

就是将已经计算过的数字缓存进一个数组中,下次再来访问的时候,直接在数组中进行查找,如果找到直接使用,如果没有找到,计算后将数字存入数组,然后返回该数字

沙箱模式

沙箱模式就是一个封闭的独立的环境

沙箱的规则:沙箱内部只能使用内部的变量,不能使用外部的变量

沙箱模式的基本模型
(function(win){
    //变量定义
    //逻辑代码
    //如果需要,向window对象添加成员,以暴露接口(win形参 window实参);
})(window)

为什么要使用立即执行函数表达式(IIFE)
因为IIFE不会向外界暴露任何的全局变量,但是又可以形成一个封闭的空间 刚好可以实现沙箱模式

第三方框架
插件
独立的组件

沙箱模式的优势
    1.沙箱模式使用的是IIFE,不会再外界暴露任何的全局变量,也就不会造成全局变量污染
    2.沙箱中的所有数据,都是和外界完全隔离的,外界无法对其进行修改,也就保证了代码的安全性

js中沙箱模式的实现原理就是
    函数可以构建作用域!上级作用域不能直接访问下级作用域中的数据

函数的四种调用模式

函数模式 this--->window 方法模式 this---->调用方法的对象 构造函数模式 this----->new出来的对象 工厂模式 寄生模式 上下文模式 执行环境的意思,相当于this this----->指定的是谁就是谁 call 函数.call(对象,arg1,arg2,arg3,...argn) apply 函数.apply(对象,数组) 都可以用来改变this的指向为参数的第一个值 call是使用单独的每一个参数来传参 apply是使用数组进行传参的,这个数组在调用的时候,会被意义拆解,当做函数的每一个采参数

apply方法和call方法第一个参数传递null的时候,都表示为函数调用模式 也就是将this指向window

call在函数的形参个数确定的情况下使用
apply在函数的形参个数不确定的情况下使用

this指向不同

JavaScript高级第七天

apply补充

当使用call和apply传入的第一个参数为值类型的时候
会将值类型转换成对应的对象(引用类型) 然后赋值给this
this.valueOf()或者+this或者“”+this,可以将this中的值打印出来

当传入的第一个参数为 null或者Undefined的时候,
会把this赋值为  window

借用构造函数 实现继承
function Person(){
    this.name:"joe";
}
function Student(){
        Person.apply(this);
}
var stu=new Student();

注册事件的兼容性处理

注册事件的方式

1.  ele.on事件类型 = function(){}
2.  addEventListener(事件类型,事件处理函数,useCapture)  第三个参数默认是false,冒泡阶段执行
3.  attachEvent(on事件类型,事件处理函数)

歌曲管理案例

tab栏切换案例

补充:

严格模式

开启严格模式的语法

    在所有语句之前加一个"use strict"

严格模式在JS的ES5版本中出现

给对象添加某一个属性,可以设置属性的各种内容

Object.defineProperty(obj,"name",{
    get:function(){
        return 10;
    }
})

indexOf 有兼容性问题,对象数组ie7不支持,字符串支持

转载于:https://my.oschina.net/u/3160839/blog/1861232

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值