Day.20 「初步认识 this,中央工厂式的自订物件~」 —— JavaSript 构造函式

Day.20 「初步认识 this,中央工厂式的自订物件~」 —— JavaSript 构造函式

如同学习函式一样!有时候我们会一直重复地做一件事,
当还是初学者的我们需要制作大量的个人资料物件时,通常第一个想法就是复制贴上~

const person = {
  name: "毛毛",
  gender: "男",
  sayName: function() {
    console.log( "大家好!我是" + person.name );
  }
}
const person2 = {
  name: "小黄",
  gender: "男",
  sayName: function() {
    console.log( "大家好!我是" + person2.name );
  }
}
/* ... */

一直重复制作一样的东西!
我们要发挥工程师的精神~看到一直有重复的程序码时,就要想办法简化它。
在学习自订物件之前,要先认识之前函式没说到的「this

this

浏览器在执行函式时,都会向函式传递一个隐藏的参数

  • 这个隐藏的参数就是今天的主角「this」,this 指向的是一个物件

    function echo () {
      console.log(this);
    }
    echo ();  // this 指向 window 这个物件
    
  • 随着函式执行的场合不同,this 的指向也会不同。

    function echoName () {
      console.log(this.name);
    }
    // 为 window 这个物件添加 name 属性,也就是在全局作用域宣告 name 变数
    var name = "我是 window 的 name 属性";  
    
    echoName ();  // "我是 window 的 name 属性"
    
    var obj = {
      name: "毛毛",
      sayName: echoName  // 物件添加函式
    }
    
    console.log(obj.sayName === echoName);  // true 用来确认是不是同一个函式
    
    obj.sayName();  // "毛毛"
    
  • 根据执行的场合不同,指向不同懒人包

    • 直接调用函式,this 的指向永远在 window
    • 使用物件的函式,this 的指向会在使用的那个物件
    • 使用建构函式,this 会指向新增建构函式的物件

当然这只是稍微认识了我们的 this,不过以目前的知识量,就能够的自订物件了!

利用函式新增物件

我们前面有说过,函式非常方便,可以把功能都写在函式里,例如我们现在要来自定义物件

function createPerson() {
  var obj = new Object;  // 新增一个物件
  obj.name = "毛毛",
  obj.gender = "男",
  obj.sayName = function() {
    console.log( "大家好!我是" + this.name );
  }
  return obj;
}
const person = createPerson();
console.log( person );
/*
   {
      name: "毛毛",
      gender: "男",
      sayName: function() {
        console.log( "大家好!我是" + this.name );
      }
   }
*/

但会发现这样新增的物件的是固定的!
这时我们利用函式的参数,就可以简化新增物件的步骤了。

function createPerson (name, gender) {
  var obj = new Object;  // 新增一个物件
  obj.name = name,
  obj.gender = gender,
  obj.sayName = function() {
    console.log( "大家好!我是" + this.name );
  }
  return obj;
}
const person = createPerson("毛毛", "男");
const person2 = createPerson("小黄", "男");
person.sayName();  // "大家好!我是毛毛"
person2.sayName();  // "大家好!我是小黄"

但如果这个时候~还想要自订一个宠物的物件,这样直接看会觉得 人的物件 与 宠物的物件 差不多。

function createPet (name, sex, animal) {
  var obj = new Object;  // 新增一个物件
  obj.name = name,
  obj.sex = sex,
  obj.animal = animal
  return obj;
}
const pet = createPet("小黄", "雄性", "小狗");
console.log( pet );   // {...}
console.log( person ) // {...} 

这时使用建构函式来真正意义上的自订物件,更加方便快速简单!

构造函式

自订一个构造函式,用来专门新增人的物件

  • 构造函式就是一个普通函式,新增的方法与普通的方法没有不同
  • 不同的是建构函式会习惯在首字母大写
function Person () {}

普通函式是直接调用,而构造函式是透过 new 关键字调用!

const 直接调用 = Person()
const 构造函式 = new Person()
console.log( 直接调用 );  // undefined
console.log( 构造函式 );  // {}

直接调用的函式,因为没有使用 return ,所以会自动返回 undefined

