Skip to content

对象

Object 对象

广义理解的对象:

js
一切皆对象,数组、函数都是对象的一种。

狭义理解的对象:

js
Object 数据类型,是对象类型中的一种,与Array、Function 是平级的。

什么是 Object 对象

js
1. Object 类型的数据是值的无序集合。
2. Object 类型的数据由属性组成,属性由属性名和属性值
3. 属性值可以是任何类型的数据; 属性名用字符串表示,如果符合标识号规范,可以省略引号。
4. 如果属性的值是一个函数,该属性可以被称为方

如何创建 Object 对象

① 直接量方式

js
var user = {
    username:'高小乐', 
    age:67,
    'home-address': '上海',
    schollAddress: '北京',
    firends: ['刘姥姥', '欧阳姥姥', '司马姥姥'],
    child: {
        name: '高小小乐', 
        age: 37
    },
    getInfo: function() {
        console.log('obj2 getInfo');
    },
    eat: function() {
        console.log('高小乐爱吃!');
    }
};

② 使用 Object 函数

js
var obj3 = Object();

③ 使用 Object 构造函数

js
new Object();

Object 对象属性的读写

① 语法

js
对象.属性名;
对象['属性名']; 中括号中的属性名必须加''
js
1. 读取不存在的属性,自动得到 undefined
2. 给不存在的属性赋值,自动添加该属性
.` 运算符, 如`obj.name

2)[] 运算符,如 obj['name']。 属性名要以字符串形式给出,也可以以变量的形式给出。

注意:

设置属性值的时候,属性已经存在,就修改属性值;如果属性不存在,就添加属性。 获取对象中不存在的属性的时候,返回 undefined

**注意:**在以下情况下我们必须使用[]语法操作:

① 如果对象的属性名不符合标识命名规范(变量名的命名规范)。

② 如果需要使用变量的值作为属性名。

② 什么情况下必须使用 [] 语法读写属性

js
1. 属性名不符合标识符规范
2. 使用变量表示属性名,真正的属性名是变量的值
var prop = 'Friend';
user[prop]; prop被当作变量

遍历对象的属性

使用 for ... in 循环可以遍历对象中的属性。

js
for (var i in 对象) {
    i;  	  // 属性名
    对象[i];   // 属性值
}

删除对象中的属性

使用 delete 运算符

js
delete 对象.属性名;
delete 对象['属性名'];

delete obj.name;
ddlete obj['name'];

delete Arrar[0]; 
delete可以删除对象中的属性,
也可以删除数组元素,删除数组元素时,只删除数组中的元素,并且用空数据填充索引,后续元素索引不会变化。
forEach遍历时会自动跳过索引数据为空的元素。

判断对象中是否存在某个属性

判断对象中是否存在某个属性,使用 in 运算符,是个二元运算符,表达式的结果是布尔值。

js
'name' in obj;  //属性名以字符串的形式给出,表达式的结果是布尔值。
js
// 表达式的值是布尔值
'属性名' in 对象;

数组,函数,是在对象基础上有自己的特点,object对象是最纯净原始的对象。

构造函数

对象是一个实际的存在, 构造函数是对对象的描述。

2)对象是构造函数的实例,构造函数是对象的抽象。

3)JS 中的构造函数相当于其他编程语言的(ES6 中也引入了类的概念)。

4)每一对象都有与之对应的构造函数。

5)一个构造函数可以对应很多对象, 一个对象只有一个构造函数。

什么是构造函数?

js
1. 构造函数就是其他编程语言中的类(ES6引入了类的概念)
2. 构造函数对对象进行描述,描述对象的特点,每个对象都有构造函数,相同数据类型的对象构造函数是同一个,如所有数组的构造函数都是Array、所有函数的构造函数都是Function。
3.构造函数对应的就是数据类型,类似工厂中的模具。

构造函数对应的是数据类型!!!

构造函数和对象的关系

js
1. 构造函数是对象的描述,对象是构造函数的实例,实例表示的是对象。
2. 一个构造函数可以对应无数个对象
   一个对象只能对应一个构造函数

判断对象的构造函数(数据类型)

1)instanceof 运算符,语法:对象 intanceof 构造函数。 返回布尔值。

2).constructor 所有的对象都有该属性,返回对象的构造函数

① 运算符 instanceof

js
对象 instanceof 构造函数;    // 表达式的值是布尔值

② constructor 属性

js
对象.constructor;   	  // 直接获取到该对象的构造函数

对象的实例化

使用new 运算符可以把构造函数实例化成一个对象,不论构造函数是系统内置的还是我们自定义的。

每实例化一个对象,内存中就会开辟一块空间来存储该对象。

