【JavaScript学习笔记】Part 3-JS的对象

1.对象

1.1 类型

六种语言类型:

  • string
  • number
  • boolean
  • null
  • undefined
  • object

但前五种本身并不是对象。

内置对象

  • String
  • Number
  • Boolean
  • Object
  • Function
  • Array
  • Date
  • RegExp
  • Error

可以当作构造函数来用,用new构造一个对应子类型的对象。

1.2 对象拷贝

function anotherFunction(){
    
    }
var anotherObject = {
    
    
    c:true
}
var anotherArray= []
var myObject = {
    
    
    a:2,
    b:anotherObject,
    c:anotherArray,
    d:anotherFunction
}
anotherArray.push(anotherObject,myObject)

如果是浅拷贝,拷贝出来的新对象中的b、c、d三个属性只是三个引用,和旧对象中的b、c、d应用的对象是一样的;

如果是深拷贝,除了复制myObject外还会复制anotherObject和anotherArray,但anotherArray又引用了anotherObject和myObject,又需要复制,从而导致死循环。

有一种JSON安全的复制方法

var newObj = JSON.parse(JSON.stringify(someObj))

ES6定义了Object.assign(..)方法来实现浅拷贝:

var newObj = Object.assign({
    
    },myObject)

newObj.a  //2
newObj.b === anotherObject  //true
newObj.c === anotherArray  //true
newObj === anotherFunction //true

1.3 属性描述符

从ES5开始,所有的属性都具备属性描述符

扫描二维码关注公众号,回复: 12408162 查看本文章

可以用Object.defineProperty()来添加一个新属性或修改已有属性。

var obj = {
    
    }
Object.defineProperty(obj,'a',{
    
    
    value:2,
    writable:true,
    configurable:true,
    enumerable:true
})
console.log(obj.a) //2
  1. writable决定是否可以修改属性的值
  2. configurable,属性可配置,则可以使用defineProperty()来修改属性描述符。
  3. enumerable,描述属性是否会出现在对象的属性枚举中,如for…in循环,若enumerable设置为false,则不会出现在枚举中,但仍然可以正常访问。
  4. getter和setter:后面再说

1.4 Getter和Setter

getter是要给隐藏函数,会在获取属性值时调用。

setter会在设置属性值时调用。

var myObject = {
    
    
    // 给a定义一个getter
    get a(){
    
    
        return 2
    }
}
Object.defineProperty(myObject,'b',{
    
    
    //给b设置要给getter
    get:function(){
    
    return this.a*2},
    enumerable:true
})
console.log(myObject.a)
console.log(myObject.b)
myObject.a = 3
console.log(myObject.a)

两种方法,一种是get定义,一种是defineProperty()定义,由于只给a定义了getter,所以对a的值进行设置时set操作会忽略赋值操作。

var myObject = {
    
    
    // 给a定义一个getter
    get a(){
    
    
        return this.r
    },
    set a(val){
    
    
        this.r = val * 2
    }
}
myObject.a = 2
console.log(myObject.a)

1.5 存在性

可以在不访问属性值的情况下判断对象中是否存在这个属性:

var myObject = {
    
    
    a:2
}
('a' in myObject) //true
('b' in myObject) //false

myObjcet.hasOwnProperty('a')  //true
myObject.hasOwnProperty('b')  //false
  • in操作符会检查属性是否在对象及[[Prototype]]原型链中。实际上它检查的是某个属性名是否存在:

    console.log(4 in [2,4,6])
    

    这里会打印false,因为数组中属性名是0、1、2,没有4。

  • hasOwnProperty()只会检查属性是否在myObject对象中,不会检查原型链。

判断是否可枚举:

  • propertyIsEnumerable()会检查给定的属性名是否存在于对象中并满足enumerable:true
  • Object.keys()返回包含所有可枚举属性的数组
  • Object.getOwnPropertyNames()返回包含所有属性的数组,无论是否可枚举

1.6 遍历

除了本身的for循环遍历外,ES5增加了一些数组的赋值迭代器,如forEach()every()some(),而它们都是遍历数组下标从而找到数组的值,ES6增加了for..of语法,可以直接遍历值。

var myArray = [1,2,3]
for(var v of myArray){
    
    
    console.log(v)
}

它首先会向被访问对象请求一个迭代器对象,然后通过迭代器对象的next()方法来遍历所有的返回值。

数组有内置的@@iterator,可以用它来手动遍历数组:

var myArray = [1,2,3]
var it = myArray[Symbol.iterator]()
it.next(); {
    
    value:1,done:false}
it.next(); {
    
    value:2,done:false}
it.next(); {
    
    value:3,done:false}
it.next(); {
    
    done:false}

@@iterator是一个返回迭代器对象的函数。

for...of可以遍历数组、对象等等,它会寻找内置的或自定义的@@iterator对象并调用它的next()方法来遍历。

2.混合对象“类”

JS中只有对象,不存在可以被实例化的类。一个对象不会被复制到其他对象,它们会被关联起来。

但也有一个方法来模拟类的复制行为,称为混入

2.1 显式混入

function mixin(sourceObj,targetObj){
    
    
    for(var key in sourceObj){
    
    
        if(!(key in targetObj)){
    
    
            targetObj[key] = sourceObj[key]
        }
    }
    return targetObj
}
var Vehicle = {
    
    
    engines:1,
    ignition:function(){
    
    
        console.log("Turning on my engine.")
    },
    drive:function(){
    
    
        this.ignition()
        console.log("Steering and moving forward!")
    }
}
var Car = mixin(Vehichle,{
    
    
    wheels:4,
    drive:function(){
    
    
        Vehicle.drive.call(this)
        console.log("Rolling on all" + this.wheels + "wheels")
    }
})

现在Car中就有了一份Vehicle属性和函数的副本了。

如果直接执行Vehicle.drive(),函数调用中的this会被绑定到Vehicle对象而不是Car对象,这和我们预期不符,因此要用.call(this)来确保drive()在Car对象的上下文中执行。

虽然复制后总体上两者已基本分离,但实际上还是有一些巧妙的方法可以影响到对象,比如引用同一个对象/数组。

2.2 隐式混入

var Something = {
    
    
    cool:function(){
    
    
        this.greeting = 'hello world'
        this.count = this.count?this.count+1:1
    }
}
Something.cool() 
Something.greeting  //'hello world'
Something.count   // 1

var Another = {
    
    
    cool:function(){
    
    
        //隐式把Someting混入Another
        Something.cool.call(this)
    }
}
Another.cool()
Another.greeting   //'hello world'
Another.count      //1

这里我们通过this绑定隐式地把Something混入了Another,最终结果是Something.cool()中的赋值操作都会应用在Another对象上而不是Something对象上(最后一个count不是2而是1)。

2.3 小结

在JS中意味着复制,它并不会像传统的类那样自动创建对象的复制,需要我们手动来进行复制,而混入可以用来模拟类的复制行为。但在JS中模拟类的行为可能会产生很多隐患,因此不常使用。

猜你喜欢

转载自blog.csdn.net/weixin_40764047/article/details/111339642