js面向对象浅谈(一)

引言

对于面向对象,相信你们必定不陌生。最近看了一些关于es6面向对象的知识,正好经过这篇文章把关于面向对象的东西给串起来分享给你们。前端

什么是对象

不少人会鄙视我,说你这篇文章是骗骗刚入行的小朋友的吧,什么是对象我还能不知道?骂个人吃瓜群众先冷静一下,你可能对对象一无所知。vue

{
    name: '李小花',
    sayname () {
        console.log(this.name)
    }
}

这是咱们最多见的对象,这个对象是经过对象字面量形式建立的。程序员

对象的含义是无序的集合,其属性能够包含基本值、对象或者函数。es6

属性类型

js中有两种内置的属性,数据属性和访问器属性,这两个属性是只有内部才能访问的属性,因此这些属性都放在了两对方括号中,如[[enumerable]],你们在vue中常常面试

数据属性

数据属性包含一个数据值的位置。在这个位置能够读取和写入值。数据属性有 4 个描述其行为的特性。
  • [[Configurable]]:表示可否经过 delete
    删除属性从而从新定义属性,可否修改属性的特性,或者可否把属性修改成访问器属性。后端

  • [[Enumerable]]:表示可否经过 for-in 循环返回属性。浏览器

  • [[Writable]]:表示可否修改属性的值。闭包

  • [[Value]]:包含这个属性的值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为
    undefined。函数

如今有一个对象经过字面量建立性能

var person =  {
         name: '张全蛋'
     }

[[Configurable]]、[[Enumerable]]、[[Writable]]属性都会被设置为true,[[Value]]被设置为了‘张全蛋’。若是想修改这几个属性任意一个值,必须使用大名鼎鼎的Object.defineProperty()方法,为啥说它大名鼎鼎,由于若是你接触过vue,就知道他核型就是经过这个方法实现的。

var person = {};

Object.defineProperty(person, 'name', {
    writable: false,
    value: '张全蛋'
})
Object {name: "张全蛋"}

clipboard.png

如今的name属性是只读的,若是是严格模式的话,

clipboard.png

这样作还会报错。一样的也适用于其余属性,我这里就不一一演示了。

注意⚠️,Object.defineProperty()方法只有现代浏览器才支持,IE8只是部分实现。

访问器属性

访问器属性不包含数据值,它们包含一对 getter 和 setter 函数(这两个函数都不是必须的)。在读取访问器属性时,会调用
getter 函数,这个函数负责返回有效的值;在写入访问器属性时,会调用 setter
并传入新值,这个函数负责决定如何处理数据。访问器属性有以下 4 个特性。

  • [[Configurable]]:表示可否经过 delete 删除属性从而从新定义属性,可否修改属性的特性,或者可否把属性修改成数据属性。

  • [[Enumerable]]:表示可否经过 for-in 循环返回属性。

  • [[Get]]:在读取属性时调用的函数。默认值为 undefined。

  • [[Set]]:在写入属性时调用的函数。默认值为 undefined。

访问只能经过bject.defineProperty()方法来定义。

var book = {
  _year: 2004,
  edition: 1
};

Object.defineProperty(book, 'year', {
  get: function() {
    return this._year;
  },
  set: function(newValue) {
    if (newValue > 2004) {
      this._year = newValue;
      this.edition += newValue - 2004;
    }
  }
});

book.year = 2005;
alert(book.edition);  // 2
alert(book.year); // 2005

访问器属性 year 则包含一个 getter 函数和一个 setter 函数。getter 函数返回 _year 的值,setter 函数经过计算来肯定正确的版本。所以,把 year 属性修改成 2005 会致使 _year 变成 2005,而 edition 变为 2。这是使用访问器属性的常见方式,即设置一个属性的值会致使其余属性发生变化。

注意⚠️,访问器属性只有IE9以上才支持,这就是为何VUE只能支持到IE9的缘由。

建立对象

