浅谈js面向对象

引言

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

什么是对象

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

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

这是我们最常见的对象,这个对象是通过对象字面量形式创建的。

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

属性类型

前端精品教程:百度网盘下载

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指向这个新对象 为这个对象添加属性 返回这个对象

person1、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就会多一次标识符解析,标识符(通常指命名)的解析是有代价的,实际上没有那种计算机操作可以不产生性能开销。在执行环境的作用域链(扯到作用域链就一定会扯到闭包问题,以后有空再仔细聊聊闭包)中,一个标识符所在的位置越深,它的读写速度也就越慢。也就是说函数中读写局部变量总是最快的,而读写全局变量总是最慢的。因为全局变量总是在执行环境作用域的末端。其实我们可以将函数移出来当全局函数来处理,但那样会造成全局函数污染,这里就不多做介绍。

转载于:https://www.cnblogs.com/aillabig/p/9785950.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值