面向对象

2017-11-29  本文已影响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运算符构造函数从而创建出一个对象的过程具体如何实现的呢?即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 来构造对象是最好的了吧!

上一篇下一篇

猜你喜欢

热点阅读