文章目录
面向对象
面向对象是一种编程思想,相对于面向过程而言。
面向过程关注的是每一个元素,元素之间的关系、顺序…
面向对象关注是找到一个对象,直接完成效果。
一、常见创建对象的方式
1. 构造函数方式
调用系统内置的构造函数创建对象,new Object()
// 创建一个对象
const obj = new Object();
// 动态给对象添加键值对
obj.name = "lucy";
obj.age = 18;
obj.gender = '女';
2. 字面量方式
直接使用字面量,也就是{}
const obj2 = {
name:'jack',
age:12
}
obj2.gender = '男';
3. 工厂函数方式
写一个工厂函数(普通函数),创建一个对象,可以给对象添加一些属性,可return对象
// 工厂函数
function createObj(name,age,gender){
// 手动创建对象
const obj = new Object();
// 手动添加属性
obj.name = name;
obj.age = age;
obj.gender = gender;
// 手动return 对象
return obj;
}
// 使用工厂函数创建对象
const zhangsan = createObj('张三',12,'女');
const lisi = createObj('李四',13,'男');
4. 自定义函数方式
自动创建对象,手动添加属性,自动返回对象
// 把函数Human当构造函数调用(和new一起使用)
const h1 = new Human('lucy',12,'女');
只要有new连用,在函数的开头自动添加const this = new Object();
.在函数结尾自动添加return this;
.
构造函数里面的this是创建好的那个对象,也可以成为实例对象。
function Human(name,age,gender){
// 自动创建对象,赋值给this
// const this = new Object();
//手动添加属性
this.name = name;
this.age = age;
this.gender = gender;
// 自动return this
// return this;
}
二、构造函数的使用注意点
1. 与new关键字连用
const h1 = new Human('lucy',12,'女');
2. 首字母大写
首字母不大写,只要与new连用,就是构造函数,有创建对象的能力。
建议构造函数的首字母大写。
3. 传参写进()
调用时,如果不需要传参可以不写(),建议都写上
4. this指向实例对象
构造函数内部的this,由于与new连用,this指的是创建好的实例对象
5. 构造函数内部不要写return
因为构造函数内部会自动返回一个对象:
如果return 一个复杂数据类型(
return [12,34,56];
),则构造函数返回是复杂数据类型如果return 一个基本数据类型(
return 123;
),则构造函数还是返回this的实例对象
6. 构造函数内的方法
构造函数内部可以赋值函数,写为构造函数里面的方法。
function Person(){
this.name = 'jack';
this.age = 18;
this.sayHi = function(){
console.log("构造函数constructor")
}
}
const o1 = new Person();
const o2 = new Person();
// 调用构造函数里的方法
o1.sayHi();
o2.sayHi();
// 两个对象中的sayHi函数占用了两个不同的内存空间
复杂数据类型比较的是地址
需要一个东西,使得同一个构造函数new出来的对象,可以共用,就是原型 prototype
三、原型 prototype
1. 概念
每一个函数自身带有一个成员,prototype,是一个对象空间
function fn(){} console.dir(fn)
构造函数中的原型
function Person(){} // Person = { prototype:{}}
给这个对象动态地添加一些东西
Person.prototype.sayHi = function(){
console.log('hi')
}
重点:
在函数prototype中存储的内容,不是给函数使用的(函数也能用),是给函数的每一个实例对象使用的。也就是给构造函数new出来的对象使用的。
2. 使用方法
__proto__
每一个对象都自带一个成员,叫做__proto__,是一个对象空间
const obj = {name:'lucy'};
/*
在浏览器中输出
obj={
name:'lucy',
[[Prototype]]:{}
}
// [[Prototype]]的真实名字是__proto__,是浏览器自己使用的,不希望用户去使用
*/
当访问一个对象中的成员时,
- 如果对象本身有这个成员,就会直接给结果,
- 如果没有,就会去__proto__对象空间中找,如果有就会给结果(找不到返回undefined,参见下一文原型链)
function Person(){
this.name='lucy';
this.age = 12
}
Person.prototype.sayHi = function(){
console.log('hello world');
}
const p1 = new Person();
console.log(p1);
/*
P1 = {
name:'lucy',
age:12,
__proto__=Person.prototype:{
sayHi:function(){}
}
}
*/
const p2 = new Person();
console.log(p2);
console.log(p1.sayHi() == p2.sayHi())//true
此时,p1 p2 使用的都是原型中的函数,比较的内存空间地址一致
总结:
在书写构造函数时,
属性写在构造函数里面,如this.name = 'lucy'
,
方法写在原型对象里面,如Person.prototype.sayHi = function(){}
3. 构造函数与实例对象
-
数组
const arr = new Array(1,2,3); const arr2 = ['hello']; // 数组中的所有方法,如map,forEach,filter... console.log(Array.prototype) Array.prototype.abc = function(){ console.log(this); console.log("新添加的abc方法"); } // 数组调用abc方法 arr.abc() arr2.abc() // 原型上的方法里面的this是实例对象
-
函数
const fn = function(){alert(1)}; function fn2(){alert(2)}; const fn3 = new Function('alert(3)'); fn(); fn2(); fn3(); // 所有的js函数都是Function构造new出来的 //构造函数的prototype == 它的实例对象.__proto__ console.log(fn.__proto__ == Function.prototype) //true console.log(Function.__proto__ == Function.prototype) // true
js中的顶级构造函数是Object