深入对象

219 阅读6分钟

一、构造函数

  • 在 JavaScript 中,构造函数是一种用于创建对象的特殊函数。它们通常与 new 操作符一起使用。当使用 new 操作符调用一个函数时,该函数被称为构造函数,并且会创建一个新的对象实例。
  • 构造函数可以包含属性和方法,这些属性和方法将成为由该函数创建的所有对象实例的共享属性和方法。构造函数通常使用大写字母开头,以便与普通函数区分开来。

示例:

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

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
};

const john = new Person("John", 30);
john.greet(); // 输出:Hello, my name is John and I'm 30 years old.

  • 在上面的例子中,Person 函数是一个构造函数,它接受两个参数 nameage,并将它们存储为新对象实例的属性。greet 方法是通过 Person 的原型添加到所有 Person 实例中的共享方法。最后,通过 new 关键字调用 Person 函数来创建一个新的 Person 对象实例,并向其传递 "John"30 作为参数。然后,使用 john 对象实例调用 greet 方法来输出问候语。

拓展:

  • 构造函数体现了面向对象封装特性
  • 构造函数实例创建的对象彼此独立、互不影响
  • 封装是面向对象思想中比较重要的一部分,js面向对象可以通过构造函数实现的封装
  • 把公共的属性和方法抽取封装到构造函数里面来实现数据的共享,这样创建的实例对象可以使用这些属性和方法了

构造函数存在的问题

  • 构造函数方法很好用,但是存在浪费内存的问题
  • image.png
  • 构造函数中函数会多次创建,占用内存。
  • image.png
function Person(name, age){
    this.name = name 
    this.age = age 
    this.sing = function(){
        console.log('hi~~')
    }
}
const zjl = new Person('zjl', 18)
const kk = new Person('kk', 20)

// zjl.sing()
// kk.sing()
console.dir(zjl)
console.dir(kk)
// 判断两个方法是否相等
console.log(zjl.sing === kk.sing)  // false 表示地址sing方法的地址不同
  • 每创建一个对象,就会在堆内存中开辟一个空间存储方法,当我们创建特别多对象时,就会占用很多内存空间
  • PS.我们常说的指针/指向:表示的就是内存中的地址(门牌号/房间号),我们可以通过这个地址访问到内存中实际的数据

解决方法:

  • 引入原型解决这个问题
  • image.png
function Person(name, age){
    // 1. 公共的属性都放在构造函数里面
    this.name = name 
    this.age = age 
    // this.sing = function(){
    //     console.log('hi~~')
    // }
}
// 2. 公共的方法,写到原型对象上,节约了内存
Person.prototype.sing = function(){
    console.log('hi~~~')
}
const zjl = new Person('zjl', 18)
const kk = new Person('kk', 20)
// 都可以使用 sing方法 在prototype能找到
console.dir(zjl)
console.dir(kk) 
zjl.sing()
kk.sing()
// 相等
console.log(zjl.sing === kk.sing) // true
  1. 公共的属性写到构造函数里面
  2. 公共的方法写到原型对象上!!!

二、实例成员& 静态成员

实例成员

  • 通过构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员(实例属性和实例方法)。

静态成员

  • 构造函数的属性和方法被称为静态成员静态属性和静态方法
  • 注:
  • 静态成员只能构造函数来访问
  • 静态方法中的this指向构造函数

总结:

  • 实例成员:是指只有在类的实例化对象被创建后,才能通过该对象访问和调用的成员,如实例方法或实例变量。
  • 静态成员:是指在类被加载时就已经存在并可以直接通过类名访问和调用的成员,如静态方法或静态变量。
  • 区别: 区别在于实例成员属于对象级别,每个实例都有独立的一份,而静态成员属于类级别,所有对象共享同一份

三、一切皆对象

  • 在 JavaScript 中,几乎所有的内容都被视为对象。这是因为 JavaScript 是一种面向对象的语言,它采用基于原型的对象模型。在 JavaScript 中,包括函数、数组、日期、正则表达式等各种数据类型都可以看作是对象。
  • JavaScript 中的每个对象都有其自身的属性和方法。甚至连基本数据类型(如字符串、数字、布尔值)也都有对应的内置对象,并且可以使用这些对象的方法和属性来操作这些基本类型的值。因此,可以说在 JavaScript 中,一切都是对象,或者至少可以被视为对象。

包装类型

  • 在 JavaScript 中,有三种基本数据类型:字符串数字布尔值。虽然它们不是对象,但是可以使用包装类型将其转换为对象,以便访问其属性和方法
  • 例如,字符串可以通过 String() 构造函数来进行包装:
var str = "hello";
var strObj = new String(str);
  • 这样就创建了一个字符串对象 strObj,它具有与字符串相应的属性和方法,如:
console.log(str.length); // 5
console.log(strObj.length); // 5

console.log(typeof str); // "string"
console.log(typeof strObj); // "object"
  • 同样地,数字和布尔值也都有对应的 Number() 和 Boolean() 构造函数。

注意:

  • 需要注意的是,在使用包装类型时,每次访问属性或方法时都会创建一个新的对象。因此,在处理大量数据时,使用包装类型可能会导致性能问题。

四、new

  • 在JavaScript中,new是用来创建一个新对象实例的操作符。它后面跟随一个构造函数调用,例如new Object()或者new Array()。当使用new操作符和构造函数一起调用时,JavaScript引擎会执行以下操作:
  1. 创建一个新对象
  2. 将该新对象的原型设置为构造函数的原型对象
  3. 将构造函数的this关键字绑定到新对象上,使构造函数内部的代码能够访问该新对象
  4. 执行构造函数内部的代码,并将其属性和方法添加到新对象上
  5. 如果构造函数返回一个对象,则该对象将成为new表达式的结果;否则,新对象将成为new表达式的结果。
  • 因此,通过new操作符可以方便地使用构造函数创建新的对象实例,并且可以对新对象进行初始化和配置。

五、内置构造函数

  • JavaScript中的内置构造函数是JavaScript语言提供的一组预定义构造函数,可以使用这些构造函数创建特定类型的对象。这些内置构造函数包括Object、Array、String、Number、Boolean、Date、RegExp等。
  • 通过这些内置构造函数,可以创建对应类型的对象,并使用它们提供的方法和属性来操作数据。例如,使用Array构造函数可以创建一个数组对象,然后使用该数组对象的push()方法添加元素,或者使用length属性获取元素数量等。这些内置构造函数在 JavaScript 中非常常见,也是开发 JavaScript 应用程序时必须了解和使用的重要部分。