js面向对象第一步是什么?答:建立对象。建立对象有不少中方式,咱们最经常使用的是对象字面量来建立对象,var obj = {},你看我这不就建立了一个对象了吗,我还干吗要继续了解那些奇葩的方法呢?这么想的人活该单身,多掌握些找对象只有好处没有坏处哈。正经的,高阶上有这么一句话,使用对象字面量建立单个对象,有个明显的缺点,使用同一个接口建立不少对象,会产生大量重复的代码。为了解决这个问题,咱们须要了解下面?这些方式。

工厂模式

工厂模式很简单,贴上一段代码。

function createPerson (name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function () {
        alert(this.name)
    }
    return o;
}
var person1 = createPerson("铁蛋", 20, '工头')

var person2 = createPerson("李四", 30, '挖掘机驾驶员')

工厂模式的优势没必要多说,若是我想建立两个对象,上面一样有name、age、job属性,这样就省去了建立包含一样属性多个对象的麻烦,可是却没有解决对象识别的问题。
有人会问,对象识别是什么鬼。咱们建立对象是为了模仿类的概念,这里的person1,person2应该都属于“人”一类,可是显然咱们如今没办法将他们归为一类,因此这个时候逼格更高的方法出现了。

构造函数模式

function Person (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        alert(this.name)
    }
}
var person1 = new Person("铁蛋", 20, '工头')
var person2 = new Person("李四", 30, '挖掘机驾驶员')

这里有个显然很突出的地方,就是这个Person的P是大写的,其实大写不是必须的,听说这种习惯是不少后端程序员转前端带过来的。构造函数模式跟工厂模式不同的地方还在于,没有用new Object显式地建立对象,一样没有return语句。
那咱们在new完一个构造函数,实则产生一个实例,咱们new一个构造函数,会经历如下神奇的四步。

建立对象 将this指向这个新对象 为这个对象添加属性 返回这个对象

person一、person2 是咱们经过 new Person这个构造函数获得的,因此这两个的构造函数都是Person,constructor(构造函数)属性就都是Person,我之前一直都不能理解constructor是什么东西,如今才理解原来constructor的中文翻译就是构造函数?,也难怪我英文最熟的一句就是"hello kugou"了。咱们能够经过使用instanceof操做符来检测对象的类型。

let arr = new Array(2)
 arr instanceof Array  // true
 arr instanceof Object // true

构造函数优于工厂模式也是在于它能够经过instanceof辨识出一类的对象。

接下来你们看一段通常没品的面试官会考的问题

this.name = "张全蛋"
function Person (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        alert(this.name)
    }
}
var person1 = new Person("铁蛋", 20, '工头')
var person2 = Person("李小花", 30, "厂花")

person1.sayName()  // 铁蛋
person2.sayName() // 报错

咱们首先要肯定一个概念,构造函数也是函数,若是不用new 的方式来调用它,它跟普通函数没有半毛钱的区别,咱们知道在函数的做用域是window,因此this指向的是window,因此这段代码person2对象this就是window,window没有sayName属性,因此会报错。若是经过的是new方式调用的话,咱们上面也讲了,为将this赋值给这个对象,因此this就是person1这个实例。那么构造函数是否是没有缺点呢?显然是不对的,由于我已经这么问了。构造函数的缺点,每一个方法都要在实例上从新建立一遍,js中函数也是对象,定义函数就是实例化对象

function Person (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = new Function () {
        alert(this.name)
    }
}

每次new一个function就会多一次标识符解析,标识符(一般指命名)的解析是有代价的,实际上没有那种计算机操做能够不产生性能开销。在执行环境的做用域链(扯到做用域链就必定会扯到闭包问题,之后有空再仔细聊聊闭包)中,一个标识符所在的位置越深,它的读写速度也就越慢。也就是说函数中读写局部变量老是最快的,而读写全局变量老是最慢的。由于全局变量老是在执行环境做用域的末端。其实咱们能够将函数移出来当全局函数来处理,但那样会形成全局函数污染,这里就很少作介绍。

相关文章
相关标签/搜索