HTML5

HTML5

跨域

跨域的原因:浏览器的同源策略导致
同源策略要求:网页中利用ajax发送请求时,目标服务器的域名 端口号 协议 都与当前网页相同

同源: 协议 + 域名 + 端口号 三者都相同
协议://域名:端口号 比如 http://localhost:3000
协议:http; 域名:localhost; 端口号:3000;

网页的开发方案分两类:

  • 前后端不分离: 由服务器完成所有任务, 服务器存在极大的压力
  • 前后端分离: 服务器负责查数据库, 浏览器服务器拼接成html; 服务器把拼接HTML的任务分离出去, 自身压力减轻, 更适合当前场景.

跨域的解决方案主流存在3种

  • CORS: 最推荐 - 在服务器上增加白名单 允许其他来源的访问
  • JSONP: 利用 脚本的 src 发请求不存在跨域限定 来解决问题
    • 缺点: 仅适用于 GET 请求
  • PROXY: 代理

解决方案(三种)

cors

在服务器中为响应头添加Access-Control-Allow-Origin,允许其他来源访问

JSONP

代理方案: 不需要在服务器上进行修改, 前端人员自己就能解决跨域

  • 1.JSON Padding 利用 脚本的src属性请求数据 这种方式不存在跨域限定
  • 2.需要在请求地址中,利用参数传递回调函数的名字<script src=“xxxx?callback=函数名”>
  • 3.服务器中,需要把数据拼接到 回调函数中 res.send(callback + ( + ' JSON数据 ' )')
  • 特点: 仅支持GET请求 + 仅支持JSON格式数据的传递
proxy

代理模式. 仅需要前端解决. 无需修改服务器代码

  • 过程: html --请求1–> express服务器 —请求2–> 斗鱼服务器
  • 请求1: 存在跨域问题; 请求2: 无跨域问题, 服务器之间的交互.
  • 代理方案: 不需要在服务器上进行修改, 前端人员自己就能解决跨域

XSS: 跨站脚本攻击

英文名: Cross Site Script Attack

理论上简写是: CSS, 但是这个名称和 层叠样式表的缩写重名, 所以改为 XSS

我们的网站中, 如果使用了来自其他网站提供的脚本代码 – 是不安全的做法

如果脚本代码中存在恶意代码, 会导致网站被攻击!!

总结: 不要使用不受信任的网站提供的脚本, 应该从官方下载

最好把脚本下载到本地使用, 而不是使用远程脚本. 有效防止远程脚本变更导致的安全性问题!!

文件上传

利用multer模块方案

需要利用 uuid 模块生成唯一的文件名保存到服务器中

前端部分

Form

form表单方式能够实现文件上传 但是限制很多

  • 上传文件大小受限
  • 上传速度慢
  • 不支持断点续传
  • 不支持上传进度显示
 <!-- 文件上传的最基本方案: Form表单方案 -->
  <!-- action: 当提交操作触发时, 内容传递的地址 -->
  <!-- entype: 编码类型. 如果文件上传则必须是 multipart/form-data -->
  <form action="http://localhost:3000/avatar" method="post" enctype="multipart/form-data">
    <!-- 这里的name属性, 就是服务器接口的 upload.single(参数) 的参数 -->
    <input type="file" name="avatar" id="">
    <button>开始上传</button>
  </form>

app.js 服务器代码

  <!-- 使用时, 不允许用 live server !!  自带刷新效果 会出现问题 -->
  <!-- 要使用 localhost:3000 的方案来访问 -->
<script src="https://api.xin88.top/js/jquery-3.6.1.min.js"></script>

const express = require('express');
const cors = require('cors'); // 跨域模块

// multer: 负责处理上传文件
const multer = require('multer');
// uuid : 用于生成不重复的 由英文组成的字符串, 适合做文件的唯一名称
const uuid = require('uuid');

const app = express()

app.use(cors())
app.use(express.static('public'))
// 允许 上传文件夹 中的内容, 被外部访问
app.use(express.static('upload'))

// multer 创建负责处理上传文件的对象
const upload = multer({
  // ctrl + i : 查看提示

  // dest -> destination 目标,目的地
  // 代表上传文件存储的位置 - 目录/文件夹
  // 此目录如果不存在,会自动创建
  // dest: 'upload', 

  // 默认的上传设定: 会把文件重用名, 但是没有后缀名, 导致文件无法查看

  // storage: 可以个性化对上传的文件 的保存方式进行定制
  storage: multer.diskStorage({
    destination: 'upload', //配置保存的目录
    // 用于接收上传的内容, 然后给出文件存储时的名称
    filename(req, file, cb) {
      console.log('文件信息:', file);
      // 读取上传的文件名
      const { originalname } = file
      // 从原名称中截取后缀名的部分
      const i = originalname.lastIndexOf('.')
      // 截取 . 开始的内容
      const ext = originalname.substring(i) // .jpg  .png ...这种

      // 生成唯一名称
      const unique_name = uuid.v4() + ext // v4 是最常用的方案
      console.log('唯一名称:', unique_name);

      // cb : callback缩写, 回调函数. 通过此函数设置文件的存储名称
      // cb(错误信息, 文件存储时的名称)
      cb(null, unique_name)
      // 参数1: null 代表没有错误

      // 直接采用原文件名存在两个BUG
      // 1. 中文文件名 会乱码
      // 2. 同名文件 会覆盖
    }
  })
})


app.listen(3000, () => {
  console.log('服务器已开启, 端口3000');
})

// 制作接口, 用与接收用户上传的头像图片
// 上传操作要求 必须为 POST 方案

// single: 单个,单独的;  代表要处理单文件上传
// 'avatar' : 代表通过post传递的数据中, 名字是avatar的是文件类型,需要处理
app.post('/avatar', upload.single('avatar'), (req, res) => {
  console.log(req.file)

  res.send(req.file)
})

DOM方案

  • 利用DOM方式可以实现更加自定义的上传方式
  • 需要把文件的信息存储在FormDate类型的对象里
  • 使用jQuery的ajax方法实现
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>首页</title>

  <style>
    #progress {
      height: 20px;
      background-color: #aaa;
      width: 200px;
    }

    #progress>#thumb {
      height: 100%;
      background-color: orange;
      width: 0%;
      transition: 0.1s;
    }
  </style>
