构造函数和原型
面向对象
面向过程
概念:根据流程,一步步实现特定的功能,亲力亲为。‘小兵思维’
面向过程是一种以过程为中心的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是封装、继承、类。简写为POP
好处:对于流程步骤非常清晰
缺点:不适合大型项目
面向对象
概念:从全局出发,将功能拆分到一个个的对象中,通过调用对象的方法实现。‘指挥家思维’
面向对象的方法主要是把事物给对象化,包括其属性和行为。面向对象编程更贴近实际生活的思想。总体来说面向对象的底层还是面向过程,面向过程抽象成类,然后封装,方便使用就是面向对象(万物皆对象)。
好处:适合大型项目
缺点:对于流程步骤不够清晰
构造函数
概念
JS中的函数即可以是构造函数又可以当作普通函数来调用,当使用new来创建对象时,对应的函数就是构造函数,通过对象来调用时就是普通函数。
构造函数就是你构造出来的函数,是一种特殊的方法,与普通函数有着质的区别。
构造函数例如工厂流水线,实例对象例如需要加工的产品
作用
批量创建具有相同属性和方法的实例对象
语法:
function 函数名(形参1,形参2,...) {
this.属性1 = 值1
this.属性2 = 值2
...
this.属性n = 值n
}
调用:
let p1 = new 函数名(实参1, 实参2)
注意:
- 构造函数的首字母需要大写
- 函数体内部需要用this赋值
- 需要通过new关键字来调用该构造函数
- 构造函数不需要return返回值
构造函数的this指向: 指向构造函数的实例对象
new关键字在实例化过程中所起的作用:
1. 创建一个空对象
2. 将this指向这个空对象
3. 指向函数体里面的代码
4. 将具有内容的新对象赋值给实例对象
JS 中构造函数和普通函数的区别
-
构造函数也是一个普通函数,创建方式和普通函数一样,但构造函数习惯上首字母大写
-
调用方式同
普通函数的调用方式:直接调用 person()
构造函数的调用方式:需要使用new关键字来调用 new Person()
-
构造函数的函数名与类名相同:Person( ) 这个构造函数,Person 既是函数名,也是这个对象的类名
-
构造函数,不需要返回值;普通函数,因为没有返回值,所以是undefined
类和实例对象的关系
类:具有相同特征(属性和方法)的物体的集合
对象: 特定某一个物体
类和对象的关系:基本上所有的对象都是由类实例化出来的
js的中的类(构造函数):Array, Object, RegExp, Date, String, Number, Boolean
方法过载
直接挂载到构造函数内部的方法,当实例化了多个对象的时候,就会在内存的堆中开辟不同的空间,存放具有相同功能的方法。
如果实例化很多对象,就会造成内存浪费,甚至内存泄漏
原型和原型链
【面试题】
原型
原型关系图
prototype:原型对象
作用
: 挂载到原型对象上的方法,可以被实例对象共享
语法
:
构造函数.prototype.方法名 = function(){}
特性
:
-
这里特指构造函数,都会有一个
prototype
,这就是原型对象,也叫显式原型。挂载到原型对象上的方法和属性可以被共享 -
每一个实例对象,都会有一个
__proto__
, 现代浏览器也写作[[prototype]]
, 这就是对象的原型,也叫隐式原型,它会指向构造函数的原型对象。实际开发中,不会用到隐式原型,它只起到指向的作用(只想原型对象)p1.__proto__ === Person.prototype // true
-
每一个原型对象,都会有一个
constructor
,这是构造器,它会指回构造函数本身Person.protoype.constructor===Person // true
function Person(uname, age) {
this.uname = uname
this.age = age
this.skill = function () {
console.log('蹲草丛');
}
}
// prototype: 原型对象
// 往Person这个构造函数的原型对象上挂载了一个location方法
Person.prototype.location = function () {
console.log('打野');
}
let p1 = new Person('小妲己', 18)
let p2 = new Person('小貂蝉', 19)
console.log(p1.location === p2.location)
//true
//结论:p1实例对象的location方法和p2实例对象的location方法是同一个方法
原型链
原型链关系图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p8e1jxH0-1678965096609)(F:\大前端\笔记\js\API\img\原型链关系图.png)]
概念
规定了属性和方法的查找规则:
原型链是原型对象创建过程的记录 ,当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构
当查找一个对象的属性时,JavaScript 会根据原型链向上遍历对象的原型,直到找到给定名称的属性为止,直到到达原型链的顶部仍然没有找到指定的属性,就会返回 undefined
特性:
-
构造函数的原型对象也是一个对象,它也会有一个
__proto__
,也就是隐式原型,它会指向Object的原型对象Person.prototype.__proto__ === Object.prototype // true
-
Object的原型对象也是一个对象,它也会有一个
__proto__
,也就是隐式原型,它会指向nullObject.prototype.__proto__ === null // true
-
Object的原型对象,也会有一个
constructor
,这是构造器,它会指回Object本身Object.prototype.constructor === Object // true
注意:Object是js中最大的那个对象,‘万物皆对象’
判断数据类型的方法
typeof
缺点:只能用来判断基本数据类型
typeof '123' 'string'
typeof 123 'number'
typeof null 'object'
typeof [1,2,3] 'object'
typeof {uname: '小妲己'} 'object'
typeof function() {} 'function'
constructor构造器
原理:实例对象本身是没有constructor属性的,但是可以根据原型链关系,实例对象可以使用构造函数的原型对象上的constructor构造器
缺点:不能判断undefined和null
[1,2,3].construtor // Array
{}.constructor // Obejct
'小妲己'.construtor // String
undefined.construtor //报错
unll.construtor//报错
instanceof
判断是否是构造函数的实例对象
缺点:不能判断基本数据类型
数组,函数,对象都是Object的实例对象,判断时,请把对象的判断放到最后
[1,2,3] instanceof Array // true
if (arr1 instanceof Array) {
console.log('数组');
} else if (arr1 instanceof Function) {
console.log('函数');
} else {
console.log('对象');
}
Object.prototype.toString.call()
最完美的判断方法,可以判断所有数据类型
Object.prototype.toString.call([1,2,3]) // '[object Array]'
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call('小妲己') // '[object String]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
// 函数封装
function getType(data) {
return Object.prototype.toString.call(data)
}