原型对象

98 阅读6分钟

1.面向对象是什么

面向对象是什么: 面向对象是一种注重结果的思维方式 面向过程: 注重过程 面向对象: 注重结果

2.面向对象与面向过程的关系 :面向对象的本质 就是 对面向过程的 封装

举例:吃火锅

    1.面向过程:注重过程 
    (1)买鸳鸯锅
    (2)买电磁炉
    (3)买锅底
    (4)买牛肉、羊肉、青菜、千张、毛肚、火锅面、菌类
    (5)开火热锅
    (6)放食材
    (7)夹起来开干
    
    2.面向对象:注重结果 
    点火锅送过来

3.内置对象

内置对象: js作者提前封装好的对象

3.1数组对象

声明数组

let arr = [10,20,30,40,50]// new Array(10,20,30,40,50)

3.1.1 arr.concat(数组):连接对象

// 应用场景:下拉加载更多的时候,会把新数组链接到原来数组的后面
 arr = arr.concat([40,50,60])//链接两个或更多的数组,得到一个拼接后的新数组,需要接收
 console.log(arr);

3.1.2 arr.reverse(数组):翻转对象

//应用场景: 价格从低到高 切换成 从高到低, 只需要翻转数组即可
arr.reverse()
console.log( arr )

3.1.3 arr.join(‘分隔符’):把数组的每一个元素拼接成字符串

let arr1 = [80,90,55,60]
    //应用场景 :  有些歌曲是多个人合唱,服务器会给我们一个数组。 这个时候就          需要将数组元素通过join拼接起来然后再页面显示
    let str = arr1.join('&')
    console.log( str )//80&90&55&60

3.1.3 arr.sort(function(a,b){return a-b}):排序

    let arr2 = [80,90,50,20,77,88]
    arr2.sort( function(a,b){
        // return a-b //从小到大
        return b-a //从大到小
    } )
    console.log(arr2)

3.2字符串对象

声明一个字符串

let str = '黑马程序员武汉大前端女神节快乐!'

3.2.1 字符串类似于数组,也有长度和下标

console.log( str.length )//16
console.log( str[5] )//武

3.2.2 str.indexOf('字符串') 获取字符串在str中的首字母下标

如果字符串存在则返回首字母下标,如果字符串不存在则返回固定值-1

// 应用场景: 一般用户判断 str中是否有某个字符串  如果没有则返回-1,不是-1说明有

    let index1 = str.indexOf('大前端')
    console.log( index1 )//7
    let index2 = str.indexOf('大女神')
    console.log( index2 )//-1

3.2.3 str.split('分隔符') 用分隔符切割字符串,得到切割之后的数组

// 应用场景 : 一般用户解析 网址
    let url = 'http://www.baidu.com?name=张三&age=20'
    console.log( url.split('|') )//['http://www.baidu.com?name=张三&age=20']
    console.log( url.split('?') )//['http://www.baidu.com', 'name=张三&age=20']
    console.log( url.split('=') )//['http://www.baidu.com?name', '张三&age', '20']

3.2.4 str.substr(起始下标,截取长度) 截取字符串

// 应用场景 : 一般后台返回的数据 不会和前端完全匹配。 有时候需要自己截取一部分
    //例如: 商品价格后台返回 :价格58元  但是前端只需要显示58元,就需要截取
    console.log( str.substr(2,5) )//从2下标开始,往后截取5个字 程序员武汉

3.2.5 大小写转换 (中文没有大小写)

//应用场景: 字母验证码不区分大小写 (一般无论你输入什么,都会转成大写或小写保持格式统一)

    console.log('dsSFJSGDJHsdfs'.toLocaleLowerCase() )//小写 dssfjsgdjhsdfs
    console.log('dsSFJSGDJHsdfs'.toLocaleUpperCase() )//大写 DSSFJSGDJHSDFS

4.工厂函数

<script>
        /* 需求 :  需要创建很多个对象 (姓名、年龄、性别) */
       
        // let p1 = {
        //     name:'张三',
        //     age:20,
        //     sex:'男'
        // }

        // let p2 = {
        //     name:'李四',
        //     age:22,
        //     sex:'女'
        // }

        // let p3 = {
        //     name:'王五',
        //     age:30,
        //     sex:'男'
        // }
        
        // 工厂函数 :  用于创建对象的函数
        function createPerson(name,age,sex){
            //1.创建对象
            let p = {}
            //2.给对象赋值
            p.name = name
            p.age = age
            p.sex = sex
            //3. 返回对象
            return p
        }

        let p1 = createPerson('张三',20,'男')
        let p2 = createPerson('李四',22,'女')
        console.log(p1,p2)    
    </script>

5.构造函数

1.工厂函数:用于创建对象的函数

2.构造函数:使用new调用一个函数 构造函数作用与工厂函数一致,都是用来创建对象的。但是代码更加简洁

3.构造函数new工作原理 (1)创建空对象 (2)this 指向这个对象 (3)对象赋值 (4)返回这个对象

4.构造函数new在使用时需要注意的地方 4.1构造函数首字母一般大写,为了提醒调用者不要忘记new关键字 4.2如果在构造函数内部 手动return return 值类型 :无效,还是返回new创建的对象 return 引用类型:有效,会覆盖new创建的对象