js
new 构造函数();
[];  // 相当于 new Array
{};  // 相当于 new Object
// 直接量创建数组  其实就是 new Array() 的简写
var arr3 = [];   // new Array()
var arr4 = [];   // new Array()
console.log(arr3 === arr4);

// 直接量方式创建对象 其实就是 new Object 的简写
var obj1 = {};
var obj2 = {};
console.log(obj1 === obj2);



//自定义构造函数
function Person() {
}

// 实例化自定义的构造函数
var p = new Person();

// 实例化内置的构造函数
var arr = new Array();
var obj = new Object();
var fn = new Function();
js
实例化指创建对象的过程
每实例化一次构造函数就会产生一个新的对象,每个对象都有独立的内存空间

自定义构造函数

定义一个构造函数与定义一个普通函数是一样的,我们通常会把构造函数的名字首字母大写,以示区别(这只是人为区分不是语法)。

js
// 自定义构造函数  User 与 Array、Function、Object 同为构造函数
//构造函数仍然是函数,构造函数是f函数的对象。
// this 表示User的实例 u1 u2
function User(username, age, address) {
    // 设置 User 实例的属性
    this.name = username;
    this.age = age;
    this.address = address;
    this.addShopcart = function(product) {
        console.log(this.name + '将' + product + '加入购物车!');
    };
    this.buy = function(product) {
        console.log(this.name + '购买了' + product);
    }
}

// 实例化构造函数 创建新的对象
var u1 = new User('高小乐', 78, '上海');
var u2 = new User('曹操', 79, '北京');

构造函数和函数是一个东西,拥有波粒二象性,既有函数的,又有类的。看从哪个角度去分析去使用,胡萝卜是蔬菜还是水果。炒菜和直接吃。

自定义构造函数的返回值对实例化结果的影响:

js
js作者设计的语法规则,规定
1. 如果构造函数中没有 return 或者 return 的是原始类型数据(number string null belean undefined),实例化的结果就是创建的新对象。
2. 如果构造函数中 return 的是对象类型数据(Array,Function,object),实例化的结果就是 return 的数据

实例化也相当于调用,也会执行函数中的语句。

构造函数和普通函数

任何的函数都可以是普通函数,也可以是构造函数,就看我们怎么去使用。

js
一个函数,如果取实例化它,它就是构造函数;如果去调用它,它就是函数
js
Array();  // 当函数用
new Array();  // 当构造函数用
js
function User() {
    console.log('hello User');
}

var res1 = new User();
var res2 = User();
console.log('');

console.log(res1);   // User的实例 新的对象 User{}
console.log(res2);   // undefeind
console.log('');
console.log('');


// 调用和实例化的结果一样
function product() {
    return function(){}
}

var p1 = product();
var p2 = new product();   // p2 是 product 的实例

console.log(p1);
console.log(p2);

原始类型数据的对象特性

js
原始类型数据 Number、String、Boolean, 既有值的状态也有对象的状态
js
// 创建数字 直接量方式   值的状态
var num01 = 89;
// 创建数字 Number 函数方式  值的状态
var num02 = Number(88);
// 创建数字 Number 构造函数  对象的状态
var num03 = new Number(87);

// 不论处于什么状态,需要什么形式转为什么形式,不需要就保持原有形态。
// num03自动转为值的状态
num01 * num03;                  
console.log(num03.constructor); //Number()
console.log(typeof num03);      //object

// num01 自动包装成对象
console.log(num01.constructor); //Number()
// 执行完上条语句,临时对象自动销毁,变为值的状态
console.log(typeof num01);      //number

原始类型数据的对象特征,默认是值的状态,当我们把它当作成对象的状态,他会临时自动创建一个属性,语句执行完,临时对象自动销毁。

js
var arr = [];
arr.address = '上海';
console.log(arr.address); //数组本省就是对象的状态。

var msg = '';
// 需要msg包装成对象, new String(msg) 临时创建对象,给临时创建的对象添加属性address,本语句执行完,临时对象自动销毁
msg.address = '北京';
// 使用 msg.address, 又临时创建新对象new String(msg),从该临时对象中读取属性address,用完即毁
console.log(msg.address); //undefined

this

this 的含义

  • this 是 JS 内置的一个变量,本质上是一个对象
  • 通常在函数或方法当中使用,代表这个函数的调用者。
js
1. this 是系统内置的只读变量(不能更改),相当于常量
2. this 的值在不同的地方是不一样的

this 的指向(取值)

js
1. 在函数外面使用(全局下使用)
   this 的值是 window

2. 在构造函数内部使用
   this 的值是构造函数的实例(实例化构造函数所创建的对象)
   
