JavaScript——原型思想(重点)

本文深入探讨JavaScript中的对象、函数、原型和构造函数之间的关系,包括函数的属性如name、length和prototype,以及如何通过prototype和__proto__属性实现对象间的继承。文章还介绍了如何操作对象成员和原型对象,以及自定义构造函数和系统内置构造函数的原型对象区别。同时,通过案例分析了对象和函数的原型属性,展示了如何通过原型对象进行属性共享和访问。
摘要由CSDN通过智能技术生成

1.前言:

 object function为js中的引用数据

        引用数据  ==>是一种内存空间 是一种数据容器  数据容器就是可以存储很多数据的引用

  • 数组是一种有下标的数据容器
  • 对象是一种有键值对的数据容器
  • 函数是一种有代码块和作用域的数据容器

 函数的属性

           name       保存了一个字符串  即函数的名字

           length     保存了一个数字    即函数形参的个数

           prototype  保存(引用)了一个系统内置的对象  这个对象是new Object()

构造函数

  1. 一般专门用于创建对象的函数 就是构造函数
  2. 同一个函数创建出来的对象们 具有相同的空间结构和功能
  3. 每一个函数创建出来的对象是不相同的

构造函数的分类

   1.自定义构造函数

  • 自定义构造函数的原型对象也是一个自定义构造函数创建的对象

    实例:

function Kedou() {
            this.life = 1
            this.tail = 1
        }
var k1 = new Kedou()

function Qingwa() {
            this.leg = 4
            this.eye = 2
        }

var k2=new Kedou()   //k1,k2 结构和原型对象相同 同一个函数创建的对象
Qingwa.prototype=k2  
/* 分析:
  Qingwa.prototype=由Qingwa()创建的对象的__proto__属性=k2  
  k2是Kedou()创建的对象 ==>k2.__proto__=Kedou.prototype=k1.__proto__
  那么Qingwa.prototype=q1.__proto__=k2
  ==>q1.__proto__.__proto__=k2.__proto__=k1.__proto__
*/
var q1 = new Qingwa()
console.log(q1.life) //1
/* 找到life属性的步骤:q1.life==this.life
   1.先去 Qingwa()中找是否有life属性 无
   2.去q1的__proto__(Qingwa的prototype)即k2中找 k2对象有k2.life=1 找到
*/

//k1是不是q1的原型对象?-----不是
console.log(q1.__proto__==k1,q1.__proto__==k2)  //false
//k1的原型对象是q1的原型对象的原型对象
console.log(k1.__proto__===q1.__proto__.__proto__)  //true 

   2.官方提供的函数:Function String Number Boolean Object Array Date Math ...

2.原型

 定义:原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。

 基本思想:内存空间共用

 使用构造函数创建对象:

  • 任何函数都有一个属性 prototype  是一个对象 new Object()/{}
  • 所有的对象都有一个属性 __proto__  代表的是这个对象的原型对象
  • 用函数创建对象 创建出来的原型对象就是prototype属性引用的对象
  • prototype属性中引用了一个系统内置的对象:new Object()/{}
  • 同一个函数创建出来的对象的原型对象是同一个对象

 构造函数、原型、实例对象的关系:

  • 实例对象都有__proto__属性 该属性指向构造函数的原型对象
  • 构造函数都有prototype属性  这个属性是一个对象,是Object的实例
  • obj.__proto__===Object.prototype

 prototype与__proto__的关系:

  • prototype是构造函数的属性
  • __proto__是实例对象的属性
  • 两者指向同一个对象

3.案例

   function fn(firstName) {
            this.life = 1
            this.firstName = firstName
            this.sayName = function () {
                console.log(this.firstName)
            }
        }
        var f1 = new fn("张") //{life:1,firstName:"张",sayName:f()}
        var f2 = new fn("李") //{life:1,firstName:"李",sayName:f()}
        f1.__proto__.age = 23
        console.log(f2.age) //23
/*
  f1 f2是两个内存空间 但f1 f2的原型对象是相等的(对象共用存储空间) 
  因为是同一个函数(fn)创建的对象 所以f2也能访问age属性 f2.age=f1.age=23
*/
function fn() {
          this.life = 1
          //隐式操作: fn.prototype={}
        }
        function fm() {
            this.color = "black"
            //隐式操作: fm.prototype={}
        }
        var f1 = new fn()
        var f2 = new fm()

        console.log(f1.__proto__ === f2.__proto__) //false 因为函数不是同一个内存空间
        console.log(f1.__proto__ === fn.prototype) //true 
        console.log(f2.__proto__ === fm.prototype) //true
        console.log(f1.__proto__ === fm.prototype) //false
        //f1的原型对象是fn的prototype f2的原型对象是fm的prototype
     function fn() {
            this.life = 1
        }
        fn.prototype.color = "red"
        var f1 = new fn()
        f1.age = 21
        var f2 = new fn()
        var f3 = new fn()
        console.log(f1.color, f2.color, f3.color) //都是red
        console.log(f2.age) // undefined  只有f1能用
       
        /* f1.__proto__.age = 21
           console.log(f2.age)   //21  此时f1,f2,f3均可用age
        */
   function fn() {
            this.a = 20
        }
        //隐式操作:fn.prototype={}

        function fm() {
            this.a = 30
        }
        //隐式操作:fm.prototype={}

        fm.prototype.fn = new fn()
        /* 分析:
          fm.prototype.fn ==> 给fm.prototype添加成员fn ==>fm.prototype={fn:{a:20,__proto__:{}}}
          new fn()        ==> {__proto__:fn.prototype} ==> {a:20,__proto__:{}}
        */

        var f1 = new fm()
        //new fm() ==>  {__proto__:fm.prototype,a:30}  ==> {__proto__:{fn:{a:20,__proto__:{}}},a:30}
       
        console.log(f1)
        //{a:30,__proto__:{fn:{a:20,__proto__:{}}}}