<script>
        /* 
        1.工厂函数(了解) : 用于创建对象的函数
        2.构造函数 :  使用new调用一个函数
            构造函数作用与工厂函数一致,都是用来创建对象的。但是代码更加简洁。
        3.构造函数new工作原理
            (1)创建空对象
            (2)this指向这个对象
            (3)对象赋值
            (4)返回这个对象
        4.构造函数new在使用时需要注意的地方
            4.1 构造函数首字母一般大写, 为了提醒调用者不要忘记new关键字
            4.2 如果在构造函数内部 手动return
                return 值类型  : 无效,还是返回new创建的对象
                return 引用类型  : 有效,会覆盖new创建的对象
        */
        // 构造函数
        function Person(name,age,sex){
            //(1)创建空对象   {}
            //(2)this指向这个对象  this = {}
            //(3)对象赋值
            this.name = name
            this.age = age
            this.sex = sex
            //(4)返回这个对象 return this
        }
        
        // 实例对象
        let p1 = new Person('张三',20,'男')
        console.log(p1)

        // JS中几乎所有的对象都是构造函数创建
        /* 
        数组: new Array() 
        对象: new Object()
        日期:new Date()
        正则: new RegExp()
        */
    </script>

6.原型对象

6.1原型对象是什么?

任何函数在声明的时候,系统会自动帮你创建一个对象,称之为原型对象

6.2原型对象的作用

(1)构造函数内部方法: 浪费内存资源

  function Person(name,age){
         this.name = name
        this.age = age
        this.eat = function(){
            console.log('eat');
     }
    }

  let p1 = new Person('张三',18)
  let p2 = new Person('李四',20)
  console.log( p1,p2)

思考: p1和p2都有eat方法,而是函数体相同。但是他们是同一个函数吗?

 不是同一个: 因为每一次调用构造函数, 内部都会执行一次function,就会在堆中开辟一个新的空间。虽然代码是一样的,但是地址不同。 就会导致每调用一次构造函数,多出一个函数堆空间。导致内存资源浪费
  引用类型只比较地址,不比较值。 不能因为值相同,就认为引用类型地址相同
   console.log( p1.eat == p2.eat )//false

QQ图片20220429090622.png

(2)使用全局函数解决内存浪费 导致新的问题: 全局变量污染

    let eat = function() {
     console.log("吃东西")
    }

    let learn = function() {
      console.log("学习")
    }

    function Person(name, age) {
      this.name = name
      this.age = age
      this.eat = eat
      this.learn = learn
    }

    let p1 = new Person("张三", 18)
    let p2 = new Person("李四", 20)
    console.log(p1, p2)

思考题:p1的eat和p2是不是同一个 答案:是的 因为构造函数内部并没有重新function创建一个函数,而是拷贝eat的地址赋值。 无论你调用构造函数多少次,都是拷贝eat的地址

       console.log( p1.eat == p2.eat )//true

(3)使用对象 : 解决内存浪费 + 变量污染

        eat: function() {
          console.log("吃东西")
        },
        learn: function() {
          console.log("学习")
        }
      }

      function Person(name, age) {
        this.name = name
        this.age = age
        this.eat = obj.eat
        this.learn = obj.learn
      }

      let p1 = new Person("张三", 18)
      let p2 = new Person("李四", 20)
      console.log(p1, p2)

6.3原型对象相关三个属性:构造函数 、原型对象、实例对象 三者关系

 prototype :  属于构造函数, 指向原型对象
                     解决构造函数内存浪费+变量污染
 __proto__ :  属于实例对象,指向原型对象
                     让实例对象直接使用原型的成员(函数+属性)
 constructor : 属于原型对象,指向构造函数
                     让实例对象知道自己的构造函数是谁

OV}{`S9BQL0JFZIZWSX7GFJ.png

    //1.构造函数
    function Person(name,age){
        this.name = name
        this.age = age
    }

    //2.原型对象
    Person.prototype.eat = function(){
        console.log('吃东西')
    }

    Person.prototype.learn = function(){
        console.log('学习')
    }

    console.log( Person.prototype.constructor )//Person
    // 可以让实例对象知道自己被哪一个构造函数创建

    //3.实例对象
    let p1 = new Person('张三',20)
    console.log(p1)

    /* __proto__ : 属于实例对象的,指向原型对象
    注意: 这个属性不是web标准,很多浏览器不会显示的。 这个属性在开发中不能使用,只能用于学习研究
    */
    p1.eat()//p1.__proto__.eat()

    /* 验证 构造函数、原型对象、实例对象三者关系 */
    // console.log(p1.__proto__);//p1的原型对象
    console.log( p1.__proto__.constructor )//Person
    console.log( Person.prototype === p1.__proto__ )//true
    

7.静态成员与实例成员

静态成员: 函数的属性

实例成员: 实例对象的属性

       /* 
       静态成员:  函数的属性
       实例成员:  实例对象的属性
       */
       function Person(name,age){
           this.name = name
           this.age = age
       }

       let p1 = new Person('张三',20)
       console.log( p1.name )//实例成员
       console.log( p1.age )//实例成员

       console.log( Person.prototype )//静态成员
       console.log( Math.PI ) //静态成员
       
    </script>

8.Object的values方法

        
         /* 需求:获取对象所有的属性值 */   
         let person = {
             name:'张三',
             age:20,
             sex:'男'
         }

         //1 以前的写法:  for-in 循环
         for(let key in person ){
             console.log( person[key] )  
         }

         //2.静态方法  Object.values(对象名)
         //返回值是一个数组,会存储对象每一个属性值
         let arr = Object.values(person)
         console.log(arr)
    </script>