深入JavaScript对象

1.对象的创建

2.属性描述符

3.对象方法补充

4.构造函数创建对象

1)new的时候发生了什么

2)对象原型

3)函数原型

4)创建对象的内存表现

5)把prototype赋值为新的对象发生了什么,new的时候会创建多个函数,影响内存,如何解决

6)constructor

7)原型链

8)继承

5.class类

1.对象的创建 

// 对象的创建 四种方式
// 第一种
let obj={a:1}
console.log(obj.a);//1
// 第二种
let obj1=new Object()
obj1.a=1
console.log(obj1.a);//1
// 第三种  下文会讲
function ObjFn(){
  this.a=1
}
let obj2=new ObjFn()
console.log(obj2.a);//1
// 第四种  下文会讲
class Objclass{
   a=2
}
let obj3=new Objclass()
console.log(obj3.a);//2

2.属性描述符

1)内容:包括数据属性和描述属性:

2)数据属性可以设置configurable,enumerable,value,writable   

3)描述属性可以设置configurable,enumerable,set,get 

如果名字记不住可以通过Object里面的defineProperty的PropertyDescriptor查看 注意数据描述符里面是不能设置get和set的  描述属性里面不能设置value和writable 因为这两对属性是互斥的

4)关于各个属性的含义

configurable:是否可以删除和修改

enumerable:是否可以被遍历

value:属性对应的值

writable:是否可获取

set:对某个属性设置值的时候,执行的方法

get:对某个值获取的时候执行的方法

5)对于他们的默认值:

let obj={
  a:1
}
//设置属性描述符 
console.log(Object.getOwnPropertyDescriptor(obj,'a'));
//{ value: 1, writable: true, enumerable: true, configurable: true }
//获取属性描述符
Object.defineProperty(obj,'b',{})
console.log(Object.getOwnPropertyDescriptor(obj,'b'));
//{ value: undefined, writable: false, enumerable: false, configurable: false}

3.对象方法

1).Object.definePropertiy():设置单个描述符

let obj={a:21}
Object.defineProperty(obj,'b',{
  configurable:true,
  enumerable:true,
  value:'1',
  writable:true
})
console.log(obj);//{ a: 21, b: '1' }

2).Object.defineProperties():设置多个描述符

let obj={a:21}
Object.defineProperties(obj,
  {
  'b':{
    configurable:true,
    enumerable:true,
    value:'1',
    writable:true
  },
  'c':{
    configurable:true,
    enumerable:true,
    value:'2',
    writable:true
      }
  }
)
console.log(obj);//{ a: 21, b: '1', c: '2' }

3).Object.getOwnPropertyDescriptor():获取单个描述符

let obj={a:21}
Object.defineProperties(obj,
  {
  'b':{
    configurable:true,
    enumerable:true,
    value:'1',
    writable:true
  },
  }
)
console.log(Object.getOwnPropertyDescriptor(obj,'b'));
//   b: { value: '1', writable: true, enumerable: true, configurable: true },

4).Object.getOwnPropertyDescriptors():获取全部描述符

let obj={a:21}
Object.defineProperties(obj,
  {
  'b':{
    configurable:true,
    enumerable:true,
    value:'1',
    writable:true
  },
  }
)
console.log(Object.getOwnPropertyDescriptors(obj));
// {
//   a: { value: 21, writable: true, enumerable: true, configurable: true },
//   b: { value: '1', writable: true, enumerable: true, configurable: true },
// }

5).Object.preventExtensions() (在严格模式下会报错):禁止对对象添加属性

let obj={a:21}
Object.preventExtensions(obj)
obj.b=3
console.log(obj);//{ a: 21 }

6).Object.seal():禁止对对象添加,修改删除属性,其实是preventExtensions和configurable的结合

let obj={a:21}
Object.seal(obj)
obj.b=3
console.log(obj);//{ a: 21 }

7).Object.feeze():禁止对对象添加/删除/修改/读取值。其实是seal和writable:false的结合

let obj={a:21}
Object.freeze(obj)
obj.b=3
console.log(obj);//{ a: 21 }

8).Object.hasOwnProperty():对象里是否有这个属性,不包括原型链上的属性(原型链后面讲)

let obj={a:21}
// Object.create创造__proto__对象指向obj的对象
let info=Object.create(obj)
info.b=2
console.log(info.hasOwnProperty('a'));//false
console.log(info.hasOwnProperty('b'));//true

9).in/for in:in判断对象里是否有这个属性,包括原型链上的属性(原型链后面讲) for in是循环对象上的属性,包括原型链里面的也会被循环(原型链后面讲)

let obj={
  a:21
}
// Object.create创造__proto__对象指向obj的对象
let info=Object.create(obj)
info.b=2
// 原型链上的值也是属于true
console.log('b' in info);//true
console.log('a' in info);//true
// 会对对象以及原型链上的属性都遍历
for(let a in info){
  console.log(a);//打印a  b
}