</head>

<body>
  <h1>Welcome To Express!</h1>

  <!-- 用DOM的方式, 可以实现更加灵活的上传 -->
  <input type="file">
  <br>
  <button id="upload">上传文件</button>

  <div id="progress">
    <div id="thumb"></div>
  </div>

  <img src="" alt="">

  <!-- 运行时 必须用 localhost:3000 -->
  <!-- 因为live server 自带刷新, 与上传操作有冲突! -->

  <script src="https://api.xin88.top/js/jquery-3.6.1.min.js"></script>
  <script>
    // 思路: 点击上传按钮后, 获取 上传文件 的信息, 通过结果传递给服务器
    $('button#upload').click(function () {
      // 查看文件上传元素中的值
      // console.log($(':file'))
      // files属性: 存储文件上传的信息
      const files = $(':file').prop('files')
      console.log('files:', files)

      // 1. 先检查上传文件的个数, 如果是0个 则可以弹出提醒
      if (files.length == 0) {
        alert("请先选择文件, 再进行上传操作")
        return
      }

      // 2. 限制只能传递 图片类型的文件
      // type 的值中 含有 image 字样, 就是图片类型. 反之 不含有image 就不是图片
      // indexOf() : 值 -1 代表找不到
      if (files[0].type.indexOf('image') == -1) {
        alert("只允许图片类型文件的上传!!")
        return
      }

      // 大小检测: 只允许上传 2M 以内文件
      // 2MB = 2*1024KB = 2 * 1024 * 1024B
      if (files[0].size > 2 * 1024 * 1024) {
        alert("只允许上传2M以内的文件!")
        return
      }

      // 需要把文件数据封装到 FormData 类型的对象中, 才能被服务器接收
      const fd = new FormData()
      // 利用 append 方法 把文件数据添加到 fd 中
      fd.append('avatar', files[0])
      // 参数1: 数据的名字, 相当于 <input type='file' name="avatar"> 中的name属性. 服务器接口中会点名接收此属性的值

      // 利用POST方式进行上传
      // 需要使用更加自定义的 ajax 方法实现
      $.ajax({
        // ctrl+i: 可以查看可选的配置项
        url: 'http://localhost:3000/avatar', //接口地址
        type: 'post', //请求类型
        data: fd, // 传输的数据
        // 内容类型: false代表不允许更改,采用原始数据类型;  
        // 默认会自动更改为 字符串类型
        contentType: false,
        // 数据编码方式: false代表不对数据进行编码, 保持原有状态.
        processData: false,

        // 监听上传进度
        xhr() {
          // 提供自定义的xhr 对象实现网络操作, 可以添加进度的监听
          var xhr = new XMLHttpRequest()
          // progress事件: 当上传进度发生变化时触发
          xhr.upload.addEventListener('progress', e => {
            // 事件参数 e 中, 包含本次事件的相关信息
            // console.log('事件参数:', e);

            // 总大小, 已加载大小
            const { total, loaded } = e

            const num = loaded / total;
            const percentage = (num * 100).toFixed(0) + '%';
            console.log(percentage);

            console.log('加载进度:', percentage);
            $('#thumb').width(percentage)
          })

          return xhr
        },

        // 上传完毕后的回调函数
        success(data) {
          console.log('上传结果:', data)
          // 读取存储在服务器上的文件名
          const { filename } = data
          // 把存储在服务器上的文件, 用 img 标签进行展示
          $('img').prop('src', `http://localhost:3000/${filename}`)
            .height(100)
        }
      })
    })
  </script>
