对于面向对象,相信你们必定不陌生。最近看了一些关于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: "张全蛋"}
如今的name属性是只读的,若是是严格模式的话,
这样作还会报错。一样的也适用于其余属性,我这里就不一一演示了。
注意⚠️,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就会多一次标识符解析,标识符(一般指命名)的解析是有代价的,实际上没有那种计算机操做能够不产生性能开销。在执行环境的做用域链(扯到做用域链就必定会扯到闭包问题,之后有空再仔细聊聊闭包)中,一个标识符所在的位置越深,它的读写速度也就越慢。也就是说函数中读写局部变量老是最快的,而读写全局变量老是最慢的。由于全局变量老是在执行环境做用域的末端。其实咱们能够将函数移出来当全局函数来处理,但那样会形成全局函数污染,这里就很少作介绍。