10).对象  instanceof  类:原型链上是否有某个类,不能检测基础类型

class Ini{}
function namea(params) {}
let arr=[1,2]
console.log(arr instanceof Array);//true
console.log('a' instanceof String);//false  不能检测基础类型
// 非基础类型都是对象类型构造函数  基础类型都返回false
console.log(arr instanceof Object);//true 
console.log(namea instanceof Object);//true 
console.log({a:2} instanceof Object);//true 
console.log(Ini instanceof Object);//true 
console.log('a' instanceof Object);//false

11).对象.isPorototypeOf(对象):后面的对象的原型链上是否有前面那个对象,返回布尔值

var obj = {
  name: "why",
  age: 18
}
// Object.create创造__proto__对象指向obj的对象
var info = Object.create(obj)
var info1 = Object.create(info)
var inf2 = Object.create(info1)
console.log(obj.isPrototypeOf(inf2))//true

 12)Object.getPrototypeOf():获取对象原型

4.构造函数创建对象

一个普通的函数被使用new操作符来调用了,那么这个函数就称之为是一个构造函数,构造函数可以让我们方便的创建差不多的对象,缺点是构造函数里面如果有函数,每次创建对象的时候会创建一个新的函数,会占用内存,但是可以通过在构造函数里不命名函数,而是在构造函数的原型对象上命名就不会重复创建函数,下面是构造函数创建对象的示例:
//构造函数首字母一般大写是一种默认的规范
function ObjFn(){
  this.a=1
  this.fn=function(){}
}
//objFn就是构造函数 每次new的时候会构造一个函数
let obj=new objFn()
console.log(obj);//objFn { a: 1 }

1)new的时候发生了什么

p 1. 在内存中创建一个新的对象(空对象);
p 2. 这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性;(后面详细讲);
p 3. 构造函数内部的this,会指向创建出来的新对象;
p 4. 执行函数的内部代码(函数体代码);
p 5. 如果构造函数没有返回非空对象,则返回创建出来的新对象;

2)对象原型和函数原型

每个对象和函数都有一个原型,对象原型可以通过属性__proto__或Object.getPrototypeOf来获取,对于函数原型可以通过属性prototype来获取,在原型对象里面有一个属性constructor会指回构造函数

let obj={a:1}
// 如果是这种创建方式(new Object同理) 原型直接是Object的原型对象
console.log(obj.__proto__);//[Object: null prototype] {}
console.log(obj.__proto__.__proto__);//null 对象是顶级对象 所以对象的原型是null
function ObjFn(){}
let obj1=new ObjFn()
console.log(obj1.__proto__);// {}是ObjFn的原型
console.log(obj1.__proto__.__proto__);//[Object: null prototype] {}
console.log(obj1.__proto__.__proto__.__proto__);//null
class ObjFn1{}
let obj2=new ObjFn1()
console.log(obj2.__proto__);// {}是ObjFn1的原型
console.log(obj2.__proto__.__proto__);//[Object: null prototype] {}
console.log(obj2.__proto__.__proto__.__proto__);//null

 对于代码里构造函数new出来的原型链结构图如下:

 

7)原型链

原型链就是由对象的原型组成的链 如图红色部分就属于原型链,当我们去一个对象获取值的时候,,查找到就返回,如果该对象的原型对象上没有该值,就会去上一层查找该值,直到顶级Object的原型null为止,如果还是没查找到就返回undefined

 8)继承

不用class实现继承常见的方式有:原型链继承  借用构造函数继承  父类原型赋值继承  原型式继承  寄生式继承  寄生组合式继承 具体不展开了。

5.class类

类是es6新推出的标准

1)声明

// 首字母大写 默认规范
class Person{}
let Student=class{}

2)constructor extends super 

  // 首字母大写 默认规范
class Person{
  // 属性的定义
  a
  b='b'
  // 函数的定义 由于es6字面量增强 所以可以这样写
  foo(){console.log('foo');}
  // 当new或super的时候会调用
  constructor(a){
    console.log('constructor被调用了');
    this.a=a
  }
}
// extends代表继承
class Student extends Person {
  constructor(){
    // 调用Person的constructor
    super('a')
  }
}
let obj=new Student()
console.log(obj);//Student { a: 'a', b: 'b' } 会包含父亲里面有的属性和自身的属性,因为继承了父亲

3)get和set  静态属性  属性命名和函数命名(命名见上2)


// obj.b 取值优先级不是get 而是属性值
class Person{
  a=1
  b=2
  static c=1
  get a(){
    return this.a
  }
  set a(value){
    this.a=value
  }
  get b(){
    return this.a
  }
  set b(value){
    this.b=value
  }
}
let obj=new Person()
console.log(obj.b);// 如果有b=2 则obj.b会取这个2的值 如果没有则会执行get b(){}
console.log(obj);//Person { a: 1, b: 2 } 没有c的属性
console.log(Person.c);//1 static静态属性是可以通过类访问的,但是不能通过new出来的对象访问

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值