</body>

</html>

拖拽操作

  • 由HTML5 提供的新的交互方式, 其中 超链接 和 图标 默认支持拖拽, 其他元素不支持, 需要添加 draggable="true" 来开启
  • 7个事件
    • 3个与被拖拽元素相关
      • dragstart:开始拖拽
        • 事件参数中的数据传输者: dataTransfer 可以存储一些数据, 可以在7个事件中获取
          • setData(‘text’, 内容) : 用于存储文本信息
          • getData(‘text’) : 用于获取文本信息
      • drag: 拖拽中
      • dragend: 拖拽结束
    • 4个与拖拽元素 路过的元素相关
      • dragenter: 进入
      • dragover: 在上方
        • 阻止默认事件: 例如 超链接 和 图片 默认在放下时, 会在新标签中打开. 如果希望自定义效果, 则需要阻止默认操作: e.preventDefault()
      • dragleave: 离开
      • drop: 放下

拖拽方式实现多文件上传

  • 在 dragover 和 drop 方法中, 要调用 preventDefault 阻止默认行为, 否则会在新标签中开启
  • 文件信息存储在 dataTransfer.files 属性里
  • 多文件接口的制作:
    • 使用 array 方法: upload.array('avatars'), 保存后的信息存储在 req.files 属性里

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>首页</title>
    <style>
        #box1 {
            height: 200px;
            background-color: #aaa;
        }

        #box2 {
            height: 100px;
            background-color: orange;
        }
    </style>
</head>

<body>
    <h1>Welcome To Express!</h1>
    <!-- HTML5 提供的新的交互方式:拖拽 -->
    <!-- 超链接 和 图片 标签 默认支持拖拽操作 默认行为:在新的标签中开启 -->
    <a href="http://baidu.com">百度一下</a>
    <br>
    <img height="200" src="https://web.codeboy.com/image/index/banner.png" alt="">
    <!-- 默认不支持拖拽的元素  可以添加 draggable="true" 让元素允许被拖拽,但是没有默认行为 -->
    <p draggable="true">Lorem, ipsum dolor sit amet consectetur adipisicing elit. Suscipit dicta blanditiis nam magni
        eaque obcaecati
        repudiandae odit voluptas culpa ut tempore possimus, excepturi facere eos vero ullam esse! Soluta, perferendis?
    </p>

    <hr>
    <div id="box1">
        <a href="">百度一下</a>
        <a href="">京东</a>
        <a href="">Tmooc</a>
    </div>
    <div id="box2">

    </div>
    <script src="https://api.xin88.top/js/jquery-3.6.1.min.js"></script>
    <script>
        // 拖拽相关事件:
        $('#box1>a')
            .on('dragstart', function (e) {
                console.log('dragstart: 开始拖动', e);

                // dataTransfer : 数据传输者 - 用于存储一些数据传递给其他事件
                // 把当前拖动的 标签的序号 保存在数据传输者中
                const i = $(this).index()
                // setData(数据类型, 数据本身):用于存储值
                // 'text': 固定写法 代表数据是文本类型
                e.originalEvent.dataTransfer.setData('text', i)
            })

            // .on('drag', function(e) {
            //     e.preventDefault()  // 阻止默认行为
            //     // 存在两种触发形式:1.拖动时 2.不动 每隔0.3s自动触发一次
            //     // console.log('drag: 拖动中...');
            // })

            // .on('dragend', function() {
            //     console.log('dragend: 结束拖动');
            // })

        // 当有被拖动的元素进入自身时
        $('#box2')
            // .on('dragenter', function() {
            //     console.log('dragenter:有拖拽元素进入');
            // })

            .on('dragover', function(e) {
                // 在box2上经过时,阻止拖拽元素的默认行为 在新标签中打开
                // prevent:阻止    default:默认
                e.preventDefault()  // 阻止默认行为

                console.log('dragover:拖拽元素在自身内部');
            })

            // .on('dragleave', function() {
            //     console.log('dragleave:拖拽元素离开自身范围');
            // })

            .on('drop', function(e) {
                console.log('drop:有元素被放下');
                // 检测被放下的元素是哪个 把这个元素添加到 #box2 中

                // 读取事件传输者中保存的 文本类型的数据内容
                const i = e.originalEvent.dataTransfer.getData('text')
                console.log('被拖拽元素的序号:', i);

                // 通过序号找到被拖拽的元素
                const $a = $('#box1>a').eq(i);
                // 添加到 #box2 里
                $('#box2').append($a)
            })


            // 扩展作业:能够从box2中拖拽到 box1
            $('#box1')
                .on('dragover', function(e) {
                    e.preventDefault()   // 阻止默认,防止在新标签打开
                })
                .on('drop', function(e) {
                    // 读取数据传输者中携带的文本信息:当前元素的序号
                    const i = e.originalEvent.dataTransfer.getData('text');
                    console.log({ i });

                    $('#box1').append(
                        $('#box2>a').eq(i)
                    )
                })
    </script>
