1.深入对象

  • 构造函数

    • 用来初始化对象
    • 可以通过构造函数快速创建多个类的对象
    • 约定:命名以大写字母开头,只能由 new 关键字来执行
    // 创建构造函数
    function Person(name, age){
        this.name = name;
        this.age = age;
    }
    console.log(new Person("马浩楠", 22));
    console.log(new Person("浩楠", 22));
    
    • 说明
      • 使用 new 关键字调用函数的行为被称为实例化
      • 实例化构造函数时没有参数时可以省略 ()
      • 构造函数内部无需写 return,返回值即为新创建的对象
  • 练习

image-20230810204053418.png

function Goods(name, price, count){
    this.name = name;
    this.price = price;
    this.count = count;
}
const goods = [
    new Goods("小米", 1999, 20),
    new Goods("华为", 3999, 59),
    new Goods("vivo", 1888, 100)
]
goods.forEach(item => {
    console.log(item)
})
  • 实例成员

    • 通过构造函数创建的对象称为实例化,实例化对象中的属性和方法称为实例成员
    function Person(){
        // 实例属性
        this.name = '小明'
        // 实例方法
        this.sayHi = function(){
            console.log("Hello")
        }
    }
    
  • 静态成员

    • 构造函数的属性和方法被称为静态成员
    function Person(name, age){
        // 实例成员
    }
    // 静态属性
    Person.eyes = 2
    // 静态方法
    Person.walk = function(){
        console.log("走路...")
    }
    

2.内置构造函数

基本数据类型:字符串、数值、布尔、undefined、null

引用类型:对象

  • Object

    • Object.keys() 静态方法获取对象中所有的属性名【返回数组】
    • Object.values() 静态方法获取对象中所有的属性值【返回数组】

    • Object.assign() 静态方法常用于对象拷贝【返回拷贝后对象】

    const obj = {userName: "马浩楠", age: 22};
    // 1.获取所有的属性名
    console.log(Object.keys(obj));
    // 2.获取所有的属性值
    console.log(Object.values(obj));
    // 3.copy对象
    const o = {};
    Object.assign(o,obj);
    console.log(o)
    
    // 追加属性
    Object.assign(obj, {gender: "男"})
    console.log(obj)
    
  • Array

    • 数组常见实例方法-核心方法

image-20230810204106908.png

  • reduce

    // arr.reduce(function(上一次的值, 当前值), 初始值){}
    const arr = [1, 5, 8];
    // 无初始值
    const num = arr.reduce((previous, current) => previous + current);
    console.log(num); // 14
    
    // 有初始值
    const total = arr.reduce((previous, current) => previous + current, 10);
    console.log(total) // 24
    
    //不存在初始值,则初始值为数组第一个元素
    
  • 常见数组方法——其它

image-20230810204200760.png

  const arr = [
      {
          name: "小米",
          price: 1999
      },
      {
          name: "华为",
          price: 3999
      }
  ]
  // find:找到 name = 小米的这个对象
  const xiaomi = arr.find(item => item.name == "小米");
  console.log(xiaomi)


  // every:每一个是否都符合条件,一个不符合就为false
  const arr1 = [10, 20, 30];
  const flag = arr1.every(item => item > 20)
  console.log(flag)
  • Array.from():伪数组转真数组

    <body>
      <ul>
          <li>1</li>
          <li>2</li>
          <li>3</li>
      </ul>
      <script>
          const lis = document.querySelectorAll("ul li");
          // lis 伪数组 =》 真数组
          const liss = Array.from(lis);
          console.log(liss)
      </script>
    </body>
    
  • String

    • 常见实例方法

image-20230810204126270.png

  // split:字符串转数组
  const str = "blur,red,green";
  const arr = str.split(",");
  console.log(arr);

  // 2.substring:截取字符串  包前不包后
  const str1 = "今天又要做核酸了";
  console.log(str1.substring(4,8)) // 做核酸了
  console.log(str1.substring(4)) // 做核酸了
  // 省略结束的索引号,则意为从当前索引号截取到最后

  // 3.startsWith:是否以...开头 true/false
  const str2 = "我正在学习JS";
  console.log(str2.startsWith("我")) // true
  console.log(str2.startsWith("学习")) // false
  console.log(str2.startsWith("学习",3)) // true

  // 4.includes:判断是否包含某一段字符(区分大小写)
  const str3 = "我正在学习代码";
  console.log(str3.includes("学习")); // true
  console.log(str3.includes("学习",4)); // false
  • 练习

image-20230810204133861.png

  <body>
      <div></div>
      <script>
          const gift = "50g的茶叶,清洗球";
          // 拆分数组并添加span标签
          const str = gift.split(",").map(item => `<span>【赠品】 ${item} </span> <br/>`).join("");
          // 渲染
          document.querySelector("div").innerHTML = str;
      </script>
  </body>
  • Number

    • toFixed() 设置保留小数位长度【四舍五入】
    // 数值类型
    const price = 12,345
    // 保留两位小数 四舍五入
    console.log(price.toFixed(2)); // 12.35
    

