javascript 对象的创建与继承 

2019-05-04 09:40:39来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

针对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)
}

本人菜鸡儿一个,如果错误欢迎大家指正 


原文链接:https://www.cnblogs.com/wangzirui98/p/10808546.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:前端笔记之Vue(三)生命周期&CSS预处理&全局组件&

下一篇:D3.js的基础部分之数组的处理 嵌套结构(Nest)(v3版本)