</body>

</html>

Canvas: 画布

  • HTML5提供的标签, 带有一套绘制图形的工具库, 可以利用JS把数据实时转换成图片
  • 使用场景: 地图 / 图表 / 3D图形 / 网页游戏
  • 这个API 是给 高级程序员使用的, 可以基于此API封装库

ECharts

官网

  • 生产力工具: 实际开发中 可以用于解决问题的工具
  • ECharts 是基于 Canvas 制作的一个 JavaScript图表库, 可以更简单的绘制各种优秀的图表

SVG

HTML5提供的另一种图形绘制方案, 采用 DOM 的方式绘制图形. 提供更佳的交互体验

SVG属于矢量图, 在放大缩小时不会失真

  • 矢量图: 放大缩小都不失真, 因为是实时生成的.
  • 可交互: 图片的每个部分都是DOM元素, 可以进行灵活的交互
    • 例如 影院的选座, 飞机的选座

Promise

  • 解决回调地狱问题: 传统的回调函数方案解决异步操作问题时, 如果要确保多个异步操作按照指定的顺序执行,就需要在回调函数中触发下一次异步操作, 会导致层层嵌套.

  • ES6提供的 解决回调地狱问题的 构造函数

  • 三种状态:

    • pending: 就绪. new Promise() 之后
    • rejected: 拒绝/失败. 触发 reject 之后
    • fulfilled: 满足/成功. 触发 resolve 之后

    设定: 状态只能从 pending 转为其他两种之一. 不可逆

  • 4个静态方法

    • all: 多个Promise完成后. 必须都是 fulfilled 状态
    • allsettled: 多个Promise状态敲定后. 对状态无要求
    • race: 多个Promise中,哪个先完成就执行那个
    • any: 多个Promise中, 任何一个状态敲定即可

async 和 await

await和async 是 ES7 中提供的新特性, 解决异步操作的语法问题
ES7: 提供语法糖 await 和 async, 是简化 Generator 语法的

在ES6的范围内有三种方案解决异步操作问题:
1. 回调函数: 问题-回调地狱
2. Promise: 问题- then的链式语法导致代码过长
3. Generator: ES6提供的新语法,但是由于格式复杂,使用较少