3.综合案例

image-20230810204229625.png

<body>
  <div class="list">
    <!-- <div class="item">
      <img src="https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg" alt="">
      <p class="name">称心如意手摇咖啡磨豆机咖啡豆研磨机 <span class="tag">【赠品】10优惠券</span></p>
      <p class="spec">白色/10寸</p>
      <p class="price">289.90</p>
      <p class="count">x2</p>
      <p class="sub-total">579.80</p>
    </div> -->
  </div>
  <div class="total">
    <div>合计:<span class="amount">1000.00</span></div>
  </div>
  <script>
    const goodsList = [
      {
        id: '4001172',
        name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',
        price: 289.9,
        picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',
        count: 2,
        spec: { color: '白色' }
      },
      {
        id: '4001009',
        name: '竹制干泡茶盘正方形沥水茶台品茶盘',
        price: 109.8,
        picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',
        count: 3,
        spec: { size: '40cm*40cm', color: '黑色' }
      },
      {
        id: '4001874',
        name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',
        price: 488,
        picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',
        count: 1,
        spec: { color: '青色', sum: '一大四小' }
      },
      {
        id: '4001649',
        name: '大师监制龙泉青瓷茶叶罐',
        price: 139,
        picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',
        count: 1,
        spec: { size: '小号', color: '紫色' },
        gift: '50g茶叶,清洗球'
      }
    ]
    const box = document.querySelector(".list");
    let totalMoney = 0;
    const str = goodsList.map(item => {
      const name = item.gift == undefined ? "" : item.gift.split(",").map(item => `<span class="tag"> 【赠品】${item}</span>`).join("");
      const spec = Object.values(item.spec).join("/");
      totalMoney += item.price * item.count;
      totalMoney.reduce
      return `
        <div class="item">
          <img src=${item.picture} alt="">
          <p class="name">${item.name+name}</p>
          <p class="spec">${spec}</p>
          <p class="price">${item.price}</p>
          <p class="count">x${item.count}</p>
          <p class="sub-total">${(item.price * item.count).toFixed(2)}</p>
        </div>
      `
    }).join("");
    box.innerHTML = str;
    document.querySelector(".amount").innerHTML 
    = goodsList.reduce((previous, current) => {
      console.log(previous+"......"+(current.price * current.count).toFixed(2))
      return (+previous + current.price * current.count).toFixed(2)
    }, 0);
  </script>
</body>

4.构造函数【问题】

  • 封装是面向对象思想中比较重要的一部分,js 面向对象可以通过构造函数实现的封装
  • 存在浪费内存的问题
function Star(name, age){
    this.name = name;
    this.age = age;
    this.sing = function(){
        console.log("我会唱歌");
    }
}
const ldh = new Star("刘德华", 18)
const zxy = new Star("张学友", 19)
console.log(ldh.sing === zxy.sing) // false
// 说明两个函数不一样,表示每一个实力对象该对象的方法都会分配新的内存

5.原型

  • 原型

    • 构造函数通过原型分配的函数是所有对象所 共享的
    • JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象,所有我们也称为原型对象
    • 这个对象可以挂载函数,对象实例化不会多次创建原型,节约内存
    • 可以吧那些不变的方法,直接定义在 prototype 对象上,所有对象的实例就可以共享这些方法
    • 构造函数和原型对象中的 this 都指向实例化的对象
    function Star(name, age){
        this.name = name;
        this.age = age;
    }
    console.log(Star.prototype) // 放回一个对象称为原型对象
    Start.prototype.sing = function (){
        console.log("我会唱歌")
    }
    const ldh = new Star("刘德华", 18)
    const zxy = new Star("张学友", 19)
    console.log(ldh.sing === zxy.sing) // true
    
  • 练习

image-20230810204241242.png

const arr = [1, 2, 3];
// 这个方法,每个实例数组对象都可以使用
// 1.求和
Array.prototype.sum = function(){
    return this.reduce((previous, current) => previous + current);
}
console.log(arr.sum());
// 2.求最大值
Array.prototype.max = function(){
    return Math.max(...this);
}
console.log(arr.max());
  • constructor 属性

    • 每个原型对象里都存在 constructor 属性
    • 该属性指向该原型对象的构造函数

image-20230810204248162.png

  • 使用场景:如果有多个对象的方法,我们可以给原型对象采取对象形式赋值,但是会覆盖构造函数原型对象原来的内容.通过修改该后的原型对象中,添加 constructor 指向原来的构造函数

    function Star(){
    
    }
    Star.prototype = {
      // 重新指回创造这个原型对象的 构造函数
      constructor: Star,
      sing: function(){
          console.log("唱歌");
      },
      dance: function(){
          console.log("跳舞");
      }
    }
    console.log(Star.prototype); // Object { constructor: Star(), sing: sing(), dance: dance() }
    
  • 思考

