JavaScript 面向对象编程(一)


前言

JavaScript属于多范式编程,今天我们来探讨下JavaScript中的面向对象编程。本篇文章包含对象的属性描述符、原型、构造函数、原型链。


一、Object.defineProperty(obj,属性,属性描述符)

当我们需要对一个属性进行更加精准的操作时,可以使用属性描述符。或许说到属性描述符大家会有点陌生,因为在实际的开发中非常少使用到,但有看过vue2源码的小伙伴们,应该是知道vue2的响应式原理就是通过属性描述符来实现的。
在这里插入图片描述

话不多说直接上干货!属性描述符分为数据属性描述符和存取属性描述符。

1.数据属性描述符

configurable:是否可以通过delete删除属性,是否可以修改属性描述符类型,是否可以修改属性特性
enumerable:是否可以通过遍历出该属性(for…in…、Object.keys()等)
writable: 是否可以修改属性值
value:属性值

var obj = {name:"susan",age:18}
Object.definProperty(obj,"address",{
	configurable:true,
	enumerable:true,
	writable:true,
	value:"北京市"
})

2.存取属性描述符

configurable:是否可以通过delete删除属性,是否可以修改属性描述符类型,是否可以修改属性特性
enumerable:是否可以通过遍历出该属性(for…in…、Object.keys()等)
get: 获取属性
set:设置属性

var obj = {name:"susan",age:18,_address="北京市"}
Object.definProperty(obj,"address",{
	configurable:true,
	enumerable:true,
	get:function(){
		return this._address
	},
	set:function(value){
		this._address = value
	}
})

用途:1.对象中设置私有属性,不希望直接被外界获取或修改
2.用于截获对象中一个属性设置和被访问的过程(vue2的响应式原理)

二、原型

1.原型到底是啥玩意?

每一个对象都有一个特殊的内置属性[[prototype]],该属性本质是一个对象。
我们可以通过__proto__在浏览器中去查看下这个属性,但在开发中不要这样去获取到原型。ES5之后可以通过Object.getPrototypeOf()获取到原型。
但由于直接去获取一个对象的原型,会发现打印出来的是空对象,那是因为该对象上的很多属性的属性描述符的enumerable:false。那我们直接简单粗暴看下这个原型所有的属性描述符。
代码如下(示例):

var obj = {name:"susan",age:18}
console.log(Object.getOwnPropertyDescriptors(obj.__proto__))

打印结果:

 {"constructor":{"writable":true,"enumerable":false,"configurable":true},"__defineGetter__":{"writable":true,"enumerable":false,"configurable":true},"__defineSetter__":{"writable":true,"enumerable":false,"configurable":true},"hasOwnProperty":{"writable":true,"enumerable":false,"configurable":true},"__lookupGetter__":{"writable":true,"enumerable":false,"configurable":true},"__lookupSetter__":{"writable":true,"enumerable":false,"configurable":true},"isPrototypeOf":{"writable":true,"enumerable":false,"configurable":true},"propertyIsEnumerable":{"writable":true,"enumerable":false,"configurable":true},"toString":{"writable":true,"enumerable":false,"configurable":true},"valueOf":{"writable":true,"enumerable":false,"configurable":true},"__proto__":{"enumerable":false,"configurable":true},"toLocaleString":{"writable":true,"enumerable":false,"configurable":true}}

你一定会说给我看这个干啥?这玩意到底有啥用?
在这里插入图片描述

我们需要知道的是。当我们从一个对象中获取一个属性,会触发[[get]]操作。
1.当在该对象中查询某个属性,如果在该对象中可以找到就直接从该对象中获取
2.如果在该对象中没有找到,就会沿着该对象的原型链去找。
不信,咱们立马校验一下,我说的是否正确?

var obj = {name:"susan",age:18}
obj.__proto__ = {address:"北京市"}
console.log(obj.address)

打印结果:

> 北京市

在obj对象中并没有address属性,但是打印的结果是obj原型上的address属性。

2.new操作符

既然知道了原型的概念,那我们来说下当执行new操作符的时候,都做了些什么操作?
1.在内存中创建一个空对象
2.这个对象内部的__proto__属性被赋值为该构造函数的proptype属性(函数是一个对象,函数具有__proto(隐式原型)和函数独具的prototype(显示原型))
为了验证这一步的操作,直接上代码:

var Person = function(){
    this.name = "susan",
    this.age = 18
}
const person1 = new Person()
console.log(person1.__proto__ === Person.prototype)

打印结果:

> true

3.构造函数内部的this指向新创建出来的对象
4.执行函数中的代码
5.如果构造函数没有返回非空对象,则返回创建出来的新对象。

3.原型链

咱们带着几个疑问,来看下原型链。
1.既然原型是个对象,对象中又有内置的__proto__,那是不是可以obj.proto.proto.__proto__无限下去?
2.那如果不会无限查找下去,那顶层的原型到底是什么东西?
在这里插入图片描述

我们先来简单分析一下:对象可不可以理解成是通过Object构造函数创建出来的,那Object是所有对象的父类。当使用new操作符创建出来的对象隐式原型被赋值为Object构造函数的prototype属性。那prototype属性本身就是一个对象,含有__proto__属性,那我们直接看下Object的prototype属性中__proto__到底指向的是个什么东西?(这里有点绕,多看几遍理解一下)
接下来直接上代码验证下,咱们分析的对不对

var obj = {name:"susan",age:18}
console.log(obj.__proto__ === Object.prototype)

打印结果:

true
var obj = {name:"susan",age:18}
console.log(Object.prototype.__proto__)

打印结果:


> null

通过打印的结果可以看到,最后Object.prototype.proto = null,由此可以看出其实原型链并不是无限长的,当它查询到最后的原型指向null时就停止查询了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值