<script>
    function get(url) {
      return new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest()
        xhr.open('get', url)
        xhr.send()
        xhr.onload = function () {
          var data = JSON.parse(xhr.response)
          resolve({ data }) // 触发then
        }
        xhr.onerror = function () {
          reject(xhr.response)
        }
      })
    }

    var url1 = 'https://serverms.xin88.top/mall?page=1'
    var url2 = 'https://serverms.xin88.top/mall?page=2'
    var url3 = 'https://serverms.xin88.top/mall?page=3'
    var url4 = 'https://serverms.xin88.top/mall?page=4'
    var url5 = 'https://serverms.xin88.top/mall?page=5'

    // 固定规范: 把异步操作放到一个函数中, 函数必须用 async 来修饰
    // async:异步    await:等待
    async function getData() {
      // await只能书写在 用 async 修饰的函数中
      // 代表 等待 后方Promise的 then 结果, 触发resolve
      const res1 = await get(url1)
      console.log({ res1 })

      const res2 = await get(url2)
      console.log({ res2 })

      const res3 = await get(url3)
      console.log({ res3 })

      const res4 = await get(url4)
      console.log({ res4 })

      const res5 = await get(url5)
      console.log({ res5 })
    }

    getData()

    // 利用 try...catch 抓取报错信息
    async function fetchData() {
      try {
        const res1 = await get(url1)
        const res2 = await get(url2)
        console.log({ res1, res2 })
      } catch (error) {
        console.log({ error });
      }
    }

    fetchData()
  </script>

fetch

 <!-- 
    关于网络操作浏览器提供了两种方案:
    1. XHR: XMLHttpRequest.  属于早期方案
       -- 利用 回调函数 方式实现异步操作
    2. fetch: ES6提供的新的请求方式
       -- 利用 Promise 方式实现的异步操作
   -->

  <script>
    var url1 = 'https://serverms.xin88.top/mall?page=1'

    fetch(url1).then(res => {
      console.log(res)
      // 利用 json() 获取其中的数据, 这也是异步操作, 需要用then获取解析的结果
      res.json().then(data => {
        console.log({ data })
      })
    })

    // 链式语法:
    fetch(url1).then(res => {
      return res.json()
    }).then(data => {
      console.log({ data });
    })

    // 利用箭头函数语法糖进一步简化
    fetch(url1).then(res => res.json()).then(data => {
      console.log({ data })
    })

    // 总结: 关于网络接口中数据的获取
    // 官方提供两种方案:
    // 1. xhr: 利用回调
    // 2. fetch: 利用Promise

    // 非官方的方案:
    // 1. 自己封装
    // 2. 第三方封装的, 例如 axios , jQuery 等...

WebWorker

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>WebWorker 10:45</title>
</head>

<body>
  <h1 id="time"></h1>

  <!-- src方式引入外部js文件, 属于同步操作, 需要把js中的代码执行一遍 -->
  <!-- <script src="06.js"></script> -->

  <script>
    // worker: 创建一个新的`工人` 帮你去操作外部js文件中的代码 ,属于微任务
    // 不会影响到 宏任务代码的执行, 不会卡顿
    new Worker('./06.js')

    // 用户体验优化的一种方案: 耗时操作用 worker 执行即可

    // 定时器 属于 异步操作 ->  微任务队列:  支线  优先级低
    setInterval(() => {
      time.innerHTML = new Date().toLocaleTimeString()
    }, 1000);

    // WebWorker: 用于把某些JS代码 主动放到异步中执行, 即放到微任务中, 不反感主线任务的操作

    // 1个操作复杂的函数,会消耗很多时间
    // function wasteTime(n) {
    //   return n < 3 ? 1 : wasteTime(n - 1) + wasteTime(n - 2)
    // }

    // console.log(
    //   wasteTime(46) // 属于主线任务 - 宏任务
    //   // 必须执行完毕 才能执行其他的 微任务
    // )

    // JS代码的运行机制: 事件循环
    // 所有代码会排队执行
  </script>
</body>

</html>
// 06.js
function wasteTime(n) {
  return n < 3 ? 1 : wasteTime(n - 1) + wasteTime(n - 2)
}

var res = wasteTime(46)

console.log({ res })
// 发送消息: 此操作会触发 worker 的 onmessage 事件
postMessage({ res })

监听结果

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>webworder 11:21</title>
</head>

<body>
  <h1>运行结果: <span id="result"></span></h1>

  <script>
    // 当前: 不需要反馈信息
    // 现在: 需要 worker 执行完毕后, 告知执行结果
    const worker = new Worker('./06.js')

    // 监听woker发送的信息
    worker.onmessage = function (e) {
      console.log('来自worker的消息:', e);

      result.innerHTML = e.data.res
    }
  </script>
</body>

</html>

事件循环: EventLoop

