JavaScript发明之始,从技术上来说就是一门面向对象的语言,但在ES6以前,JS的不少特性和传统的面向对象语言有所不一样,好比没有类的概念(ES6有了class)。今天结合《JS高编》第六章开始回顾和深刻学习面向对象部分,包括对象、原型、原型链、继承等部分。程序员
谈JS的对象以前,先复习一下面向对象的基础概念和特色吧。
面向对象OOP(Object-oriented programming),结合维基百科和百度百科的阐述,再谈谈个人理解。函数
官方解释:
面向对象就是基于对象概念,以对象为中心,以类和继承为构造机制,来认识、理解、刻画客观世界和设计、构建相应的软件系统学习
个人理解:
在JavaScript的世界中,万物皆对象。任何事和物你均可以将其定义为一个对象,程序员界有个笑话就是单身狗能够new一个对象嘛......个人粗浅理解,若是我是一个上帝,这个世界的任何人和事相对于我而言都是一个对象。有了控制对象的权力,我就能够对他们进行任何操做。针对事,我能够发布一个号令,发布一个政策,告诉别人怎么执行,何时开始,何时结束。针对人,我能够把他们分为男人、女人,这就是类。而后我能够限制他们的儿子是男人仍是女人,是男人那就必须有和爸爸同样的性别特征,这就是继承。我还能够控制他们什么时间作什么事等等,整个过程我都是围绕某个对象来展开的,那么这个过程叫作面向对象。测试
特色:
1.类
2.继承
3.封装
4.多态
具体的在后面学习和复习时再谈。this
let obj = { name:"勾鑫宇", age:23 }
1.数据属性:[[Configurable]],[[Enumerable]],[[Writable]],[[Value]]
2.访问器属性:[[Configurable]],[[Enumerable]],[[Get]],[[Set]]
spa
书上讲到属性类型时,只是简单提了一下是为了表示对象的特性,描述了属性的特征,而且在JS中不能直接访问。光看介绍不太理解究竟是干什么的,可是看了数据属性的内容以后,发现不难理解。翻译
个人理解,数据属性就是咱们能够从根源去控制一个对象的属性是否能被修改、删除、循环等,并能够经过访问器属性在别人不知道的状况下进行数据处理。经过Object.defineProperty()
这个方法,咱们能够去设置这些限制对象属性操做的值,从而限制别人对某个对象属性的操做。举个例子,上面的obj
这个对象的name
属性的值是“勾鑫宇”,从如今起我不想任何人可以修改它的值,那么我就经过数据属性来将这个属性设置为不可修改,别人用obj.name = "张三"
来修改就不会生效了。而我若是想在修改name
属性的值后同时让age
也跟着改变,那么此时就能够用访问器属性来进行数据处理。设计
咱们是经过Object.defineProperty()
这个方法来进行两种属性的设置。那么首先了解一下Object.defineProperty()
这个方法,它接收三个参数:code
Object.defineProperty(对象名,属性名,描述符对象) //举例 Object.defineProperty(obj,"name",{ writable:false,//设置不可修改 enumerable:false//设置不可循环到该属性 })
能够在对象的constructor中找到该方法对象
同时,咱们能够经过Object.getOwnPropertyDescriptor()
方法来查看这四个特性的设置状况。接受两个参数:
Object.getOwnPropertyDescriptor(对象名,属性名)
数据属性包含一个数据值的位置。在这个位置能够读取和写入值,有4个描述其行为的特性。
下面就具体来对每一个数据属性进行分析:
1.[[Writable]]
:英文意思译为“可写的”,可理解为“可修改的”。这个属性用来设置对象的某个属性是否能被修改,默认为true。
//举例 let obj = { name:"勾鑫宇", age:23 } Object.defineProperty(obj,"name",{ writable:false,//设置不可修改 }) //这时再进行修改就不会生效,严格模式下会报错 obj.name = "张三" console.log(obj.name)//输出的仍是勾鑫宇
严格模式报错
2.[[Enumerable]]
:英文译为“可数的,可枚举的”,是否支持for-in循环来返回属性,默认为true。
//举例 let obj = { name:"勾鑫宇", age:23, gender:male } Object.defineProperty(obj,"name",{ enumerable:false,//设置不可经过for-in循环返回 }) //循环测试 for(let i in obj){ console.log(i)//输出结果为age,gender,没有name属性,效果就像隐藏了这个属性。 } //但这时咱们的name属性仍是存在的 console.log(obj)
3.[[value]]
:这个就不说翻译了,你们都知道,就是值。这个特性是设置咱们对象某个属性的值,读值、写值都在这里,默认值为undefined。
//举例 let obj = { name:"勾鑫宇", age:23, gender:male } Object.defineProperty(obj,"name",{ value:"张三",//设置name的值为张三 }) console.log(obj.name)//输出为张三 //设置value不影响后面再次修改值,value至关于修改了一次你最早定义的值而已。 obj.name = "傻逼" concole.log(obj.name)//输出为“傻逼”
4.[[Configurable]]
:英文译为“可配置的”,这个和前面的Writable有什么区别呢?放到最后讲是有缘由的。前面有设置修改,设置循环,设置值,可是尚未设置是否可删除。Configurable就是作这个事情的。它表示可否经过delete删除属性从而从新定义属性,默认值为true。
//举例 let obj = { name:"勾鑫宇", age:23, gender:male } Object.defineProperty(obj,"name",{ configurable:false,//不容许删除属性 }) delete obj.name//报错"Uncaught TypeError: Cannot delete property 'name' of #<Object>"
这个属性还有最重要的一个特色,就是当你设置为false事后,就不能再设为true了,即便你设置了也无效。书上说得个时候你再设置value,enumerable都不会生效,只能设置writable,那么咱们来试试。
//接着上面再把configurable修改成true Object.defineProperty(obj,"name",{ configurable:true, }) //此时为会报错“Uncaught TypeError: Cannot redefine property: name” //接着再次调用 Object.defineProperty(obj,"name",{ value:'张三' }) console.log(obj)//此时打印出来的是“张三”,而并书上所说的不能修改value的值。 //设置enumerable Object.defineProperty(obj,"name",{ enumerable:false//报错"Uncaught TypeError: Cannot redefine property: name" })
测试了不少遍,value值在configurable为false的状况下仍然是能够修改的。
//设置writable Object.defineProperty(obj,"name",{ writable:false//不会报错 }) //再次修改writable Object.defineProperty(obj,"name",{ writable:true//报错“Uncaught TypeError: Cannot redefine property: name” }) //修改value Object.defineProperty(obj,"name",{ value:"张三"//报错“Uncaught TypeError: Cannot redefine property: name” })
上面设置writable说明在configurable和writable同时为false的状况下,就不能再修改任何值了。
Configurable还能控制是否能修改成访问器属性,这个在访问器属性的时候再讲。
访问器属性不包含数据值,包含一对getter和setter函数,读取访问器属性时调用getter,写入时调用setter,并负责处理数据。
访问器属性一样有4个特性值能够设置:
1.[[Configurable]]
:和数据属性的功能同样,只是有一点区别就是可否修改成数据属性。
2.[[Enumerable]]
:和数据属性的功能同样。
3.[[Get]]
:读取属性时调用,默认值为undefined。
get函数就是可以让你读取对象中的某个属性,前提是这个属性自己是只能经过对象方法来访问的,也就是说定义时要有下划线记号,不然自己就能直接访问的话,用get也没有意义了。
//举例 let obj = { _name:"勾鑫宇",//下划线是一种记号,表示只能经过对象方法访问 age:23, gender:male } console.log(obj.name)//输出为undefined //用get方法来读取这个属性,并返回给对象 Object.defineProperty(obj,"name",{ get(){ return this._name } }) console.log(obj.name)//输出“勾鑫宇”
4.[[Set]]
:set函数就是写入属性的时候调用,默认值为undefined。
set函数会接收一个参数,这个参数就是咱们修改对象或添加对象的属性值。
//举例 let obj = { _name:"勾鑫宇", age:23, gender:male } //用set方法来写入这个属性 Object.defineProperty(obj,"name",{ set(val){ this._name = 'hh'+val } }) obj.name = "张三" console.log(obj.name)//输出为undefined
这个时候咱们就无法进行下去了,由于不管怎样,都是输出undefined
。缘由就是由于咱们没有使用get函数去读取咱们写入的属性值,记住name
在初始定义时就必须是_name
。
//同时使用get和set let obj = { _name:"勾鑫宇", age:23, gender:male } //用set方法来写入这个属性 Object.defineProperty(obj,"name",{ get(){ return this._name }, set(val){ this. = 'hh'+val } }) obj.name = "张三" console.log(obj.name)//输出'hh张三'
从上面的代码就能够看出这个set和get函数的强大之处,那就是能够进行数据处理。咱们能够经过set函数来进行对象里不一样属性的关联,也能够实现属性值的各类计算。
//举例 let obj = { _name:"勾鑫宇", age:23, gender:male } //用set方法来进行不一样属性间的关联 Object.defineProperty(obj,"name",{ get(){ return this._name }, set(val){ if(val === '张三'){ this._name = val; this.age = 18 } } }) //修改属性值 obj.name = '张三'; console.log(obj)//输出 {name:'张三',age:18,gender:male}
除了Object.defineProperty()
方法,还有Object.defineProperties()
方法,顾名思义,复数形式就是能够同时定义多个属性。它接受两个参数:
Object.defineProperties(obj,{ name:{ writable:false }, age:{ configurable:true } ... })
这就是对属性类型的一个学习和理解,若有错误,请使劲点我。