0%

js学习笔记

这是到目前为止的学习记录,持续更新中

JavaSprit学习笔记

出现背景

网景公司和sun公司合作,由Brendan Eich花费十天设计(敷衍设计的)

  • 要求:和java相似,比java简单
  • 于是Brendan Eich借鉴了
    • c语言的基本语法
    • java的数据类型和内存管理
    • Scheme的函数“第一等公民”的地位
    • Self的基于原型的继承机制
  • 总之,js
    • 是简化的函数式编程
    • 是简化的面向对象编程
    • 不是一个非常完善的语言
  • 后来,随着不断的使用,开发,完善,js现在已经是以一个成熟的网页编程语言

js的组成

  • BOM
    • Browser Object Model
    • js操作浏览器发生变化的属性和方法
  • DOM
    • Document Object Model
    • js操作文档流发生变化的属性和方法
  • ECMAScript
    • js的书写规则
    • js的语法规则
    • 用这种规则来操作BOM、DOM使网页或浏览器的内容发生变化

js的书写位置

  • 行内式
    • 写到html标签内部

        <a href="" javasprict:'你的js代码';></a>
      
  • 内嵌式
    • 写到html为js准备的标签script

        <script>
        你的js代码
        </script>
      
  • 外链式
    • 写到一个单独的js文件里,通过标签script的src属性(路径)来链接html文件

        <script src="/js/index.js"></script>
      
    • 不需要依赖任何行为,打开html就可以执行

js的变量

  • 变量

    • 在程序的运行过程中,保存一个中间值使用
  • 如何设置变量

      var num = 100
    
    • var - 表示准备一个容器
    • num - 变量名
    • = - 把100保存到num里,不是等于的意思
    • 100 - 要存放的数据
  • 一个变量只有一个值,第二次赋值会丢掉第一次的数据。

      var num = 100
      num = 200
    
    • 此时,num里的数据是200。100就不见/丢掉了
  • 变量的命名规则

    • 可以由:数字、字母、下划线、美元符组成
    • 不能以数字开头
    • 不能是js里的关键字
      • var、 function、 for
    • 严格区分大小写
      • num、NUM、Num是三个不一样的变量
    • 最好使用有意义的英文单词,拼音(不许缩写!其他人不理解)
      • 可以直观体现这个变量里面保存了什么

如何书写注释

  • 注释
    • 运行中会自动忽略的内容,主要用于学习沟通,便于理解代码使用
  • 书写方法
    • 单行注释

        //这是一行注释
      
    • 多行注释

        /*
        1
        2
        3
        */
      

在浏览器输出

  •   alert()
    
    • 弹窗显示
  •   console.log()
    
    • 控制台打印
  •   document.write()
    
    • 直接在页面输出

js的数据类型

基本数据类型

  • 数值类型

    • 0x100 - 16进制
    • 0o100 - 8进制
    • 0b100 - 2进制
  • 字符串类型

      var a = "英文状态下引号"
      var b = '单双引号都可以'
      var c = "前后引号要配套"  
    
  • 布尔类型

      var a = true
      var b = false
      //true和false要记牢
    
  • 空类型

      var a           //undefined
      var b = null    //null
    
    • undefined - 没有值,没有赋值
    • null - 有值,是空值null

引用数据类型

  • 盲区

js数据类型检测

tepoof 要检测的变量名

  • var a = 100
  • var result = tepoof a
  • console.log(result)
  • number

js数据类型的转换

转数值

  • Number()
    • 只有全是数字时可以转换
  • ParseInt()
    • 一位一位查看,到第一个非数字停止,保留前面的数字部分(首位不是数字,返回NaN)
    • 只能转整数
  • ParseFloat()
    • 规则和parseint()一样
    • 能转小数
      转字符串
  • string()
  • Tostring()
    • 要转换的内容.Tostring()
      转布尔
  • boolean()
    • 要转换的内容.boolean()
    • 只有0、NaN、””、undefind、null会被转换成false
    • 其他内容全部是true

js的运算符

算数运算符

  • +:加法运算
    • 只要符号有任何一边是字符串的时候,会进行字符串拼接
  • -:减法运算
  • *:乘法运算
  • /:除法运算
  • %:取余运算

赋值运算符

  • =:进行赋值操作
  • +=
    • a += 10(a = a + 10)
  • -=
  • *=
  • /=
  • %=

比较运算符

