js原型和原型链
js中复杂类型都是对象类型(Object),而js中没有类(class)这个概念,那么其中的继承是如何实现的呢?
答案是构造函数
ES6中的class可以看作只是一个语法糖,它的绝大部分的功能,ES5都可以做到,新的class写法只是让原型的写法更加的清晰、更像面向对象编程的语法而已。
1. 前置知识
我们需要理解以下知识:
* 函数也是一种对象
* 普通函数和构造函数的区别
* 搞清楚 __proto__、prototype、constructor
需要记住以下两点:
- __proto__、constructor属性是对象独有的
- prototype属性是函数独有的
前面说过函数也是对象的一种,所以,函数同样有__proto__、constructor,即:
函数有:__proto__、constructor、prototype
对象有:__proto__、constructor
2. 构造函数
构造函数和普通函数在JavaScript中有几个主要区别:
创建对象:构造函数用于创建对象的实例,而普通函数用于执行特定的功能并返回一个值。
使用
new
关键字:在调用构造函数时,需要使用new
关键字创建对象实例。这将触发以下操作:- 创建一个新的空对象
- 将构造函数的作用域绑定到新对象(使
this
引用该对象) - 将新对象的原型指向构造函数的原型
- 返回新的对象实例
对象属性和方法:构造函数经常用于在实例化过程中,给对象设置初始状态(例如属性和方法)。这些属性和方法在每个由构造函数创建的对象实例中都是独立的。普通函数一般不涉及对象的创建和状态管理,它可以执行一系列操作,但不会直接影响对象的属性和方法。
命名约定:通常,构造函数的命名习惯是首字母大写,以突出其作为构造函数的特殊功能和用途。
下面是一个示例,展示了构造函数与普通函数的区别:
1 | // 构造函数 |
在上述示例中,Person
是一个构造函数,用于创建Person
对象的实例。它具有属性name
和age
,以及方法greet
。通过使用new
关键字调用构造函数,并传递适当的参数,我们可以创建一个person
对象。
另一方面,add
是一个普通函数,用于执行简单的加法操作。它接受两个参数并返回它们的和。这里没有涉及创建对象实例或设置对象状态,只是执行了一个计算操作并返回结果。
总结起来,构造函数用于创建对象的实例,而普通函数用于执行特定的功能。构造函数可以用于为对象设置属性和方法,而普通函数则更专注于执行某些操作并返回结果。
小结: 构造函数通过new实例化,而普通函数没有这一过程,只是简单执行一段代码。
3. prototype
在此之前,我们先看一段Python代码:
1 | class Person(): |
上面代码中a、b学校相同
那在js中不同实例如何共享属性和方法呢,没错就是prototype!
1 | var Parent = function () { |
4. __proto__ 和原型链
1 | console.log(p1.__proto__ === Parent.prototype) // true |
__proto__ 指向该对象的原型对象,现已不推荐使用
推荐使用:Object.getPrototypeOf(person)
每个通过构造函数创建出来的实例对象,其本身有个属性__proto__,这个属性会指向该实例对象的构造函数的原型对象。
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会通过它的__proto__隐式属性,找到它的构造函数的原型对象,如果还没有找到就会再在其构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链
4. constructor
一句话:指向对象的构造函数
1 | console.log(p1.constructor) // [Function: Parent] |
参考
[1] https://juejin.cn/post/6984678359275929637#heading-2
[2] https://juejin.cn/post/7095651623812202533
[3] https://juejin.cn/post/7021416739887906830#comment