构造函式执行过程

  1. 会立刻自动新增一个物件
  2. 函式的 this 会指向该物件
  3. 逐行执行程序码(我们操作的部分)
  4. 将新增的物件作为返回值返回
function Person (name, gender) {
  this.name = name,
  this.gender = gender,
  this.sayName = function() {
    console.log( "大家好!我是" + this.name );
  }
}
const person = new Person("毛毛", "男");
console.log( person )  // Person {...}

这时你发现前面出现了 Person,再来用一个的宠物的构造函式。

function Pet (name, sex, animal) {
  this.name = name,
  this.sex = sex,
  this.animal = animal
}
const pet = new Pet("小黄", "雄性", "小狗");
console.log( person )  // Person {...}
console.log( pet )     // Pet {...}

这样就可以透过构造函式更直观的看同一类的物件

构造函式实例检查

JavaScript 有个语法 instanceof,可以用来检查,物件是否为该构造函式新增出来的实例。

console.log(person instanceof Person); // true  代表是由这个构造函式创建出来的
console.log(person instanceof Pet);    // false 代表不是由这个构造函式创建出来的

优化构造函式

我们前面的构造函式中,有为物件添加函式 sayName()

function Person (name, gender) {
  this.name = name,
  this.gender = gender,
  this.sayName = function() {
    console.log( "大家好!我是" + this.name );
  }
}
const person = new Person("毛毛", "男");
person.sayName();  // "大家好!我是毛毛"

而我们每新增一个物件,同时也跟着在物件内新增一个 sayName 函式

function Person (name, gender) {
  this.name = name,
  this.gender = gender,
  this.sayName = function() {
    console.log( "大家好!我是" + this.name );
  }
}
const person = new Person("毛毛", "男");
const person2 = new Person("小黄", "男");
console.log( person.sayName === person2.sayName );  // false  两个 sayName 不一样

发现 sayName 函式,彼此不相同,当新增了 10000 个 Person 物件,也会同时新增 10000 个 sayName 函式!而这 10000 个 sayName 函式其实都是一模一样的,会为了这一模一样的函式浪费记忆体空间!

这想当然是没有必要的事情,我们可以让所有物件共同使用一个函式。
直接在全局作用域定义一个 sayName 函式,在构造函式内赋值 sayName 函式,这时构造函式内找不到 sayName 函式,就会往外找 sayName 函式

function Person (name, gender) {
  this.name = name,
  this.gender = gender,
  this.sayName = sayName
}
function sayName() {
  console.log( "大家好!我是" + this.name );
}

const person = new Person("毛毛", "男");
const person2 = new Person("小黄", "男");
console.log( person.sayName === person2.sayName );  // true  两个 sayName 引用同一个函式,所以一样

当然这样也是有缺点,就是把函式定义在全局作用域会压缩到全局作用域的命名空间,而且多人协作的时候,也容易出问题

总结

今天稍微介绍了 JavaScript 的 「this」,它可是 JavaScript 的精随,少了 this 会有很多事情不能做,昨天介绍的记忆体堆叠,在使用物件型别的东西要特别注意,不然一不小心会让浏览器效能变低,网页卡卡的!


<<:  Unity自主学习(十五):认识Unity介面(6)

>>:  Day22-"气泡排序法"

Day 13 Decorator Part - 1

今天要介绍的是 Decorator,会先介绍用法之後再来看看为甚麽要用这个,因为该章节一开始的介绍大...

[DAY20]新手学Istio

I s t i o 什麽是Istio Istio是Google、IBM 和 Lyft一起开发的开源专...

[Day 13]每天前进一点应该也是进步吧?(後端篇)

挑战目标: MockNative Camp 今天来做教师的更新API,因为我没有实际看过教师更新的画...

EP 22: Create SQLite DB for TopStore App

Hello, 各位 iT邦帮忙 的粉丝们大家好~~~ 本篇是 Re: 从零开始用 Xamarin 技...

固执投资者的特质:金钱、想法、耐心、运气

固执的投资者须具备四种要素:金钱、想法、耐心、运气 – 德国股神 科斯托兰尼 科老对金钱的定义,不...