结果一定是个布尔值

  • ‘<’
  • ‘>’
  • ‘<=’
  • ‘>=’
  • ‘==’
    • 等于
    • 只比较值是否相等,不比较数据类型
  • ‘===’
    • 全等于
    • 数据类型和值要全部相等
  • ‘!=’
    • 不等于
    • 只考虑值是不是不相等,不考虑数据类型
  • ‘!==’
    • 不全等
    • 数据类型和值任意一个不相等,就是true

逻辑运算符

  • && 与
    • 两边都为true,最终结果才是true
  • || 或
    • 两边任意一边是true,最终结果就是true
  • ! 非
    • 取反运算 !true=false !false=true

自增自减运算符

  • ++
    • 前置++,先把变量值改变,再用改变后的值参与运算
    • 后置++,先参与运算,再改变变量值
    • 前置–,先把变量值改变,再用改变后的值参与运算
    • 后置–,先参与运算,再改变变量值

条件语句

条件分支语句

if 条件语句

  • if(){}
  • if(){}else{}
  • if(){}else if(){}
  • if(){}else if(){}else{}

swith 条件语句

  • swith(已知条件){

    case 选项:

    代码

    break

    case 选项:

    代码

    break

    case 选项:

    代码

    break

    }

  • 找到和已知条件完全匹配的选项执行

  • 需要写break,不然会向下穿透

  • 可以书写一个default,会在所有选项都不匹配的时候执行

  • 当发生穿透时,会从第一个满足条件的选项开始向下穿透

js循环结构语句

主要功能,可以提供一组有规律的数字

while 循环

  • while(条件判断){代码段}
  • while会重复执行一段代码,直到重复结束才会继续执行后面的代码
  • 千万要书写改变初始值的代码,不然就会出现死循环
  • 在循环内,初始值,条件判断和改变初始值都能控制循环的次数
  • 在循环内,循环控制变量是一组有规律的数字

do while 循环

  • do{代码端} while(条件判断)
  • 当初始值在条件以内的时候,while和do while是一样的
  • 当初始值在条件以外的时候
    • while循环一次都不执行
    • do while循环会执行一次

for 循环

  • for(定义初始值;条件判断;改变初始值){代码}
    1. 定义初定值
    2. 进行条件判断
    3. 执行代码
    4. 改变初始值
    • 优点:防止忘记写改变初始值进入死循环,因为不写“改变初始值”代码会报错

函数

1
2
3
4
5
6
7
//定义阶段
fuction 函数名(形参){
代码
return 返回值
}
//调用阶段
函数名(实参)

定义函数阶段

  • 函数定义阶段,函数体内的代码不执行

函数调用阶段

  • 调用一次执行一次

参数

  • 形参:
    • 就是定义再函数内部使用的变量
  • 实参:
    • 就是函数调用时给形参赋值的内容
  • return
    • 在函数内使用return给函数添加一个结果作为函数的返回值

作用域

范围

  • 全局作用域
    • 一个页面就是一个全局作用域
  • 私有作用域
    • 只有函数生成私有作用域

使用

  • 定义
    • 声明在什么位置的变量就是哪一个作用域的变量
  • 访问
    • 自己有用自己的,自己没有用父级的,以此类推,到全局没有就报错
  • 赋值
    • 自己给自己的赋值,自己没有的就给父级赋值,以此类推,到全局都没有,定义为全局再赋值

递归函数

一个函数调用了它自身,这种现象就称为递归。

1
2
3
fuction fn(n){
rutern n * fn(n-1);
}

但是,一个函数调用了它自身,并设置了结束条件,这个函数才是一个正确的递归函数

1
2
3
4
fuction fn(n){
if(n === 1) return 1;
rutern n * fn(n-1);
}

斐波那契数列

1
2
3
4
fuction fn(n){
if(n === 1 || n === 2) return 1;
rutern fn(n-1) * fn(n-2);
}

数据类型

对象数据类型(Object)

创建

1
var obj = {hair:'3',eyes:'2'}

操作

  • 增 对象名.键=值 or 对象名[‘键’]=值
  • 删 delete 对象名.键 or delete 对象名[‘键’]
  • 改 对象名.键=值 or 对象名[‘键’]=值
  • 查 对象名.键 or 对象名[‘键’]

数据数据类型(array)

