本文共 6261 字,大约阅读时间需要 20 分钟。
目录
1.什么是构造函数
定义:在js中,使用new
关键字来调用的函数,被称为构造函数。
构造函数:本质也是函数;
构造函数的作用:创建对象。
2.为什么要使用构造函数
假如需要创建多个类似的对象,我们会书写很多重复的无意义代码。此时我们使用构造函数,方便快捷的创建一个对象。
如何封装一个构造函数
构造函数内部: 添加的时私有的属性和方法
构造函数的原型对象上添加共有的属性和方法
function Ball(type, size) { //console.log(this);//Ball {} // 私有属性 this.type = type; this.size = size; // 添加私有方法 this.play1 = function() { console.log('私有方法'); } } // 原型对象上 :原型对象不需要创建,创建一个构造函数,该构造函数自然就拥有 prototype 属性, // 该属性指向一个对象的引用,称之为原型对象 Ball.prototype.play2 = function() { console.log('公有方法'); } Ball.prototype.color = '公有属性' // 通过new关键字创建出来的是实例化对象 var ball = new Ball('足球', 18); //调用输出 console.log(ball); ball.play1() //私有方法 ball.play2() //公有方法 console.log(typeof ball); //object console.log(typeof Ball); //function
构造函数: 拥有 prototype 属性 : prototype 属性指向一个对象的引用,称之为原型对象 prototype 实例化对象: 拥有 __proto__ 属性: __proto__ 属性指向该实例化对象的原型对象 原型对象: 原型对象创建之初自然拥有两个属性: construcrtor 属性和 __proto__ 属性 construcrtor 属性指向原型对象的父构造函数 :指向可以随时更改 __proto__ 属性指向原型对象
3.构造函数的执行过程
function Animal(color){ this.color = color;}
当一个函数创建完成后,我们并不知道它是不是一个构造函数。
像上面案例中,即使函数名首字母大写,我们也不确定它是构造函数。
只有当一个函数前用new
关键字来调用时,我们才能说它是一个构造函数。
var dog = new Animal("black")
构造函数的执行过程有以下4个步骤。
- 当用
new
关键字调用构造函数时,会开辟一个新的内存空间,这个内容空间就是新的对象实例。 - 将构造函数内部的
this
指向当前的内存空间(新的对象)。 - 执行函数内的代码。(对象的属性和方法的赋值。)
- 将内存空间的地址作为返回值返回。
本质用函数表示大致是这样(不要细扣)
function fun(a, b) { var obj = { }; function test() { this.a = a this.b = b; } test.call(obj) return obj; } let res = fun(100, 'hello') console.log(res);//{a: 100, b: "hello"}
4.构造函数的返回值
构造函数是没有返回值的,实际中用不到
存在返回值(面试题),但不是通过return 语句返回的, 构造函数默认返回的时创建的新对象(this)
- 构造函数的返回值时基本数据类型。返回值会被忽略
function Person(name){ this.name = name; return "蔡徐坤";}var p = new Person("范丞丞");console.log(p.name);//范丞丞
- 构造函数的返回值时引用数据类型。返回值会被忽略,this指向会丢失
function Person(name) { this.name = name; return { name: "蔡徐坤" }; //这样写就是错的 return ["name", "蔡徐坤" ]; } var p = new Person("范丞丞"); console.log(p.name);//蔡徐坤
5.与普通函数的区别
构造函数和普通函数的区别:
1. 构造函数的函数名大写 2. 构造函数可以继承 3. 构造函数没有返回值, 4. 构造函数必须通过new关键字调用 5. 构造函数内部通过this添加属性和方法5.1调用方式的不同
普通函数使用函数名
调用
构造函数通过new
关键字来调用
5.2 返回值不同
普通函数的返回值是函数内return的结果
构造函数的返回值是函数内创建对象的地址。
5.3 作用的不同
构造函数时专门用来创建对象。
普通函数的作用可以自由定义。
原型对象prototype
传统写法:
因为上述方法造成了资源的浪费我们学习一个新的概念prototype属性我们创建的每一个函数都有一个prototype属性,这个属性指向一个对象。而这个对象所有的属性和方法都会被构造函数拥有。
对象的封装
一般情况下,公共属性定义到构造函数里面,公共的方法定义到原型对象身上。
混合模式(构造函数+原型 模式)原型链
每一个对象都有一个属性__proto__
,这个属性指向构造函数的prototype
,也就是构造函数的原型对象。我们之所以可以在对象中使用原型对象中的方法和属性就是因为对象中有__proto__
属性的存在。
原型链概念:
每个实例化对象都具有一个原型链指针__proto__,该指针指向创建它的函数对象的原型对象,
而上一层的原型对象的结构依然类似,有自己的原型链指针,指向创建它的函数对象的原型对象。 这样利用__proto__一直指向Object的原型对象上, 而Object的原型对象用Object.proto = null表示原型链的最顶端。 这样由一系列__proto__串起来的原型对象就构成了原型链。
原型链(这副图从构造函数位置开始看)
面向对象的三大特性:
封装(封装构造函数),继承,多态
面向对象 是一种编程思想。
区别: 比如吃饭: 面向过程: 红烧肉 1.买菜 2.洗菜 3.切菜 4.炒菜 5.出锅 6.开吃 面向对象: 1.找一个对象 2.让她给你做饭吃
继承:从父类那里继承父类的属性和方法。
多态:子类自己重新定义从父类继承过来的方法。或者新增一个父类没有的方法。
继承
ES6之前没有给我们提供 extends 继承。我们可以通过构造函数+原型对象的模式去模拟实现继承。这种方法也被称为组合继承。
使用call()方法实现继承
特点:
- 该方式是靠调用需要继承的构造函数来实现的,调用过程中使用call方法来改变this的指向。
- call是不可以继承父对象原型中的属性和方法。
- call是只能继承构造函数中的属性和方法。
优点:继承了父类构造函数中所有的属性和方法
缺点:不能继承父类原型对象中的属性和方法
看下面这张图你会好理解使用prototype实现继承
在原型对象中有一个constructor属性,该属性指向该原型对象的构造函数。
优点:继承了父级原型上的属性和方法
缺点:实现化多个子类时,必须使用共同的属性值。
组合式继承
多态
多态:子类自己重新定义从父类继承过来的方法。或者新增一个父类没有的方法。
ES6面向对象
es5 类: 构造函数
es6 定义类: classclass 类
// function Dog(breed,color,age){ // this.breed = breed;// this.color = color;// this.age = age;// }// Dog.prototype.bark = function(){ // alert("汪汪汪")// }// var dog = new Dog("泰迪","棕色",5);// ------------- ES6写法 -------------------------class Dog { constructor(breed, color, age) { this.breed = breed; this.color = color; this.age = age; } bark(){ alert("汪汪汪") }}var dog = new Dog("泰迪","棕色",5); console.log(dog.age, dog.breed, dog.color);// 实例对象.属性 5 "泰迪" "棕色" dog.bark();//调用Dog方法 输出汪汪汪
- 在类的
实例
上调用方法实际上就是调用原型
上的方法
console.log(typeof Dog); //function console.log(Dog === Dog.prototype.constructor); //true 都指向Dog构造函数
通过以上的代码,我们发现,class的本质是函数,类本身指向的就是构造函数。
ES6的class
可以看作是构造函数的语法糖。它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型写法更加清晰,更加符合面向对象编程的语法而已。
类必须使用new调用,否则会报错.普通构造函数不用new也可以执行(虽然没有太大意义),但类不行
//什么是语法糖var arr = new Array();var arr2 = [];//就是上面new Array的语法糖。
- constructor方法
constructor方法是类的默认方法,定义私有的属性
,通过new命令生成实例对象时,自动调用该方法.
一个类必须有constructor方法,如果没有显式定义,会默认添加一个空constructor方法
constructor默认返回实例对象(this),完全可以指定返回另外一个对象
//改变返回的对象为空对象,因此通过new Foo()创建的实例不是继承自Foo class Foo { constructor() { return Object.create(null); } } new Foo() instanceof Foo // false
ES6继承
class Dog { constructor(breed, color, age) { this.breed = breed; this.color = color; this.age = age; } bark(){ alert("汪汪汪") }}class Haskie extends Dog{ constructor(breed, color, age, name){ //super在这里就相当于调用了父类的构造函数。 //super不可以省略,即使是个空括号也要写 super(breed, color, age); this.name = name; }}const h2 = new Haskie("哈士奇","黑白",5,"二哈");console.log(h2.name,h2.breed,h2.color,h2.age);h2.bark();
extends 这是继承 例子下面b继承a
上面用的super是什么呢,下面来解释
super
关键字,既可以当函数来使用,也可以当对象来使用。是一个方法
第一种情况:super作为函数调用时,表示父类的构造函数。
作为函数时,super()只能用在子类的构造函数中
class A { } class B extends A { //B使用A的方法 constructor() { super(); //不会报错 } fn() { } }
class A { } class B extends A { //B使用A的方法 constructor() { //构造函数B的属性 } fn() { super(); //报错(作为函数时,super()只能用在子类的构造函数中) } }
第二种情况
super作为对象时,在普通方法中,指向父类的原型对象。
class A { p() { return 1; }}class B extends A { constructor() { super(); console.log(super.p());//1 }}let b = new B();console.log(b.p());//1
转载地址:https://blog.csdn.net/z18237613052/article/details/114118233 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!