「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!」
对象
- 对象是单个实物的抽象
- 对象是一个容器,封装了属性和方法
- 对象可以复用,通过继承机制还可以定制
面向对象(OOP)
面向对象做了什么?
- 将真实的世界中的各种复杂关系,抽象为一个个对象
- 由对象之间的分工与合作,完成对真实世界的抽象
面向对象解决了什么问题?
- 具有灵活、代码可复用、高度模块化等特点,容易维护和开发
- 比起由一系列函数或指令组成的传统的过程式编程,更适合多人合作的大型软件项目
构造函数
什么是类?
- 典型的面向对象的语言(eg.c++和Java)中,都有类这个概念
- 类就是对象的模版,对象就是类的实例
- 类可以创建任意多个具有相同属性和方法的对象
JS怎么实现"类"?
- 通过构造函数和原型链
什么是构造函数?
- 专门用来生成实例对象的函数
- 是对象的模版,描述实例对象的基本结构
- 一个构造函数,可以生成多个实例,而且这些实例对象都有相同的结构
构造函数有何特点?
var Vehicle = function (p) {
this.price = p;
};
var v = new Vehicle(500);
- 函数体内部使用了this关键字,代表了所要生成的对象实例。
- 生成对象的时候,必须使用
new命令。
new命令做了什么?
- 创建一个空对象,作为将要返回的对象实例
构造函数内部,this指的是一个新生成的空对象,所有针对this的操作,都会发生在这个空对象上。
- 将这个空对象的原型,指向构造函数的prototype属性
- 将这个空对象赋值给函数内部的this关键字
- 开始执行构造函数内部的代码
如果构造函数内部有return语句,而且return后面跟着一个对象,new命令会返回return语句指定的对象;否则,就会不管return语句,返回this对象。
// new的实现原理
function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) {
// 将 arguments 对象转为数组
var args = [].slice.call(arguments);
// 取出构造函数
var constructor = args.shift();
// 创建一个空对象,继承构造函数的 prototype 属性
var context = Object.create(constructor.prototype);
// 执行构造函数
var result = constructor.apply(context, args);
// 如果返回结果是对象,就直接返回,否则返回 context 对象
return (typeof result === 'object' && result != null) ? result : context;
}
// 实例
var actor = _new(Person, '张三', 28);
如果忘了使用new命令,直接调用构造函数会发生什么事?
- this会指向全局
new.target的作用是什么?
- 函数内部可以使用new.target属性
- 如果当前函数是new命令调用,new.target指向当前函数,否则为undefined
- 可以用来判断函数调用时是否使用了new命令
function f() {
if (!new.target) {
throw new Error('请使用 new 命令调用!');
}
// ...
}
f() // Uncaught Error: 请使用 new 命令调用!
构造函数的缺点是什么?
- 同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费
- 解决方法==>原型对象
原型对象&原型链
什么是原型对象?
- 每个函数都有一个prototype属性,指向一个对象
对于普通函数来说,该属性基本无用。但是,对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型
- 原型对象的属性不是实例对象自身的属性。只要修改原型对象,变动就立刻会体现在所有实例对象上
原型对象的作用,就是定义所有实例对象共享的属性和方法
什么是原型链
所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……
- 读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined
- 原型链的尽头就是null
constructor 属性到底是个啥?
- prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数,可以被所有实例对象继承
function P() {}
P.prototype.constructor === P // true
- constructor属性的作用是,可以得知某个实例对象,到底是哪一个构造函数产生的
- 有了constructor属性,就可以从一个实例对象新建另一个实例(间接调用
function Constr() {}
var x = new Constr();
var y = new x.constructor();
y instanceof Constr // true
//在实例方法中,调用自身的构造函数成为可能
Constr.prototype.createCopy = function () {
return new this.constructor();
};
instanceof 运算符有何作用?
- instanceof运算符返回一个布尔值,表示对象是否为某个构造函数的实例
构造函数如何实现继承?
- 第一步是在子类的构造函数中,调用父类的构造函数
function Sub(value) {
//Sub是子类的构造函数,this是子类的实例
//在实例上调用父类的构造函数Super,就会让子类实例具有父类实例的属性
Super.call(this);
this.prop = value;
}
- 是让子类的原型指向父类的原型,这样子类就可以继承父类原型
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.prototype.method = '...';
未完待续