数组:有序的数据集合

  • 创建
    1
    var arr =[100,200,300,400]
  • 排列
    • 索引:从0开始,依次+1
  • 长度操作
    • 访问:数组.length
    • 设置:数组.length=数字
  • 数据操作
    • 访问:数组[索引]
    • 设置:数组[索引]=值

      遍历

  • 利用循环进行遍历,开始为0,结束为“小于索引长度”,步长为1,使用循环控制变量当作索引来访问数组里面的每一个数据
    1
    2
    3
    4
    5
    var arr = []
    for(var i = 0 ; i < arr.length ; i++){
    arr[i] //当前索引上存在的数据

    }

排序

冒泡排序

选择排序

方法

数组常用方法

帮助我们对数组进行快速操作

  1. push() 从后面追加
    • 语法: 数组.push(数据)
    • 作用:将数据追加到数组末尾
    • 返回值:追加数据后数组的最新长度
  2. pop() 从后面删除
    • 语法:数组.pop()
    • 作用:删除数组的最后一个数据
    • 返回值:被删除的数据
  3. unshift() 从前面添加
    • 语法: 数组.unshift(数据)
    • 作用: 将数据添加到数组最前
    • 返回值: 添加数据后数组的最新长度
  4. shift() 从前面删除
    • 语法:数组.shift()
    • 作用: 删除数组最前一个数据
    • 返回值: 被删除的数据
  5. reverse() 反转数组
    • 语法: 数组.reverse()
    • 作用: 将数组反转
    • 返回值:反转后的数组
  6. splice()
    • 语法:数组.splice(开始索引,多少个,要插入的数据)
      • 开始索引:默认是0
      • 多少个:默认是0
      • 要插入的数据: 默认是没有
    • 作用:删除数组中若干数据,并选择是否插入新的数据
    • 返回值:以新数组的形式返回被删除的数据
  7. sort() 数组排序(分类)
    • 语法:数组.sort()
      • 数组.sort(fuction(a,b){return a - b })
      • 数组.sort(fuction(a,b){return b - a })
    • 作用:将数组进行排序
    • 返回值:排序好的新数组
  8. join() 数组链接为字符串
    • 语法:数组.join(连接符)
    • 作用:将数组用连接符连接成为一个字符串
    • 返回值:连接好的字符串
  9. concat() 拼接数组
    • 语法:数组.concat(其他数组)
    • 作用:将其他数组和数组拼接在一起
    • 返回值:拼接好的新数组
  10. slice() 截取数组
    • 语法:数组.slice(开始索引,结束索引)
      • 开始索引: 默认是0
      • 结束索引: 默认是数组长度
    • 作用:截取数组中的某些数据
    • 返回值:以新数组的形式返回截取出来的数据

      slice(1,3)包前不包后,就说,截取的数据只有索引为1,2的,没有3.

  11. indexOf() 查找数据在数组中的索引
    • 语法:数组.indexOf(数据)
    • 作用:查找数据在数组中索引的位置
    • 返回值:
      • 有该数据,返回一次出现的索引的位置
      • 没有数据,返回-1

item 数组的每一项
index 数组的索引
arr 原始数组

  1. forEach() 遍历数组
    • 语法:数组.forEach(fuction(item,index,arr){})
    • 作用:遍历数组
    • 返回值:无
  2. map() 映射数组
    • 语法:数组.map(fuction(item,index,arr){})
    • 作用:映射数组
    • 返回值:映射后的新数组
  3. filter() 过滤数组
    • 语法:数组.filter(fuction(item,index,arr){})
    • 作用:过滤数组
    • 返回值:过滤后的新数组
  4. every() 判断是否全部满足条件
    • 语法:数组.every(fuction(item,index,arr){})
    • 作用:判断数组是不是每一项都满足条件
    • 返回值:一个布尔值
  5. some() 判断是否有满足条件的项
    • 语法:数组.some(fuction(item,index,arr){})
    • 作用:判断数组是不是有某一项满足条件
    • 返回值:一个布尔值

字符串常用方法