4.对象和函数的关系(常出现在笔试题的选择题中)

  通过案例分析理解:

Object.prototype.life = 1 //执行后用Object创建的对象的原型对象都有life属性 1
Function.prototype.life = 2 //执行后函数的原型对象都有life属性 2

function fn() {
      this.name = "lusis"
}
var f1 = new fn()
console.log(f1.name, f1.life) //lusis 1
/* 分析:
  f1.name=this.name = "jack"
  f1.life ==> fn()函数中没有life属性
              f1.__proto__=fn.prototype = new Object() => Object.prototype
              Object.prototype有life属性为1
              f1.life=Object.prototype.life=1
*/
console.log(fn.life, fn.name) //2 fn 
/* 分析:
  fn.life ==> fn函数中没有life属性 去到函数的原型对象
              fn.__proto__=Function.prototype
              Function.prototype有life属性为2
              fn.life=2
  fn.name ==> 函数的名字
*/

案例深入:

Object.prototype.life = 1 //执行后用Object创建的对象的原型对象都有life属性 1
function fn() {
     this.name = "lusis"
}
var f1 = new fn()
console.log(f1.life) // 打印 1  fn.prototype = new Object() => Object.prototype
console.log(fn.life) /* 打印 1  
                        Function.prototype = 函数的原型对象 => 原型对象(n层) 
                         => Object.prototype
                     */
Function.prototype.life = 1  //所有的函数的原型对象都有life属性 1
function fn() {
    this.name = "lusis"
}
var f1 = new fn()
console.log(f1.life) //undefined
/* 分析:
  f1.life ==> fn()函数中没有life属性 去到原型对象
              f1.__proto__=fn.prototype = new Object() => Object.prototype
              Object.prototype没有定义life属性 再往上也没有life属性值 直到null
              返回undefined           
*/

console.log(fn.life) //1 
/* 分析:
  fn.life ==> fn函数中没有life属性 去到函数的原型对象
              fn.__proto__=Function.prototype
              Function.prototype有life属性为1
              fn.life=1
*/

5.对象的成员操作

(1)基本操作:

var obj = {
            name: "lusis"
        }
        obj.age = 20 //添加age属性
        obj.name = "haha" //更新name属性
        var re = obj.age //取出age属性的值
        var re2 = obj.x //取出x属性的值  没有x 取出undefined
        var re3 = obj.name //取出最后一次name属性修改的值
        console.log(re, re2, re3) //20 undefined haha

(2)存值、取值:

function fn(name) {
    this.name
}
var obj = new fn("lusis") //{name:"lusis",age:20,__proto__:{}}
//存值
obj.age = 20 //如果给一个对象存值 没有该属性就直接创建该属性
obj.name = "haha" //如果给一个对象存值 有该属性就更新该属性  但不会更新原型对象

//取值
var re=obj.age //取对象的属性值 先找原型对象的 没有再找原型的原型一直到null还没有就返回undefined
var re2 = obj.x //undefined
var re3 = obj.name //
console.log(re, re2, re3) // 20 undefined haha

6.原型对象的操作

  实例:在以下程序中添加代码 使打印结果为20

function fn() {
            this.a = 10
        }
        //fn.prototype.x=20     -->第一种
        //fn.prototype={x:20}   -->第二种
        var f1 = new fn()
        // f1.__proto__.x=20    -->第三种
        //f1.__proto__={x:20}   -->第四种
        console.log(f1.x) 

 系统内置的构造函数的原型对象属性不可以修改 可以操作这个对象的属性

Array.prototype={name:"lusis"} //不会报错 但也不会生效 =>跳过编译
Array.prototype.age = 20 //所有数组都有age属性
var arr = [10, 203, 4]
console.log(arr.age, arr)

7.对象操作原型

实例:

function fn() {
    this.age = 21
}
fn.prototype = {
     life: 1,
     fm: {
        name: "lusis"
      }
}
var f1 = new fn() // ==> {age:21,__proto__:{life:1,fm:{name:"lusis"}}
console.log(f1.life, f1.age) // 1  21

f1.age = 20 //更新属性值
f1.life = 2 //给自己添加life:2,不会修改原型中的life:1
// ==> {life:2,age:20,__proto__:{life:1,fm:{name:"lusis"}}
var re = f1.fm
console.log(re) // {name: "lusis"}
console.log(f1) // {age:20,life:2,__proto__:{life:1,fm:{name:"lusis"}}

f1.fm.name = "cici" //fm才是原型对象的属性 没有修改原型对象的成员就可以操作

var f2 = new fn()  // ==> {age:21,__proto__:{life:1,fm:{name:"cici"}}
console.log(f2) // {age:21,__proto__:{life:1,fm:{name:"cici"}}
console.log(f2.fm.name) // cici

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈哈ha~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值