JavaScript之“对象”学习笔记

358 阅读6分钟

对象

学习对象之前,应该先对javaScript的数据类型有一个简单的了解

数据类型

javaScript的数据类型分为两类:第一类为基本类型;第二类为引用类型

基本类型

  • Number (数字)
  • String (字符串)
  • Boolean (布尔值,true和false)
  • null (空)
  • undefined (未定义)

引用类型

  • Object (对象)

对象又可以分为:

  1. Function (函数)
  2. Array(数组)
  3. Date(日期)
  4. Regexp(正则)
  5. ...等等

如果想更加直观的方便输出的是哪种类型,可以使用typeof进行检验:

1. 对象字面量

对象字面量提供了一种非常方便的创建新对象值的表示法。一个对象字面量就是包围在一对花括号中的零或者多个“名/值”对。对象字面量可以出现在任何允许表达式出现的地方

   var empty_object = {}      //空对象
   var student = {
        "name": "zhangsan",
        "gender": "male"
    }

属性名可以是包括空字符串在内的任何字符串。在对象字面量中,如果属性名是一个合法的JavaScript标识符且不是保留字,并不强制要求用引号括住属性名。所以用引号括住属性值"zhangsan"是必须的,但是否括住属性名"name"则是可选的。使用逗号用来分隔多个“名/值”对。

属性的值可以从包括另一个对象的字面量在内的任意表达式中获得。对象是可以嵌套的:

例如:person对象嵌套一个hobby对象

 var person = {
            name: "zhangsan",
            age: 21,
            hobby: {
                eat: "cake",
                play: "computer games"
            }
        }

2. 检索

要检索对象中包含的值,可以采用在[]后缀中括住一个字符串表达式的方式。如果字符串表达式是一个常数,而且是一个合法的JavaScript标识符而非保留字,也可以用属性名.属性名来表示,推荐使用属性名.属性值的方式。

如果是一个不存在的属性名,则会返回undefinde

例如:输出一个student对象不存在的age属性

可以使用||运算符填充默认值

 var empty_object = {}
        var student = {
            name: "zhangsan",
            gender: "male"
        }
        var age = student.age || "none"
        console.log("输出:" + age)

尝试检索一个undefined值会导致TypeError异常

var empty_object = {}
        var student = {
            name: "zhangsan",
            gender: "male"
        }
        console.log(student.age)
        console.log(student.age.model)

可以通过&&运算符来避免

console.log(student.age && student.age.model)

输出undefined,避免报错。

3. 更新

对象中的值可以通过赋值语句来更新。

  1. 如果属性名已经存在在于对象中,那么这个属性的值将被替换。

2. 如果对象之前没有这个属性,则该属性会添加到对象中。
可以看到运行之后student对象多了一个age属性

4. 引用

对象通过引用来传递。它们永远不会被拷贝

var student = {
        "name": "zhangsan",
        "gender": "male"
    }
    var studentCopy = student;
    studentCopy.name = 'wangwu'
    //因为studentCopy和student是指向同一个对象的引用,所以student的name也改变成wangwu了
    console.log(student.name)
    console.log(studentCopy.name)
    console.log(student.name === studentCopy.name)

    var a={},b={},c={}
    //a、b和c每个都引用不用的空对象
    a=b=c={}
    //a、b和c都引用同一个空对象

输出结果为:

5. 原型

每个对象都连接到一个原型对象,并且可以从中继承属性。给Object增加一个beget方法,用于创建一个使用原对象作为原型的新对象。

        //定义一个student作为原型对象
      var student = {
            name: "zhangsan",
            gender: "male",
            age: 18,
            score: 80
        }
        if (typeof Object.beget != 'function') {
            Object.beget = function(o) {
                var F = function() {}
                F.prototype = o
                return new F()
            }
        }
        //定义一个新对象,使用student为原型
        var collegeStudent = Object.beget(student)
        //更新新对象不会改变该对象的原型
        collegeStudent.name = "zhaoliu";
        console.log(student.name)
        console.log(collegeStudent.name)
        //新对象未定义的属性值继承原型的属性值
        console.log("新对象:" + collegeStudent.gender)

原型连接在更新时是不起作用的,例如在对某个对象做出改变时,不会触及到该对象的原型;