帮助我们对字符串进行快速操作

  1. charAt() 按照索引获取字符
    • 语法:字符串.charAt(索引)
    • 作用:获取对应索引位置的字符
    • 返回值:对应索引位置的字符
  2. toLowerCase() 转大写
    • 语法:字符串.toLowerCase()
    • 作用:将字符串内的字母全部转换成小写
    • 返回值:转换好的字符串
  3. toUpperCase() 转小写
    • 语法:字符串.toLowerCase()
    • 作用: 将字符串内的字母全部转换成大写
    • 返回值:转换好的字符串
  4. replace() 替换字符串
    • 语法:字符串.replace(换下内容,换上内容)
    • 作用:将字符串内第一个满足换下内容的片段替换成换上内容
    • 返回值:替换好的字符串
  5. trim() 去除首尾空额
    • 语法:字符串.trim()
    • 作用:去除字符串首尾的空格
    • 返回值:去除空格后的字符串
  6. split() 切割字符串
    • 语法:字符串.split(分隔符)
    • 作用:按照分隔符将字符串切割成为一个数组
    • 返回值:切割后的数组
  7. substr() 截取字符串
    • 语法:字符串.substr(开始索引,多少个)
    • 作用:截取字符串
    • 返回值:截取出来的字符串
  8. substring() 截取字符串
    • 语法:字符串.substring(开始索引,结束索引)
    • 作用:截取字符串
    • 返回值:截取出来的字符串
  9. slice() 截取字符串
    • 语法:字符串.slice(开始索引,结束索引)
    • 作用:截取字符串
    • 返回值:截取出来的字符串

数字常用方法

帮助我们对数字进行快速操作

  1. random() 0-1之间的随机小数
    • 语法:Math.random()
    • 作用:获取0-1之间的随机小数。包括0,不包括1.
    • 返回值:0-1之间的随机小数
  2. round() 四舍五入取整
    • 语法:Math.round(数字)
    • 作用:对数字进行四舍五入取整
    • 返回值:四舍五入后的整数
  3. ceil() 向上取整
    • 语法:Math.ceil(数字)
    • 作用:对数字进行向上取整
    • 返回值:向上取整后的整数
  4. floor() 向下取整
    • 语法:Math.floor(数字)
    • 作用:对数字进行向下取整
    • 返回值:向下取整后的整数
  5. pow() 取幂
    • 语法:Math.pow(底数,指数)
    • 作用:对数字进行取幂运算
    • 返回值:取幂后的结果
  6. sqrt() 二次方根
    • 语法:Math.sqrt(数字)
    • 作用:对数字进行二次方跟运算
    • 返回值:二次方根后的结果
  7. abs() 取绝对值
    • 语法:Math.abs(数字)
    • 作用:对数字进行取绝对值运算
    • 返回值:绝对值运算后的结果
  8. max() 取最大值
    • 语法:Math.max(数组)
    • 作用:获取若干数字的最大值
    • 返回值:其中的最大值
  9. min() 取最小值
    • 语法:Math.min(数组)
    • 作用:获取若干数字的最小值
    • 返回值:其中的最小值
  10. PI 近似Π的值
    • 语法:Math.PI
    • 作用:得到一个近似Π的值
    • 返回值:一个近似Π的值

时间常用方法

js的BOM操作

一整套操作浏览器相关内容的属性和方法

  • 操作浏览器的历史记录
  • 操作浏览器的滚动条
  • 操作浏览器页面跳转
  • 操作浏览器标签页的开启和关闭
  • ……
  1. 获取浏览器窗口尺寸
  • 获取可视窗口宽度
  • 获取可视窗口高度
    1
    2
    3
    4
    //获取宽度
    window.innerWidth
    //获取高度
    window.innerHeight
  1. 浏览器的弹出层
  • 提示框
  • 询问框
  • 输入框
    1
    2
    3
    4
    5
    6
    //提示框
    window.alert('提示信息')
    //询问框
    window.confirm('提示信息')
    //输入框
    window.prompt('提示信息')
  1. 开启和关闭标签页
  • 开启
  • 关闭
    1
    2
    3
    4
    //开启
    window.open('地址')
    //关闭
    window.close()
  1. 浏览器常见事件
  • 资源加载完成
  • 可视尺寸改变
  • 滚动条位置改变
    1
    2
    3
    4
    5
    6
    //加载完成
    window.onload = fuction(){}
    //可视尺寸改变
    window.onresize = fuction(){}
    //滚动条位置改变
    window.onscorll = fuction(){}
  1. 浏览器的历史记录操作
  • 回退页面
  • 前进页面
    1
    2
    3
    4
    //回退页面
    window.history.back()
    //前进页面
    window.history.forward()
  1. 浏览器卷去的尺寸
  • 卷去的高度
    1
    2
    document.documentElement.scrollTop
    document.body.scrollTop
  • 卷去的宽度
    1
    2
    document.documentElement.scrollLeft
    document.body.scrollLeft
  1. 浏览器滚动到
  • window.scrollTo()
    • 参数方式
      1
      2
      3
      4
      5
      6
      7
      8
      //第一种
      window.scrollTo(left,top)
      //第二种
      window.scrollTo({
      left:xx,
      top:yy,
      behavior:'smooth'
      })