3. 在函数(方法)中使用
   this 的值是调用该函数(方法)的对象
   注意: 不要看函数声明语句所在的地方,看调用函数的语句,看.前面是哪个对象 ,外婆 妈 自己
   和作用域是相反的

注意:

在函数中使用 this,this 指向 window 对象。函数本质上其实是 window 对象的方法,所以在函数中使用 this 与第二种情况本质是一样的。

window 介绍

js
1. window 表示浏览器窗口, 运行在浏览器上的js,window 作为全局对象
2. 在打开浏览器的时候 window 对象就自动创建了
3. 所有的全局变量都是 window 的属性, 使用 window 的属性可以省略 window.


1)window 是浏览器端 JS 的全局对象。
2)打开浏览器,window 对象就会自动生成。
3)所有的全局属性(全局变量和函数)都是 window 对象的属性。
4)使用 window 的属性和方法的时候,通常可以省略window。
5)系统的函数 alert、prompt、Numbe、Boolean、Array、Object等 也是window的属性。

this练习

js
var a = 5;
function test(){
    a = 0; //这里是变量
    this.a = 0; //这里才是test实例化的属性
    console.log(a);
    console.log(this.a);
    var a;
    console.log(a);
}


/*
            调用 test(), this 是 window
            0   本作用域中的局部变量a
            5   this.a 就是 window.a 全局变量a
            0   本作用域中的局部变量a
        */
test();
console.log('');


/*
            实例化 test(), this 是创建的新对象
            0           本作用域中的局部变量a
            undefined   创建的新对象中没有属性a,自动得到undefined
            0
*/
new test();

工厂函数

工厂模式是一种设计模式,说白了就是一种简单的函数,这个函数可以创建对象,为它添加属性和方法,然后返回这个对象。就像一个工厂一样,可以批量制作某种类型的对象。这种设计模式是就是为了降低代码冗余

javascript
  function createPerson(name, age) {
        let o = new Object();
        o.name = name;
        o.age = age;
        o.sayName = function () {
            console.log(this.name);
        };
        return o;
    }
    let person1 = createPerson("jackson", 20);
    let person2 = createPerson("bear", 22);
    person1.sayName(); //jackson
    person2.sayName(); //bear

这里函数 createPerson()接收俩个参数,根据这几个参数构建了一个包含person信息的对象。这样写主要是为了解决需要创建大量有属性重叠的对象,如果每个都new一下,然后逐一添加属性。这也是个累人的活。通过上面的代码中,我们声明了一个createPerson方法,此方法可批量制造。但是还有缺点,它没有解决对象标识问题(就是创建的对象是什么类型)。

与构造函数的区别

构造函数模式可以自定义引用类型,可以使用new关键字创建内置类型实例应用创建自定义类型实例,我们常用的 new Vue(),其本质上就是传递 options参数,实例化一个Vue对象。

上面的工厂函数我们可以用构造函数来改进一下

javascript
 function Person(name, age) {
        this.name = name;
        this.age = age;
        this.sayName = function () {
            console.log(this.name);
        };
    }
    let person1 = new Person("jackson", 20);
    let person2 = new Person("bear", 22);
    person1.sayName(); // jackson
    person2.sayName(); // bear

在这个例子中,我们可以发现构造函数可以替代工厂函数,在实际开发中,我们用构造函数的频率一般会大于用工厂函数的频率。

注意:按照惯例,构造函数名称的首字母要大写

要创建Person的新实例,必须使用new操作符。以这种方式调用构造函数,实际上会有以下5个步骤。

(1) 在内存中创建一个新对象。

(2) 这个新对象内部的Prototype特性被赋值为构造函数的 prototype 属性。

(3) 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)。

(4) 执行构造函数内部的代码(给新对象添加属性)。

(5) 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。

构造函数虽然好用,但是也有一些问题,我们分析一下逻辑

上面的例子,person1和person2都有一个sayName()方法,但这俩个方法却不是同一个function实例,相当于这里定义的方法sayName()会在每个实例上都创建一遍,虽然我们自己省事了,但机器可不省事。

javascript
this.sayName = function () {console.log(this.name);};
//逻辑等价与下面的
this.sayName = new Function("console.log(this.name)");

优化一下

因为做的事情是一样的,所以没必要定义俩个不同的 Function 实例,我们可以把函数定义转移到构造函数外部。

javascript
 function Person(name, age) {
        this.name = name;
        this.age = age;
        this.sayName = sayName;
    }

    function sayName() {
        console.log(this.name);
    }
    let person1 = new Person("jackson", 20);
    let person2 = new Person("bear", 22);
    person1.sayName(); // jackson
    person2.sayName(); // bear