对象

对象

属性

var person={
    'name':'zhangsan',
    age:18,
    5:true
}

对象属性访问

点表示法

属性不能包含空格等 导致语法错误的字符,或者是关键字或保留字或数字

obj={
    name:'张三',
    age:21,
    5:23,
    'var t':3 //字符串才允许有空格
}
p='name'
console.log(obj.name);;//张三
console.log(obj.5);//报错
console.log(obj.var t);//报错
console.log(obj.'var t');//报错
console.log(obj.p);//und

方括号表示法

属性可以是变量,包含空格,关键字或保留字

obj={
    name:'张三',
    age:21,
    5:23,
    'var t':3 //字符串才允许有空格
}
p='name'
console.log(obj[5]);//23
console.log(obj['5']);//23
console.log(obj[var t]);//报错
console.log(obj['var t']);//3
console.log(obj[p])//'张三'

对象访问器

本质也是函数 只不过 使用函数名不需要() 就会调用函数

当访问器与属性重名时

访问器声明在下方则会覆盖属性

属性在下方则会覆盖访问器

get关键词

var ob={
    name:'123',
    age:2,
   	def:function(){
      return 1   
    },
    get getName(){
        return this.name
    }
}
console.log(ob.def()) //需要()调用函数
console.log(ob.getName);// 不需要 

var ob={
    name:'123',
    age:2,
    def:function(){
      return def() //这样会发生递归  
    },
    get name(){//与属性重名
        return this.name// 这样会发生递归 而不是返回属性name
    }
}
console.log(ob.def());//调用对象函数
console.log(ob.name);//调用访问器


访问器与属性同名时 声明在下方的优先级更高

var ob={
    name:'123',
    age:2,
    get name(){
        return 2
    }
}
console.log(ob.name) // 调用了访问器 输出2

set关键词

var ob={
    age:2,
    name:'123',
    get getName(){
        return this.name
    },
    set setName(value){
        this.name=value
    } ,
    def:function(val){
        this.name=val;
    }
}
ob.def('zhangsan');//函数使用方法
ob.setName='张三' //set使用方法	
console.log(ob.name);

属性defineProperty()

数据属性

image-20211013162124820

writable

var person={
    name:'zhangsan'
}
Object.defineProperty(person,'name',{
    writable:false,//name属性不可修改
    value:'lisi'
})
console.log(person.name);//lisi
person.name='wangwu';
console.log(person.name);//lisi 

configurable

var person={
    name:'zhangsan',
    age:13,
}
Object.defineProperty(person,'name',{
    configurable:false,//name属性不可配置
    value:'lisi'
})

console.log(person);
delete person.name;//无法删除name属性
delete person.age;//成功删除age属性
console.log(person);//{name:'lisi'}

Object.defineProperty(person,'name',{
    configurable:true,//报错 一旦被定义为不可配置那么就不能再变回可配置了
    value:'wangwu'
})


enumerable

var person={
    name:'zhangsan',
    age:13,
    phone:1329092285
}
Object.defineProperty(person,'name',{
    enumerable:false,//name属性不可在forin时遍历key找到
    value:'lisi'//直接给属性赋值
})

for (const key in person) {
    if (Object.hasOwnProperty.call(person, key)) {
        const element = person[key];
        console.log(key,':',element);
    }
}
//输出:
//age: 13
//phone:1329092285

访问器属性

Get 和 Set

var person={
    _name:'zhangsan',//_符号 表示属性只能通过 对象方法(或对象访问器)访问的属性
    _age:13,
}
Object.defineProperty(person,'name',{
    get:function(){
        return '姓名:'+this._name;
    },
    set:function(){
        this._age=0;
    }
})
console.log(person.name);//姓名:zhangsna
person.name='lisi'//触发了set 修改了_age的值 
console.log(person);//{ _name: 'zhangsan', _age: 0 }        

constructor属性

实例的一个属性,可以获取实例的构造函数引用。

function Person(name,age,job){
    this.nam=name;
    this.age=age;
    this.job=job;
    this.sayName=function(){
        console.log(this.name);
    }
}
var p1=new Person('zhangsan',18,'a');
console.log(p1.constructor);//[Function: Person]