js的定时器

  • 间隔定时器
    • 按照指定周期(毫秒)去执行执行的代码
      1
      2
      3
      4
      5
      6
      setinterval(函数,时间)
      //函数:要执行的内容
      //时间:单位是ms
      setinterval(fuction(){
      console.log('执行一次')
      },1000)
  • 延时定时器
    • 在固定的时间(毫秒)后执行一次指定代码
      1
      2
      3
      4
      5
      6
      setTimeout(函数,时间)
      //时间到达执行的内容
      //单位是毫秒
      setTimeout(fuction(){
      console.log('执行一次')
      },1000)
  • 定时器的返回值
    • 不区分定时器种类
    • 表示是是当前页面的第几个定时器
      1
      2
      3
      4
      5
      6
      7
      // 书写第一个定时器
      var timer1 = setInterval(function () {}, 1000)
      // 书写第二个定时器
      var timer2 = setTimeout(function () {}, 1000)
      // 输出返回值
      console.log'timer1 : ', timer1 )
      console.log'timer2 : ', timer2 )
  • 关闭定时器
    1
    2
    3
    4
    5
    //语法一
    clearInterval(要关闭的定时器返回值)
    //语法二
    clearTimeout(要关闭的定时器返回值)
    //不区分定时器种类

DOM基本操作

定义

一成套操作文档流相关的属性和方法

  • 操作元素修改样式
  • 操作元素修改属性
  • 操作元素改变位置
  • 操作元素添加事件

获取元素的方式

确定你要操作的是哪一个元素

  • 根据id名称获取
    1
    2
    3
    4
    5
    doctument.getElementByld('id名称')
    //作用:获取文档流中id名对应的一个元素
    //返回值:
    //如果有id对应的元素,就是这个元素。
    //没有就是null
  • 根据元素类名获取
    1
    2
    3
    4
    5
    document.getElementByClassName('元素类名')
    //作用:获取文档流中类名对应的一个元素
    //返回值:必然是一个伪数组
    //如果有类名对应的元素,有多少获取多少。
    //如果没有类名对应的元素,空的伪数组
  • 根据元素标签名获取
    1
    2
    3
    4
    5
    document.getElementByTagName('标签名')
    //作用:获取文档流中标签名对应的一个元素
    //返回值:必然是一个伪数组
    //如果有标签名对应的元素,有多少获取多少。
    //如果没有标签名对应的元素,空的伪数组。
  • 根据选择器获取一个
    1
    2
    3
    4
    5
    document.querySelector('选择器')
    //作用:获取文档流中满足选择器规则的第一个元素
    //返回值:
    //如果去选择器对应的元素,获取到第一个
    //如果没有选择器对应的元素,null
  • 根据选择器获取一组
    1
    2
    3
    4
    5
    document.querySeletorAll('选择器')
    //作用:获取文档流中满足选择器规则的所有元素
    //返回值:必然是一个伪数组
    //如果有选择器对应的元素,有多少获取多少。
    //如果没有选择器对应的元素,空的伪数组。

操作元素内容

  • 操作文本内容
    1
    2
    3
    4
    //获取
    元素.innerText
    //设置
    元素.innerText = '新内容'
  • 操作超文本内容
    1
    2
    3
    4
    //获取
    元素.innerHTML
    //设置
    元素.innerHTML = '新内容'

操作元素属性

  • 原生属性

    1
    2
    3
    4
    //获取
    元素.属性名
    //设置
    元素.属性名 = '属性值'
  • 自定义属性

    1
    2
    3
    4
    5
    6
    7
    //获取
    元素.getAttribute('属性名')
    //设置
    元素.getAttribute('属性名''属性值')
    //删除
    元素.removeAttribute('属性名')
    //以上方式一般不用于操作元素 类名和样式
  • 操作元素类名

    1
    2
    3
    4
    //获取
    元素.className
    //设置
    元素.className = '新类名'
  • 操作元素行内样式

    1
    2
    3
    4
    5
    //获取
    元素.style.样式名
    //设置
    元素.style.样式名 = '样式值'
    //只能获取和设置元素的行内样式
  • 获取元素非行内样式

    1
    2
    window.getComputedStyle(元素).样式名
    //可以获取行内样式,也可以获取非行内样式。