宏任务都做完 才能执行微任务

  • 任务是任务执行时产生的
  • 必须 宏任务 都做完, 再执行微任务
  • 微任务 都是 异步操作
    • 回调函数 : 定时器的
    • promise的 then
    • await 下方的那个代码, 需要等 await 执行完毕

defineProperty: 属于比较高级的知识点

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>defineProperties 14:22</title>
</head>

<body>
  <script>
    'use strict'

    var stu = {
      sname: "楠楠",
      age: 18,
      sid: '200703012',
      phone: '10084'
    }
    // 要求: 把每个属性 都改成不可重新赋值
    // Object.defineProperty(stu, 'sname', { writable: false })
    // Object.defineProperty(stu, 'age', { writable: false })
    // Object.defineProperty(stu, 'sid', { writable: false })
    // Object.defineProperty(stu, 'phone', { writable: false })

    // defineProperties: 一次性为多个属性进行配置
    Object.defineProperties(stu, {
      // 属性名: { 配置项 }
      sname: { writable: false },
      age: { writable: false },
      sid: { writable: false },
      phone: { writable: false },
    })

    stu.sname = 11
    stu.age = 11
    stu.sid = 11
    stu.phone = 11

    console.log(stu)
  </script>
</body>

</html>

为对象属性提供自定义设定

  • 属于 高级程序员 在封装框架时使用的知识点, 面试时经常考
  • 6个配置项

writable : 可写

configurable: 可配置

<script>
    'use strict'

    const boy = {
      name: "凯凯",
      girl: "倩倩"
    }

    Object.defineProperty(boy, 'girl', {
      writable: false,
      // 可配置的: 可以重新配置权限, 可以删除元素
      configurable: false, // false 代表不可以

      // 通常: 不可写 和 不可重新配置 搭配使用, 才能最安全
    })

    // 两种方案可以突破不可写的限制
    // 1. 改成可写
    // 2. 删除属性, 再新增
    // Object.defineProperty(boy, 'girl', { writable: true })

    delete boy.girl // 删除属性
    boy.girl = '翠花' // 这里是新增操作

    console.log(boy)
  </script>

enumerable: 可遍历

<script>
    var emp = {
      ename: "凯凯",
      age: 28,
      phone: "18345422334",
      eid: '000454',
      salary: 30000, // 薪资保密: 不可以被for..in遍历到
    }

    Object.defineProperty(emp, 'salary', {
      enumerable: false, // 是否可以被遍历
    })

    // 在 Chrome 中, 不可遍历的属性以浅色显示
    console.log(emp)

    // 遍历对象: for...in
    for (const key in emp) {
      console.log(key, emp[key])
    }
  </script>

value: 默认值

<script>
    'use strict'

    var emp = { ename: '凯凯' }

    // 通过 define 方式新增属性
    // 如果emp中存在age属性, 则为修改操作
    // 如果emp中不存在age属性, 则为新增操作
    Object.defineProperty(emp, 'age', {
      value: 33,
      writable: true, //必须手动开启权限,才能赋值
    })
    // 此方式新增的属性, 默认的权限配置都是最低的: 不可写,不可配置,不可遍历

    console.log(emp)

    emp.age = 20
  </script>

get: 计算属性

 <script>
    var r1 = {
      width: 100,
      height: 20,
      // 语法糖: get
      // 在 无参数的函数 前方添加get关键词, 这个函数称为计算属性
      // 在使用时不需要() 就能自动触发
      get area() {
        return this.width * this.height
      }
    }

    console.log(r1)

    // console.log(r1.area())
    console.log(r1.area) // 使用时 宛如在 读取属性的值, 更加直观


    ///////////////////////////////////////////
    // 练习: 立方体
    var c1 = {
      length: 20,
      width: 40,
      height: 50,
      get volume() {
        return this.width * this.height * this.length
      }
    }

    // 使用 define 的方式增加计算属性:
    Object.defineProperty(c1, 'perimeter', {
      get() {
        return (this.length + this.width + this.height) * 4
      }
    })

    Object.defineProperty(c1, 'area', {
      get() {
        return 2 * (this.length * this.width + this.length * this.height + this.width * this.height)
      }
    })

    // 要求: 添加计算属性, 用于计算出 体积 面积 和 周长
    console.log(
      c1.volume, // 长x宽x高
      c1.area, // (长x宽 + 长x高 + 宽x高)x2
      c1.perimeter, // (长+宽+高)*4
    );
  </script>

set: 赋值监听

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值