zoukankan      html  css  js  c++  java
  • javascript 对象的创建与继承模式

    针对JS高级程序设计这本书,主要是理解概念,大部分要点源自书内。写这个主要是当个笔记加总结

    存在的问题请大家多多指正!

    6.1理解对象

    创建对象的两个方法(暂时)

     1 //第一种,通过创建一个Object类型的实例,然后为他添加属性和方法
     2 var person = new Object()
     3     person.name = 'laotie'
     4     person.sayName = function(){
     5         alert(this.name)
     6 }   
     7 //第二种简化版
     8 var person = {
     9     name: 'laotie',
    10     sayName: {
    11         alert(this.name)
    12     }
    13 }

    6.1.1 类型属性

    1.数据属性

    JS不能访问的数据属性

    • Configurable 能不能用delete删除 默认true
    • Enumerable 能否通过for-in循环返回属性 默认true
    • Writable 能否修改属性 默认true
    • Value 就是这个属性的属性值 默认undefined

    Object.defineProperty()接收三个参数:属性所在的对象,属性的名字和一个描述符对象 描述符对象必须是上面那四个

    var person = {}
    Object.defineProperty(person, 'name', {
        //我设置了,其中person的属性name,所以name这个属性他就动不了了
        writable: false,
        value: 'laotie'
    })
    
    alert(person.name) //'laotie'
    person.name = '666'
    alert(person.name) //'laotie'

    如果用Object创建的属性一般configurable,enumerable,writable的默认值都是false,如果不用他创建的话就没有限制。

    总之这个东西没什么太大实际用处,帮助理解吧

    2.访问器属性
    • Configurable, enumerable 跟上面的差不多
    • Get 在读取属性时调用的函数
    • Set 在写入时调用的属性 get,set默认都为undefined
    var book = {
            _year: 2004
            edition: 1
        }
        
        Object.defineProperty(book, 'year', {
            //这里放刚才的属性
            get: function(){
                return this._year
            },
            set: function(newValue){
                if(newValue > 2004){
                    this._year = newValue
                    this.edition += newValue - 2004
                }
            }
            
        })
        
        book.year = 2005
        alert(book.edition) //2

    老方法不介绍了,是直接在对象后面调用__defineGetter__和__defineSetter__,参数里面第一个是属性,第二个穿进去个处理函数

    6.1.2定义多个属性

    ES5加了个牛逼的Object.defineProperties()方法
    第一个参数里放要修改属性的对象 ,第二个加个代码块里面方参数

    var book = {}
    Object.defineProperties(book,{
        _year: {
            writable: true,
            value:2004
        },
        edition: {
            writable: true,
            value: 1
        },
        set:function(newValue){
            if(newValue > 2004){
                    this._year = newValue
                    this.edition += newValue - 2004
                }
        }
    })

    6.1.3读取属性的特性

    Object.getOwnPropertyDescriptor()

    var descript = Object.getOwnPropertyDescriptor(book, '_year')
    alert(descript.value) //2004
    alert(descript.configurable) //false

    6.2创建对象

    6.2.1工厂模式

    fucntion createPerson(name, age, job){
        var o = new Object()
        o.name = name
        o.age = age
        o.job = job
        o.sayName = function(){
            alert(this.name)
        }
        
        return o 
    }
    
    var person1 = creatPerson('laotie', 26, 'meiyou')

    没法解决你这个对象什么类型的,因为对象在里面创建的,很迷

    6.2.2构造函数模式

        //构造函数首字母大写 Person
        function Person(name, age, job){
            this.name = name 
            this.age = age
            this.job = job
            this.sayName = function(){
                alert(this.name)
            }
        }
        //有个new
        var person1 = new Person('laotie', 26, 'meiyou')

    instanceof验证是谁的实例

    person1 instanceof Object //true
    person1 instanceof Person //true
    
    • 如果不按套路用构造函数可以不用new 然后也可以没有变量接着
    Person('laotie', 25, '666') //添加对象到window
    window.sayName() //‘laotie’

    构造函数中的方法在不停的声明function实例,每一个同名function通过新对象的创建都在不停地复制着等于this.sayName = new Function('alert(this.name)')

    可以这样改

        //构造函数首字母大写 Person
        function Person(name, age, job){
            this.name = name 
            this.age = age
            this.job = job
            this.sayName = sayName
        }
        
       function sayName(){
            alert(this.name)
       }

    但是这样构建函数的话没有封装性可言,所以要用原型模式

    6.2.3原型模式

    每个函数都有一个prototype属性指向原型对象

    //标准的原型模式函数是没有参数的
    function Person(){}
    
    Person.prototype.name = 'laotie'
    Person.prototype.age = 29
    Person.prototype.job = '666'
    Person.prototype.sayName = function(){
        alert(this.name)
    }

    缺点:新建的所有对象所有属性都共享,没有传参

    只要创建一个新函数, 那他就有一个原型的属性(prototype这个属性),这个属性指向他的原型对象,原型对象自动获得一个constructor属性(叫构造函数的属性),这个属性指向prototype属性所在的函数,新建的实例函数里都会有一个不可见的[[Prototype]]的属性(这个对象在火狐safari和chrome里可以看见,叫__proto__)指向原型对象

    原型模式函数创建的对象可以再给属性赋值,赋的值可以掩盖原型对象中的值
    delete你自己赋的值之后原型对象里的值还可以用

    person1.hasOwnProperty('name') //可以看有无自己赋值的属性,有事true ,没有false
    'name' in person1 //不管是自己的属性还是原型对象里的属性,只要有值就是true

    简单点的设置prototype

    function Person(){}
    Person.prototype = {
        //一般加上constructor: Person 要不然构造函数就跑到Object了
        constructor: Person
        name:'laotie',
        sayName: function(){
            alert(this.name)
        }
    }
    新建对象是一定要在构造的后面哈,在前面建对象的话会断开和新建的原型对象的链接
    function Person(){}
    var person1 = new Person()
    //相当于重新设置了Person的原型对象,现在的原型对象和person不是同一个了,所以person1中没有sayName这个函数
    Person.prototype = {
        constructor: Person
        name:'laotie',
        sayName: function(){
            alert(this.name)
        }
    }
    person1.sayName() //error

    有个很大的毛病,就是原型模式函数不能自己传参,所以无论新建多少对象都是一个德行,没有属于自己的属性

    6.2.4 把构造函数模式和原型模式组合一波

    构造的定义不一样的属性,而原型模式构造一样的属性

    function Person(name,age,job){
        this.name = name 
        this.age = age
        this.job = job
    }
    
    Person.prototype = {
        constructor: Person,
        sayName: function(){
            alert(this.name)
        }
    }

    6.3继承

    6.3.1原型链

    原型模式构造函数:

    • 每个构造函数都会都会有一个原型对象,原型对象contrustor指向构造函数,实例对象[[prototype]]属性指向原型对象。

    原型链就是把superType的实例对象给subType构造函数当原型。

    还跟原型构造函数要注意的一样,就是在新建实力之后更改构造函数的原型,要不然就会断绝实例对象和新原型对象之间的联系

    • function SuperType(){
          this.property = true
      }
      
      SuperType.prototype.getSuperValue = function(){
          return this.property
      }
      
      function SubType(){
          this.subproperty = false
      }
      
      SubType.prototype = new SuperType()
      
      SubType.prototype.getSubValue = function(){
          return this.subproperty
      }
      
      var instance = new SubType()
      
      alert(instance.getSuperValue) //true
      原型模式参数传递不方便,所以菜的一批,所以借用构造函数

    6.3.2 借用构造函数

    就是在SubType里call或者apply一个SuperType,相当于在SubType调用了SuperType里的所有东西,所以就顺理成章的继承过来了

    function SuperType(){
        this.color = ['red', 'blue']    
    }
    
    function SubType(){
        SuperType.call(this)
    }
    
    var instance1 = new SubType()
    instance1.colors.push('black')
    alert(instance1.colors) //red,blue,black
    
    var instance2 = new SubType()
    alert(instance.colors) //red,blue

    与原型的不同就是可以传参数,然后用call的第二个后面或者apply的第二个函数赋值

    但是问题是方法都在构造函数里,函数没法复用,所以就用组合式的比较吊,可以传参,可以函数复用

    6.3.4 组合式继承

    就是上面说的,用借用构造函数传参和设定基本属性,用原型链来做方法的复用

    function SuperType(name) {
      this.name = name
      this.colors = ['red', 'blue']
    }
    
    SuperType.prototype.sayName = function() {
      alert(this.name)
    }
    
    function Subtype(name, age) {
    //第二处这里在call的时候又引入了name 和color属性。所以重复了,这也是组合继承的缺点
      SuperType.call(this, name)
      this.age = age
    }
    //第一处在设置原型对象时候在原型对象中 有name 和color属性了,看上面⤴️
    Subtype.prototype = new SuperType()
    Subtype.prototype.constructor = SubType
    Subtype.prototype.sayAge = function (){
      alert(this.age)
    }

    这样的好处是可以传入参数可以有自己的属性,然后又可以有共同的函数

    6.3.4 原型式继承

    Object.creat()这个方法,可以放一个或者两个参数,一个参数的时候是第一个是一个对象
    第二个函数是可以附加一些属性,通过{name:'laotie'}这样的直接加进去

    原理类似下面

    function object(o){
        function F(){}
        F.prototype = o
        return new F()
    }

    其实就是讲一个对象丰富了加了一些属性,然后再返回一个实例对象。有一个弊端,没有creat之前的内容和属性始终会共享。

    6.3.5 寄生式继承

    这个书上也没有仔细讲,给我感觉就是传进来一个对象,然后通过内部加强一些内容再返还出去

    function creatAnother(original){
        var clone = object(original)
        clone.sayhi = funciton(){
            alert('hi')
        }
        return clone
    }

    6.3.6 寄生组合式继承

    尼古拉斯挑了个原型链继承的和借用继承的毛病,就是里面的参数会重复的建,占用内存,所以为了优化,就找了个寄生组合继承,给我感觉像是借用加上原型式(不是原型链继承模式是原型式)模式

    function inheritPrototype(subType,SuperType){
        var prototype = object(SuperType.prototype)
        prototype.constructor = subType
        subtype.prototype = prototype
    }

    这个不就是原型式继承吗?为啥要带上寄生式,感觉没寄生式啥事。
    然后剩下的用借用就行了

    完整代码:

    function SuperType(name){
        this.name = name 
        this.colors = ['red','blue']
    }
    
    SuperType.prototype.sayName = function(){
        alert(this.name)
    }
    
    function SubType(name,age){
        SuperType.call(this,name)
        this.age = age
    }
    
    inheritPrototype(subType,SuperType)
    
    SubType.prototype.sayAge = function(){
        alert(this.age)
    }
  • 相关阅读:
    探究platform_driver中的shutdown用途
    Linux内存调试工具初探-MEMWATCH(转)
    kernel3.13 针对 Vmware安装存在的问题解决
    xgcom linux下的串口助手
    ubuntu 13.10 无法播放 mp3
    ubuntu 13.04添加 flash_plugin
    Linux安装mysql——源码安装
    Ubuntu 12.04中MyEclipse 10.6+下载+安装+破解
    [零基础学JAVA]Java SE面向对象部分.面向对象基础(06)
    [零基础学JAVA]Java SE面向对象部分.面向对象基础(05)
  • 原文地址:https://www.cnblogs.com/wangzirui98/p/10808546.html
Copyright © 2011-2022 走看看