节点操作

  • 创建节点
    1
    2
    3
    document.createElenment('标签名称')
    //创建一个指定标签元素
    //返回一个创建好的元素节点
  • 插入节点
    1
    2
    3
    4
    5
    6
    7
    //语法一
    父节点.appendChild(子节点)
    //把子节点放在父节点的内部,并且放置在最后的位置

    //语法二
    父节点.insertBefore(要插入的子节点,哪一个子节点的前面)
    //把子节点放在父节点的内部,并且放在指定的某一个子节点前面。
  • 删除节点
    1
    2
    3
    4
    5
    6
    7
    //语法一
    父节点.removeChild(子节点)
    //从父节点删除某一个子节点

    //语法二
    节点.remove()
    //把自己直接删除
  • 替换节点
    1
    2
    父节点.replaceChild(换上节点,换下节点)
    //在父节点内,使用换上节点替换掉换下节点
  • 克隆节点
    1
    2
    3
    节点.conleNode(是否克隆‘后代’替节点)
    //把该节点复制一份一摸一样的内容
    //返回克隆后的新节点

获取元素尺寸

包括

  • 边框boder
  • 内边距padding
  • 内容content
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //语法一
    元素.offsetHeight
    元素.offsetwidth
    //获取 元素 内容 + padding + boder 区域的尺寸

    //语法二
    元素.clientHeight
    元素.clientWidth
    //获取 元素 内容 + padding 区域的尺寸

事件

前端通过代码的方式和页面中的某个内容做好一个约定
用户触发指定行为的时候,就会执行代码

事件绑定的三要素

  • 事件源:
    • 和谁做好约定
  • 事件类型:
    • 约定一个什么行为
  • 事件处理函数
    • 当用户触发该行为时,执行什么代码
      1
      事件源.on.事件类型 = 事件处理函数

事件类型

  • 鼠标事件
    • click - 鼠标单击
    • dbclick - 鼠标双击
    • contextmenu - 左键单击
    • mousedown - 鼠标按下
    • mouseup - 鼠标抬起
    • mousemove - 鼠标移动
    • mouseover - 鼠标移入
    • mouseout - 鼠标移出
    • mouseenter - 鼠标移入
    • mouseleave - 鼠标移出
  • 键盘事件
    • keydown - 键盘按下
    • keyup - 键盘抬起
    • keypress - 键盘键入
  • 浏览器事件
    • load - 加载完成
    • scroll - 滚动
    • resize - 尺寸改变
  • 触摸事件
    • touchstart - 触摸开始
    • touchmove - 触摸移动
    • touchend - 触摸结束
  • 表单事件
    • foucs - 聚焦
    • blue - 失焦
    • change - 改变
    • input - 输入
    • submit - 提交
    • reset - 重置

事件对象

当事件触发时,一个描述该事件信息的对象数据类型

事件对象内的信息

鼠标事件

  1. offsetX和offsetY
    • 相对于触发事件的元素
  2. client和clientY
    • 相对于浏览器可视窗口
  3. pageX和pageY
    • 相对于页面文档流
      键盘事件
  • 键盘编码

事件对象.keyCode

事件传播

浏览器响应事件的机制

  • 浏览器窗口最先知道事件的发生
  • 捕获阶段:从window按照结构子级的顺序传递到目标
  • 目标阶段:准确触发事件的元素接收到行为
  • 冒泡阶段:从目标按照结构父级的顺序传递到window
  • 本次事件传播结束

阻止事件传播

1
事件对象.stopPropagation()

事件委托

  • 利用事件冒泡的机制,把自己的事件委托给结构父级中的某一层

理解面向对象编程

面向对象编程就是通过构建一个能重复调用的函数,完成一种或一系列特定功能。这个函数所实现的功能就叫对象。而思考如何实现这个函数功能,并且编写下来的过程就叫做面向对象编程。

  • 实现面向对象编程的主力是自定义构造函数
    1
    2
    3
    4
    5
    6
    7
    var change = function (参数1,参数2,参数3){
    this.a(属性) = 参数一
    this.b = 参数二
    this.c = 参数三
    }
    var aaa = new change
    var bbb = new change
  • 该函数可以多次调用,用于快速创建新的变量(对象)
  • 必须和new连用才能发挥应有的作用