原型连接只有在索引值的时候会被用到,如果尝试获取某个对象的属性值,且该对象并没有此属性名,则JavaScript会从原型对象找,依次类推,直到找到Object.prototype。如果要找的属性完全不存在与原型链中,那么结果就是undefined。这个过程叫委托

原型关系是一种动态关系,如果在原型中添加一个新的属性,该属性马上会对基于该原型创建的对象可见。

        //为原型添加一个birthday属性
        student.birthday = "1998-04-07"
        //新对象自动继承原型新添加的属性
        console.log("collegeStudent.birthday:" + collegeStudent.birthday)

输出:

6. 反射

检查对象并确定对象有什么属性,可以试着去检索该属性并验证取到的值。 使用typeof操作符对确定属性的类型很有帮助:

    var student = {
                name: "zhangsan",
                gender: "male",
                age: 18,
                score: 80
            }
            //输出student的属性类型
        console.log("student的属性:" + typeof student.name)
        console.log("student的属性:" + typeof student.gender)
        console.log("student的属性:" + typeof student.age)
        console.log("student的属性:" + typeof student.score)

        //注意:原型链中的属性也会产生值,例如:
        console.log("原型链的属性:" + typeof student.toString)

输出

通常情况下,我们并不需要去检索原型链的属性,有多种方法可以做到,例如通过typeof判断并剔除掉function,但是,这样做的话,所有的函数都会被剔除。 另一种方法是使用hasOwnProperty方法,如果对象拥有独有的属性,他将返回true。hasOwnProperty方法不会监查原型链。

        //属于自己的
        console.log(student.hasOwnProperty('name'))
        //属于自己的
        console.log(student.hasOwnProperty('age'))
        //属于原型链的
        console.log(student.hasOwnProperty('toString'))

输出

7. 枚举

  1. 使用for in语句可以用来遍历一个对象的所有属性名(包括函数),可以使用typeof来排除函数
    var student = {
            name: "zhangsan",
            gender: "male",
            age: 18
        }
        for (name in student) {
            if (typeof student[name] !== 'function')
                console.log(name + ':' + student[name])
        }

2. 如果对象有一些属性不需要,或者你想按照一定的顺序获取属性,可以使用一个数组来获取

    var properties = [
            'age',
            'name'
        ]
        for (var i = 0; i < properties.length; i++) {
            console.log(properties[i] + ":" + student[properties[i]])
        }

3. 还可以使用Object.keys() 方法,该方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。

   var student = {
            name: "zhangsan",
            gender: "male",
            age: 18
        }
        console.log(Object.keys(student));

8. 删除

delete运算可以用来删除对象的属性,它将一处对象中确定包含的属性。

       var student = {
            name: "zhangsan",
            gender: "male",
            age: 18,
            score: 80
        }
        //删除自己的属性
        console.log("删除前")
        console.log(student)
        delete student.name
        console.log("删除后")
        console.log(student)

可以看到,name属性已经被删除

但是delete删除不会触及原型链中的任何对象。如:

        var student = {
            name: "zhangsan",
            gender: "male",
            age: 18,
        }
        if (typeof Object.beget != 'function') {
            Object.beget = function(o) {
                var F = function() {}
                F.prototype = o
                return new F()
            }
        }
        //定义新的collegeStudent对象,使用student对象为原型
        var collegeStudent = Object.beget(student)
        console.log("删除前" + collegeStudent.name)
        //collegeStudent尝试删除原型的属性
        delete collegeStudent.name;
        console.log("删除后" + collegeStudent.name)
    </script>

可以看到,删除前后输出一致,删除原型属性并未成功。

9. 减少全局变量污染

JavaScript可以随意的定义全局变量,但是,全局变量降低了程序的灵活性,应该避免这个问题。 最小化的使用全局变量的方法就是在应用中只创建唯一一个全局变量:

var CONTAINER = {} 这时可以将这个变量当成应用的容器;

        var CONTAINER = {}
        CONTAINER.student = {
            "name": "zhangsan",
            "gender": "male"
        }
        CONTAINER.person = {
            name: "",
            age: 21,
            hobby: {
                eat: "cake",
                play: "computer games"
            }
        }

这要把多个全局变量定义在一个名称空间下,就可以显著降低与其他程序、组件或类库中间互相影响的可能性,程序的可读性也更好。