摘要:引言对于面向对象,相信大家一定不陌生。创建对象面向对象第一步是什么答创建对象。构造函数优于工厂模式也是在于它可以通过辨识出一类的对象。
引言
对于面向对象,相信大家一定不陌生。最近看了一些关于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: "张全蛋"}
现在的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指向这个新对象 为这个对象添加属性 返回这个对象
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.ucloud.cn/yun/83013.html
摘要:还有一个问题,就是不能在创建子类性时,像父类型的构造函数传递参数。组合继承将原型链和借用构造函数组合到一起,发挥两者之长的一张继承模式,下面来看个例子。组合继承最大的问题是无论在什么情况下,都会调用两次父类型构造函数。 继承 继承是面向对象语言中特别重要的概念,js的继承主要是靠原型链实现的。 原型链!!! 看到我给标题打了三个叹号吗,这里真的很重要!这里真的很重要!这里真的很重要!j...
摘要:我们通过这个构造函数为原型对象添加其他方法和属性。这个属性存在与实例与构造函数的原型对象上直接,而不存在于实例与构造函数之间。李小花班花张全蛋张全蛋李小花李小花我们在遍历对象的的属性的时候,经常需要判断属性是否来自于对象的原型还是属性。 引言 上面说了创建对象有字面量方式和工厂模式还有构造函数模式,结果发现他们都各自有缺点,所以下面再给大家介绍几种创建对象的方式,争取能找到一种无痛的模...
摘要:会造成内存浪费的问题构造函数继承声明父类声明子类生成实例组合式继承组合式继承是汲取了两者的优点,既避免了内存浪费,又使得每个实例化的子类互不影响。 写在前面 既然是浅谈,就不会从原理上深度分析,只是帮助我们更好地理解... 面向对象与面向过程 面向对象和面向过程是两种不同的编程思想,刚开始接触编程的时候,我们大都是从面向过程起步的,毕竟像我一样,大家接触的第一门计算机语言大概率都是C语...
摘要:不必在构造函数中定义对象实例的信息。其次,按照一切事物皆对象的这饿极本的面向对象的法则来说,类本身并不是一个对象,然而原型方式的构造函数和原型本身也是个对象。第二个问题就是在创建子类型的实例时,不能向超类型的构造函数中传递参数。 前言 对象(Object)应该算是js中最为重要的部分,也是js中非常难懂晦涩的一部分。更是面试以及框架设计中各出没。写这篇文章,主要参考与JavaScrip...
阅读 3786·2023-04-25 20:00
阅读 3127·2021-09-22 15:09
阅读 524·2021-08-25 09:40
阅读 3435·2021-07-26 23:38
阅读 2216·2019-08-30 15:53
阅读 1109·2019-08-30 13:46
阅读 2806·2019-08-29 16:44
阅读 2061·2019-08-29 15:32