深入理解 JavaScript 中的原型与对象

深入理解 JavaScript 中的原型与对象

在 JavaScript 中,原型是一项强大的概念,贯穿于对象创建、继承、和属性访问的方方面面。本文将深入讨论原型及相关概念,从显式原型、隐式原型到原型链,为你揭示 JavaScript 中这个核心特性的奥秘。

javascript 复制代码
function Person() {
    this.name = '小明'
    this.age = 18
}
Person.eat = function() {
    console.log('想吃面条')
}

let p = new Person()
let p2 = new Person()
console.log(p === p2)//false

以上代码中,构造函数 Preson,当我们new了两个Person,得到两个对象。在之前的学习中,我们知道了函数是引用类型,存在于堆中,当我们拿到它,其实是拿到了它在堆中的地址。按理说第11行语句的结果是true才对,说明,每new一次得到的对象都是新的对象。

第5行代码我们可以看到,我们往Person挂了一个eat属性(函数也是对象),执行Person.eat()是可以调用的,但当我们去查看new出来的Person对象时发现它并不在里面,也就是说,p.eat()是会报错的。(我的浏览器没有识别出 '小明' -.-')我们如何去解决这个问题呢?往下看

1. 显式原型

1.1 定义

在 JavaScript 中,每个函数都有一个特殊的属性,称为 prototype。这个属性定义了由该函数创建的对象的公共祖先。通过该构造函数创建的对象,可以隐式地继承这个原型上的属性和方法。

1.2 意义

显式原型允许我们将共享的属性和方法定义在一个地方,从而简化代码。所有由同一构造函数创建的对象,都共享一个原型,节省内存并使代码更加可维护。

1.3 原型上的属性修改

需要注意的是,原型上的属性修改只能由原型自己操作,实例对象无权修改。这一点对于理解 JavaScript 的继承机制至关重要。

2. 隐式原型

2.1 定义

对象原型,通常称为隐式原型,是实例对象的 __proto__ 属性,指向构造函数的显式原型。

2.2 关系

实例对象的隐式原型与构造函数的显式原型相互关联。通过这种关系,实例对象可以访问构造函数原型上的属性和方法。

ini 复制代码
<script>
    //Car.prototype.name = 'BMW'
    //Car.prototype.lang = 4900
    //Car.prototype.height = 1400
    Car.prototype = {
        name: 'BMW',
        lang: 4900,
        height: 1400
    }

    function Car(owner, color) {
        // this.name = 'BMW'
        // this.lang = 4900
        // this.height = 1400
        this.owner = owner
        this.color = color
    }

    let car = new Car('小帅', 'red')
    let car2 = new Car('小美', 'pink')

    console.log(car);
</script>

以上代码我们可以看到,Car.prototype这就是往这个构造函数的显示原型里添加属性。所以当我们new 一个Car时,它会隐式继承该原型的属性和方法。所以当我们要修改原型属性,也要通过该种方法

也就是说car.__proto__===Car.prototype

3. new 操作符

3.1 创建过程

使用 new 操作符创建对象的过程包含以下步骤:

  1. 创建一个空对象。
  2. 执行构造函数中的逻辑,将 this 绑定到新创建的对象上。
  3. 将新对象的隐式原型指向构造函数的显式原型。
  4. 返回新创建的对象。

new 操作符的机制保证了新对象与构造函数原型之间的正确关联。

4. 原型链

4.1 定义

原型链是由对象的隐式原型一级一级连接起来的链条。在属性访问时,JavaScript 引擎会沿着原型链向上查找,直到找到目标属性或者到达原型链的末端(null)。

4.2 每个对象都有一个隐式原型:

在 JavaScript 中,每个对象都有一个 __proto__ 属性,它指向该对象的原型。这个原型对象也是一个对象,并且它也有自己的 __proto__,形成了一条由对象连接而成的链,即原型链。

4.3. 原型链的顺序查找:

当你访问一个对象的属性时,如果对象本身没有这个属性,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或者到达原型链的末端(null)。

4.4. 原型链的形成:

原型链是通过对象的隐式原型一级一级连接起来的。一个对象的隐式原型指向构造函数的显式原型,而构造函数的显式原型也是一个对象,它的隐式原型又指向另一个构造函数的显式原型,依此类推,形成了原型链。

4.5. 构造函数和原型链:

每个构造函数都有一个显式原型对象,通过 prototype 属性访问。新创建的对象通过 new 操作符与构造函数关联,其隐式原型指向构造函数的显式原型。

下面是一个简单的例子来演示原型链:

javascript 复制代码
// 构造函数
function Animal(name) {
    this.name = name;
}

// 在构造函数的原型上添加方法
Animal.prototype.sayName = function() {
    console.log("My name is " + this.name);
};

// 创建实例对象
const myAnimal = new Animal("Leo");

// 访问实例对象的方法
myAnimal.sayName(); // 输出: My name is Leo

// 实例对象的隐式原型指向构造函数的显式原型
console.log(myAnimal.__proto__ === Animal.prototype); // 输出: true

// 构造函数的显式原型的隐式原型指向 Object 构造函数的显式原型
console.log(Animal.prototype.__proto__ === Object.prototype); // 输出: true

// Object 构造函数的显式原型的隐式原型是 null
console.log(Object.prototype.__proto__ === null); // 输出: true

在这个例子中,myAnimal 实例对象通过原型链可以访问到 sayName 方法,而原型链的末端是 null,表示查找到此处为止。

5. 网易面试题解析

5.1 所有对象都有隐式原型吗?

在 JavaScript 中,几乎所有的对象都有隐式原型,但有一种特殊情况例外。通过 Object.create(null) 创建的对象是没有隐式原型的。

javascript 复制代码
const obj = Object.create(null);

console.log(obj.__proto__); // 输出: undefined

在这个例子中,通过 Object.create(null) 创建的对象 obj 不继承任何属性和方法,它的隐式原型是 undefined,而不是指向标准的对象原型(Object.prototype)。

这种情况通常用于创建一个纯净的、不继承任何属性和方法的对象,可以完全按照你的需求定义其属性和方法。然而,这也意味着这个对象失去了一些 JavaScript 常规对象的特性,比如无法使用一些内置的方法和属性。因此,使用 Object.create(null) 需要慎重考虑,确保你真的需要一个没有原型链的对象。

结语

深刻理解原型、隐式原型、new 操作符和原型链是成为 JavaScript 高效开发者的关键。这些概念贯穿了 JavaScript 的对象模型,对于正确理解和利用这门语言至关重要。希望通过本文的讲解,读者能够更清晰地理解 JavaScript 中原型的精髓。

相关推荐
工业甲酰苯胺3 小时前
TypeScript枚举类型应用:前后端状态码映射的最简方案
javascript·typescript·状态模式
brzhang3 小时前
我操,终于有人把 AI 大佬们 PUA 程序员的套路给讲明白了!
前端·后端·架构
止观止4 小时前
React虚拟DOM的进化之路
前端·react.js·前端框架·reactjs·react
goms4 小时前
前端项目集成lint-staged
前端·vue·lint-staged
谢尔登4 小时前
【React Natve】NetworkError 和 TouchableOpacity 组件
前端·react.js·前端框架
Lin Hsüeh-ch'in4 小时前
如何彻底禁用 Chrome 自动更新
前端·chrome
augenstern4166 小时前
HTML面试题
前端·html
张可6 小时前
一个KMP/CMP项目的组织结构和集成方式
android·前端·kotlin
G等你下课6 小时前
React 路由懒加载入门:提升首屏性能的第一步
前端·react.js·前端框架
谢尔登7 小时前
【React Native】ScrollView 和 FlatList 组件
javascript·react native·react.js