原型

  • 作用:由构造函数添加方法,专门给实例对象使用
  • 解决问题
    • 需要给实例对象内添加方法
    • 直接书写在构造函数体内
    • 这行为并不好
    • 原型是为了解决这个问题的
  • 不好的原因
    • 把方法书写在构造函数之内
    • 每次创建新的实例,都会创建一个函数数据类型
    • 多个函数方法,一样,但是占据了多份存储空间

如何优化代码,减少空间占用

构造函数原型

  • 每一个构造函数天生自带一个prototype属性,是一个对象数据类型
  • 每一个对象天生自带一个__proto__属性,指向所属函数的prototype
  • 访问对象成员的时候,首先在自己身上找,自己没有,则去自己的__proto__上找

如何解决问题?

  • 把需要给实例对像添加的方法,放到构造函数的原型prototype上

  • 实例通过自己的__proto__来访问自己所属构造函数的prototype来获取方法,而不用再创建一个新的函数来使用,也就不占用空间内存

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    fuction Person(){}
    //函数书写完毕,Person.prototype同时出现

    Person.prototype.a = 100
    //向 Person 的原型中添加成员 a

    var s1 = new Person()
    //创建一个新的实例对象,它属于构造函数 Person()
    // s1.__proto__ === Person.prototype

    consloe.log(s1.a)
    //访问对象成员的时候,首先在自己身上查找,自己没有,则去自己的__proto__查找,也就是 s1.__proto__.a === Person.prototype.a

    如果需要多次调用,且有不需要变动的方法或属性的代码,可以放到change函数的原型()中

  • 调用函数change时,如果有没有找到的方法或属性,会去原型里找。

1
2
3
change.prototype.方法名(属性名) = function () { 
console.log('我是 change 原型上的方法(属性)')
}

原型链

问题

  1. 实例对象身上的 proto 指向谁 ?
    • 指向所属构造函数的 prototype
    • s1 所属的构造函数是 Person
    • s1.proto 指向 Person.prototype
  2. Person.prototype 的 proto 指向谁 ?
    • Person.prototype 所属的构造函数是谁
    • 因为 Perosn.prototype 是一个对象数据类型(Object)
    • 在 JS 内所有的 Object 数据类型都是属于 Object 这个内置构造函数
    • Person.prototype 是属于 Object 这个内置构造函数的
    • Person.prototype 的 proto 指向 Object.prototype
  3. Person 的 proto 指向谁 ?
    => Person 是一个函数, 函数本身也是一个对象, 就会有 proto
    => 在 JS 内, 所有的函数都是属于内置构造函数 Function 的实例
    => Person.proto 指向 Function.prototype
  4. Object.prototype 的 proto 指向谁 ?
    • Object.prototype 是一个对象数据类型, 只要是对象, 都是数据 Object 这个内置构造函数的
    • 注意: Object.prototype 在 JS 内叫做顶级原型, 不在有 proto
    • Object.prototype 的 proto 指向 null
  5. Object 的 proto 指向谁 ?
    • Object 是内一个内置构造函数, 同时也是一个函数, 同时也是一个对象
    • 在 JS 内, 所以的函数都是属于内置构造函数 Function 的实例
    • Object 也是 Function 的实例
    • Object.proto 指向 Function.prototype
  6. Function.prototype 的 proto 指向谁 ?
    • Function.prototype 也是一个对象数据类型
    • 只要是对象数据类型都是 Object 的实例
    • Function.prototype 的 proto 指向 Object.prototype
  7. Function 的 proto 指向谁 ?
    • Function 也是一个内置构造函数, 也是一个函数
    • 在 JS 内, 所有的函数都是属于内置构造函数 Function 的实例
    • Function 自己是自己的构造函数
    • Function 自己是自己的实例对象
    • Function 所属的构造函数的是 Function

原型链

  • proto 串联起来的对象链状结构
  • 注意: 使用 proto
  • 每一个对象数据类型, 都有一个属于自己的原型链
  • 作用: 为了访问对象成员

对象访问机制:

  • 当你需要访问对象的成员的时候
  • 首先在自己身上查找, 如果有直接使用
  • 如果没有, 会自动去 proto 上查找
  • 如果还没有, 就再去 proto 上查找
  • 直到 Object.prototype 都没有, 那么返回 undefined