constructor获得构造函数的引用甚至可以调用

var p2= new p1.constructor('lisi',18,'b');
console.log(p2);
//p2={
//  nam: 'lisi',
//  age: 18,
//  job: 'b',
//  sayName: [Function (anonymous)]
//}

构造函数

构造函数创建实例过程

  1. 创建一个新对象; (如果有new关键词)
  2. 将构造函数的作用域指向新对象;(this就指向了新对象)
  3. 执行构造函数中的代码;(正常按照函数ao顺序执行)
  4. 返回新的对象;

关于 new 关键词

new 关键字会进行如下的操作:

  1. 创建一个空的简单JavaScript对象(即{});
  2. 为步骤1新创建的对象添加属性proto,将该属性链接至构造函数的原型对象 ;
  3. 将步骤1新创建的对象作为this的上下文 ;
  4. 如果该函数没有返回对象,则返回this

构造函数的使用

function Person(name,age,job){
    this.nam=name;
    this.age=age;
    this.job=job;
    this.sayName=function(){
        console.log(this.name);
    }
}

var p1=new Person('zhangsan',18,'a');//函数作用域 new对象
console.log(p1);
Person('lisi',18,'c');//函数作用域 window/global
console.log(globalThis);
globalThis.sayName();//'lisi'
//更具环境给window或global 添加了name,age,job...属性

函数内的函数

函数是一个对象,因为使用了new关键词,每个对象内声明的函数属于不同的作用域,那么也就是不同的对象。
弊端:重复完全相同功能的函数

function Person(name,age,job){
    this.nam=name;
    this.age=age;
    this.job=job;
    this.sayName=function(){
        console.log(this.name);
    }
}
var p1=new Person();
var p2=new Person();
console.log(p1.sayName==p2.sayName);//false

解决方法:

在全局创造函数 sayName , 对象内属性去引用全局的 sayName函数。

function Person(name,age,job){
    this.nam=name;
    this.age=age;
    this.job=job;
    this.sayName=sayName;
}
function sayName() {
    console.log(this.name);
}
var p1=new Person();
var p2=new Person();
console.log(p1.sayName==p2.sayName);//true

弊端:全局作用域会有很多对象的函数,乱

原型模式

原型对象

在创建函数的同时会创建一个对象(原型对象),函数再创建一个prototype属性指向这个原型对象。

原型对象的属性:

  1. constructor (一个指针:指向函数。)
  2. 其他属性和方法 继承Object
image-20211018200441057

理解:

原型对象相当于静态代码块,每个实例都会拥有(继承)它的属性和方法。

访问实例的属性时 :

  1. 先搜索对象实例本身 是否拥有该属性,有的话直接返回属性值
  2. 对象实例没有该属性 再搜索__proto__指向的原型对象,如果有的话再返回值
function Person(name,age,job){
    this.name=name;
    this.age=age;
    this.job=job;
}
Person.prototype.say=function () {
    console.log('hello');
}
Person.prototype.sex='female'
Person.prototype.name='wangwu'
var p1=new Person('zhagnsan',18,'a');
p1.say(); //'hello' p1对象实例没有say() 然后去搜索它的 原型对象 找到方法say()
console.log(p1.sex);//'female' p1实例中没有sex属性,去搜索原型对象的sex属性 并返回值
console.log(p1.name);//'zhangsan' p1实例中有name属性 直接返回 不再去搜索原型对象

从原型对象继承来的函数方法 是同一个 (因为和原型对象绑定的构造函数只有一个,作用域也就只有一个)

function Person(name,age,job){
    this.name=name;
    this.age=age;
    this.job=job;
}
Person.prototype.say=function () {
    console.log('hello');
}
Person.prototype.sex='female'
Person.prototype.name='wangwu'
var p1=new Person('zhagnsan',18,'a');
var p2=new Person('lisi',18,'c');
console.log(p1.say==p2.say);//true

prototype和constructor

实例和函数 都有prototype属性 ,指向原型对象

