美文网首页
面向对象

面向对象

作者: 海山城 | 来源:发表于2017-11-29 23:31 被阅读0次

    理解对象

    JS 中的对象是一系列无序 key: value 的集合

    var obj = { a: 1, b: 2}
    var person = {
        name: 'hunger',
        printName: function(){
            console.log('My name is hsc')
        }
    }
    

    但假设我们定义一个函数

    function sum(a, b){
        return a + b
    }
    
    console.log(sum.name)   // => sum
    console.log(sum.length)  //2
    

    会发现,函数 sum也有很多属性,从这个角度看,函数也是 js 对象的一种

    构造对象

    (1) 通过字面量来构造一个对象
    这种方法缺点很明显:
    太麻烦了,每次构建一个对象都是复制一遍代码

    var obj1 = {
        name: 'Byron',
        age: 20,
        printName: function(){
            console.log(obj1.name);
        }
    }
    var obj2 = {
        name: 'Casper',
        age: 25,
        printName: function(){
            console.log(obj2.name);
        }
    }
    

    (2) 使用函数做自动化
    这种方法解决了上一种的代码重复的问题,但是这种方法还是不够完美。这种方式构造出来的对象类型都是Object,没有识别度。并且每个对象都有一个相同的printName方法,造成了内存的浪费

    function createObj(name, age)
    {
      var obj = {
        name: name,
        age: age,
        printName: function(){
          console.log(this.name)
        }
      }
      return obj
    }
    var obj = createObj('hsc', 25)
    obj.printName()
    

    (3) 通过new运算符来构造函数,返回一个对象实例

    function Person(name, age){
        this.name = name;
        this.age = age;
        this.printName = function(){
                console.log(this.name);
        }
    }
    var p1 = new Person('Byron', 25);
    var p2 = new Person('HSC', 30);
    

    这种方式创建对象首先需要了解几个知识点

    • new 运算符接受一个函数 F 及其参数:new F(arguments...)
    • function作为构造函数(通过new操作符调用)的时候会返回一个类型为function的name的对象
    • 前面说过函数也是一个对象,function有个constructor的属性指向其本身

    那么,通过new运算符构造函数从而创建出一个对象的过程具体如何实现的呢?即var p1 = new Person('Byron', 25)具体发生了什么呢?
    ①创建一个空对象。空对象的 proto 属性被浏览器自动设置为 F.prototype (具体参考原型和原型链的介绍)
    ②初始化该对象。函数 F 被传入参数并调用,关键字 this 被设定为该空对象,可按照下面理解

    function Person(name, age){
        var this = {};
        this.name = name;
        this.age = age;
        this.sayName = function(){
                console.log(this.name);
        }
        return this
    }
    var p1 = new Person('Byron', 25);
    var p2 = new Person('HSC', 30);
    

    ③返回赋值完成的对象
    注:在函数中return 基本类型,构造函数时。没有影响,但是return一个对象时,就会有影响。如下

    function Person(name, age){
        this.name= name;
        this.age = age;
        return 1 //情况①
        return {a:1,b:2} //情况②
    }
    var p1 = new Person('Byron', 25); //情况①结果: p1{name:"Byron", age:25}
    var p1 = new Person('Byron', 25); //情况②结果: p1{a:1,b:2}
    

    这种方法构建的对象具有识别度,为什么这么说呢?先来看一看instanceof这个操作符,它可以判断对象是否为某个函数的实例。注意instanceof判断的是对象(1 instanceof Number 结果是false)

    p1 instanceof Person  //true
    p1 instanceof Object   //true
    p1 instanceof Animal  //false
    

    可见通过new构造出来的对象,是属于创建它的函数的一个实例。这个创建实例的函数就是js中的类
    识别度的问题是解决了,可是这样构建对象,同样每个对象都有相同的printName方法,造成了内存的浪费,这就要提到prototype(原型)了。
    每个函数内部都有一个prototype对象,实例调用方法(p1.printName())时,会先去自身找有没有这个方法,找不到,会自动去__proto__中找,也就是F.prototype中找。这样重复的方法(比如printName)等可以放到F.prototype中(原型,相当于一个公共容器),可以减少内存的浪费。
    所以最终的代码可以改成这样

    function Person(name,  age){
        this.name = name;
        this.age = age;
    }
    Person.prototype.printName = function(){
      console.log(this.name);
    }
    var p1 = new Person('Byron', 25);
    var p2 = new Person('HSC', 30);
    

    注:公共容器中的函数中的this也是指的是调用该函数的对象(所以p1.printName输出的是Byron,而p1.__proto__.printName输出的是undefined,因为p1.__proto__(即Person.portotype)并没有name属性)
    所以,现在知道了通过new F 来构造对象是最好的了吧!

    相关文章

      网友评论

          本文标题:面向对象

          本文链接:https://www.haomeiwen.com/subject/tfovpxtx.html