构造函数 new class prototype
个人笔记,欢迎友好交流讨论。如有错误,还望指正!
构造函数
构造函数也是一个函数,类似于
function Person(name) {
// 代码
}
有函数名(Person),也有参数(name)
构造函数与其他普通函数的区别在于:
-
构造函数习惯上
首字母大写
-
构造函数使用
new
关键词调用 -
构造函数内部用
this
来创建实例化对象的属性和方法 -
构造函数本身没有
return
返回值,使用new
操作符会自动创建一个新对象,并将新对象作为返回值返回;普通函数没有return
,会返回undefined
-
构造函数的执行流程
- 立刻在堆内存中创建一个新的对象
- 将新建对象设置为函数中的
this
- 执行函数中的代码
- 将新建的对象作为返回值
// 给出一个构造函数的例子
function Person(name) {
this.name = name;
this.info = function() {
console.log(this.name)
}
}
var p = new Person("Jack")
console.log(p.name) // "Jack"
p.info() // "Jack"
new
使用 new 操作符 调用一个构造函数,发生了什么?
var obj = {}
obj.__proto__ = Person.prototype
Person.call(obj, name) // 也可以使用 apply(), 主要根据参数情况选择,后文中选择 apply()
return obj
逐行解读:
- 创建一个空对象
obj
- 让空对象的
__proto__
成员指向构造函数对象的prototype
- 调用
Person
函数,并让Person
函数中的this
指向为新创建的空对象 - 返回新对象
obj
实现一个简单的 new 方法
// 定义构造函数
function Person(name, age) {
this.name = name
this.age = age
}
// 给构造函数添加 原型对象(该构造函数创建的实例化对象
// 都可以 使用 Person.prototype 中的方法和属性)
Person.prototype.info = function () {
console.log(this.name, this.age)
}
// 自己定义 new 方法
function myNew(Func, ...params) {
let obj = {}
obj.__proto__ = Func.prototype
Func.call(obj, params)
return obj
}
var p = myNew(Person, 'hyy', 22)
// 检验与 new 创建的效果是否相同
p instanceof Person // true
// Person {name: "hyy", age: 22}
// age: 22
// name: "hyy"
// __proto__:
// info: ƒ ()
// constructor: ƒ Person(name, age)
// __proto__: Object
class
接触过其他语言的同学应该会对 class
更加熟悉,我在最开始接触到 JS 中的面向对象时,没想到是用构造函数和原型链这些。
承接上文中的 Person
构造函数,将其用 class
改写,如下:
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
info() {
console.log(this.name, this.age)
}
}
var p = new Person('hyy', 22)
p instanceof Person // true
接下来,对 class
的基本语法做简单解释:
-
constructor
方法是 ES6 中类的默认方法,通过new
命令生成对象实例时,会自动调用该方法,一个类必须有constructor
方法,如果没有定义,一个空的constructor
方法会被默认添加。 -
直接在类创建时,定义的方法,全部都定义在类的
prototype
上。如上面例子中的info()
函数是定义在Person
类的prototype
原型对象上,通过new
操作符生成的实例化对象可以调用info()
函数。 -
给类添加静态方法或静态属性,在方法前加关键词
static
,表示该方法是类的静态方法,实例无法访问。例子:class Person { constructor(name, age) { this.name = name this.age = age } info() { console.log(this.name, this.age) } static func() { console.log('这是一个静态方法') } static msg = '这是一个静态属性' } var p = new Person('hyy', 22) p.func // undefined Person.func() // "这是一个静态方法"
补充,更多关于 class 语法内容,请移步参考资料
prototype
关于 prototype
,__proto__
, constructor
一些知识点总结:
-
我们需要牢记两点:
①
__proto__
和constructor
属性是 对象 所独有的;②
prototype
属性是函数所独有的,因为函数也是一种对象,所以函数也拥有__proto__
和constructor
属性;③ 单从
constructor
属性来讲,只有prototype
对象才有,但是其他被构造函数创建出来的对象可以通过原型链找到 这个属性。 -
__proto__
属性的 作用 就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__
属性所指向的那个对象(父对象)里找,一直找,直到__proto__
属性的终点 null ,再往上找就相当于在null上取值,会报错。通过__proto__
属性将对象连接起来的这条链路即 我们所谓的原型链 。 -
prototype
属性的 作用 就是让该函数所实例化的对象们都可以找到公用的属性和方法,即p.__proto__ === Person.prototype
。 -
constructor
属性的含义就是 指向该对象的构造函数 ,所有函数(此时看成对象了)最终的构造函数都指向 Function。