function Person(name,age,job){
    this.name=name;
    this.age=age;
    this.job=job;
}
var p1=new Person();
Person.prototype.name='123'
console.log(Person.prototype);//原型对象{ name: '123' }
console.log(p1.__proto__);//原型对象{ name: '123' }

实例和原型对象 都有constructor属性,指向构造函数

function Person(name,age,job){
    this.name=name;
    this.age=age;
    this.job=job;
}
var p1=new Person();
Person.prototype.name='123'
console.log(Person.prototype.constructor);//[Function: Person]
console.log(p1.constructor);//[Function: Person]

用途:prototype和constructor属性能使 函数原型对象 彼此找到对方

屏蔽性

访问属性的过程是一个搜索的过程,从当前语句this开始向上搜索,一旦访问到属性就停止。

使用父类的方法时可以理解为单纯的借用代码,不用考虑父类方法所在的this域,实际环境仍然是调用对象所在域

实例1: 直接访问属性

function Person(name) {
    this.name=name
}
var p=new Person("张三")
Person.prototype.age=18;

访问属性时 属性重名 对象实例属性优先

p.age=20;
console.log(p.age);//20

就算对象实例属性值为null也优先

p.age=null;
console.log(p.age);//null

只能使用delete操作符才能完全删除实例属性,然后继承原型对象的属性

p.age=20;
delete p.age
console.log(p.age);//18

实例2:调用父类方法时,访问子父类重名属性

function SuperType() {
    this.property=456
}
SuperType.prototype.getSuperValue=function(){
    return this.property
}
function SubType() {
    this.property=123;
}
let superins = new SuperType();
SubType.prototype=superins;
let ins=new SubType();
console.log(ins.getSuperValue());//123
console.log(superins.getSuperValue());//456
//使用父类的父类getSuperValue()方法访问重名属性时
//从最底层开始搜索(调用函数的this域开始向上搜索)

hasOwnProperty

hasOwnProperty(v: PropertyKey): boolean; 判断属性是否在对象实例中

  • Determines whether an object exists in another object's prototype chain.
  • @param v Another object whose prototype chain is to be checked.
function  Person(name){
  this.name=name
}
Person.prototype.sex='0'
let p=new Person("zhangsan");
p.age=13;
//判断是否是实例的属性
console.log(p.hasOwnProperty('name'))//true
console.log(p.hasOwnProperty('age'))//true
console.log(p.hasOwnProperty('sex'))//false

获取对象属性

  1. for in
  2. Object.keys()
  3. Object,getOwnPropertyNames()

原型对象默认继承Object的原型对象

  • 原型对象的__proto__指向Object的prototype

    注意继承的是Object的原型对象不是Object的实例对象不是Object的构造函数

function p1() {
    this.age=3
}
console.log(p1.prototype.__proto__==Object.prototype);//true
console.log(p1.prototype.__proto__==Object);//false
console.log(p1.prototype.__proto__==new Object());//false
  • 多继承的原型链
function p1() {
}
function p2() {
}
p2.prototype.name='123'
p1.prototype=new p2()
a=new p1()
g=new p2()
console.log(p1.prototype.__proto__==Object.prototype);//false  左=p2的原型对象
console.log(p1.prototype.__proto__.__proto__==Object.prototype);//true 左=Object的原型对象
//p1.prototype  ----->  p1的原型对象是p2实例对象
//p1.prototype.__proto__   ------> p1的原型对象的原型对象----> p2的实例对象的原型对象 ----->p2的原型对象
//p1.prototype.__proto__.__proto__ -------> p2的原型对象的原型对象(默认值,未经修改)-----> Object的原型对象
  • 验证原型对象默认会继承Object的原型对象

原型对象的__proto__属性默认值为 Object.prototype

所以所有引用对象默认会继承Object原型对象的所有方法

function p1() {
}
let a=new p1()
console.log(a.__proto__.__proto__==Object.prototype)//true   
//原型对象的_proto_属性默认值为 Object.prototype

console.log(a.toString);//function
p1.prototype.__proto__=null//修改原型对象的__proto__默认值
console.log(a.toString);//null  不再继承Object j
posted @ 2021-11-15 21:14  CCCC_03  阅读(57)  评论(0)    收藏  举报