image-20230810204255434.png

  • 对象原型

    • 每个对象都会有一个属性![image-20230810204304040.png]8.png指向构造函数的 prototype 原型对象,之所有对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象存在 proto 的存在
    • 注意点
      • proto 是JS非标准属性
      • [[prototype]] 和 proto 意义相同
      • 用来表示当前实例对象指向哪个原型对象prototype
      • proto 对象原型里面也有一个 constrcutor 属性,指向创建该实例对象的构造函数

image-20230810204304040.png

  function Star(){

  }
  const ldh = new Star();
  // 对象原型 __proto__ 指向 该构造函数的原型对象
  console.log(ldh.__proto__ === Star.prototype); // true
  // 对象原型里面存在 constructor指向 构造函数
  console.log(ldh.__proto__.constructor === Star); // true
  • 原型继承

    function Man(){
        this.head = 1;
        this.eyes = 2;
        this.say = function(){
    
        }
    }
    function Woman(){
        this.head = 1;
        this.eyes = 2;
        this.say = function(){
    
        }
    }
    
    • 封装-——抽取公共部分
    const People = {
        head: 1,
        eyes:2,
        this.say = function(){
    
        }
    }
    function Man(){
    
    }
    function Woman(){
        this.baby = function(){
    
        }
    }
    
    • 继承

      • 将公共的属性和方法抽取出来
      • 赋值给Man的原型对象,可以共享这些属性和方法
      • 注意让constructor指回Man构造函数
      const People = {
          head: 1,
          eyes:2,
          this.say = function(){
      
          }
      }
      function Man(){
      
      }
      // 吧公共的属性和方法给原型对象,这样就可以共享了
      Man.prototype = People
      // 注意让原型里面的 constructor 从新指回 Man 自己的构造方法
      Man.prototype.constructor = Man
      
      const pink = new Man()
      console.log(pink)
      
      function Woman(){
          this.baby = function(){
      
          }
      }
      

image-20230810204315101.png

  • 问题

    • 如果给男人添加一个抽烟的方法,女人对象自动也存在了这个方法
  • 原因

    • 都同时使用了一个对象,根据引用类型的特点,他们指向同一个对象

image-20230810204321098.png

  • 解决

    • 构造函数
    function Persion(){
      head: 1,
      eyes:2,
      this.say = function(){
    
      }
    }
    

image-20230810204327688.png

  • 原型链

    • 基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链

image-20230810204334132.png

  • 查找规则
    • 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有改属性
    • 如果没有就查找它的原型(也就是 proto 指向的 prototype原型对象
    • 如果还没有就查找原型对象的原型(Object 的原型对象
    • 以此类推一直找到 Object 为止(null
    • proto 对象原型的意义就在于为对象成员查找机制提供一个方向
    • 可以使用 instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

6.综合案例

image-20230810204339611.png

<body>
  <button id="delete">删除</button>
  <button id="login">登录</button>

  <!-- <div class="modal">
    <div class="header">温馨提示 <i>x</i></div>
    <div class="body">您没有删除权限操作</div>
  </div> -->


  <script>
    // 1.Modal 构造函数封装 - 模态框
    function Modal(title = "", message = ""){
      // 1.1创建 modal 模态框盒子
      this.modalBox = document.createElement("div")
      // 1.2 给div标签添加类名
      this.modalBox.classList.add("modal")
      // 1.3 modal 盒子内部填充 2 个div标签并且修改文字内容
      this.modalBox.innerHTML = `
      <div class="header">${title}<i>x</i></div>
      <div class="body">${message}</div>
      `
      console.log(this.modalBox)
    }

    // 2.给构造函数原型对象挂载 open,close 方法
    Modal.prototype.open = function(){
      // 先判断页面中是否已经存在,如果存在则删除
      const box = document.querySelector(".modal")
      box && box.remove()
      document.querySelector("body").appendChild(this.modalBox)
      // 盒子显示出来,添加绑定事件
      this.modalBox.querySelector("i").addEventListener("click", () => {
        // 这里使用箭头函数,用this指向实例化对象而不是 i 元素
        this.close()
      })
    }
    Modal.prototype.close = function(){
      this.modalBox.remove()
    }

    document.querySelector("#delete").addEventListener("click", () => {
      const del = new Modal("温馨提示", "您没有权限删除操作")
      del.open()
    })
    document.querySelector("#login").addEventListener("click", () => {
      const del = new Modal("友情提示", "您没有注册呢")
      del.open()
    })
  </script>
</body>

results matching ""

    No results matching ""