核心就是 对象,类,实例三者之间的关系
js中万物皆对象
单例模式远古时期
- 把描述同一个事物的属性和方法放在同一个对象中,起到分组作用
- 说白了就是一个破对象
let person1 = {
name: "小白",
age: 19
}
let person2 = {
name: "甜甜",
age: 18
}
// => person1和person2也叫做"命名空间"
工厂模式早期方式
- 单例模式虽然解决了分组的问题,但不能实现批量的生产,属于手工作业模式
- 于是诞生了"工厂模式",实现"低耦合高内聚"
//=>把实现同一个事件的相同代码放到一个函数中,以后再想实现这个功能,只需要执行当前的函数即可->函数的封装
function createJsPerson(name, age){
var obj = {};
obj.name = name;
obj.age = age;
obj.write = function(){
console.log('my name is' + this.name + 'i can write js!');
}
return obj
}
var p1 = createJsPreson('王玉', 18);
p1.write();
var p2 = createJsPreson('婷婷', 18);
p2.write();
- 所有的编程语言都是面向对象开发的->类的继承/封装/多态
- 继承:子类继承父类中的属性和方法
- 多态: 当前方法的多种形态,在后台语言中包含 (重载和重写)
- 重载:方法名相同,传的参数数据类型不同,就是2个方法都可以用(JS中没有重载)
- 在JS中会覆盖的(所以JS没有重载)
- 重写:子类重写父类的方法
- 重载:方法名相同,传的参数数据类型不同,就是2个方法都可以用(JS中没有重载)
//Js中有一个类似重载的方法但不是重载:我们可以根据传递参数的不一样,实现不同的功能
function sum(num){
if(typeoof num === 'undefined'){
return 0;
}
return num;
}
sum(100);
sum();
构造函数
- 目的: 就是为了创建一个自定义类,并且创建这个类的实例
- 构造函数构造原理:
- 1.在函数体的最前面隐式的加上 this = {}
- 2.执行this.xxx = xxx;
- 3.隐式的返回 return this;
构造函数模式 和 工厂模式的区别?
-
- 执行的时候
- new CreatePerson() -> 通过 new执行后 CreatePerson 就是一个类了
- 相同点:
- 都是形成一个私有的作用域,经历形参赋值 -> 预解释 -> 代码从上到下执行(类也有普通函数的一面)
- 通过new执行变成了一个类,但是它本身也是普通的函数
- 不同点:
- 在代码执行前,不用自己在手动的创建对象,浏览器会默认的创建一个this = {}
- 不用手动return,构造函数会自己return this
- 如果不传参数 可以不用小括号如 new Fn;
- JS中所有的实例都是对象数据类型的
- 构造函数: 手动返回基本类型的值还是默认返回this,return 对象才会改变
function CreatePerson (name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log(`姓名:${this.name}-年龄:${this.age}`)
}
}
const p1 = new CreatePerson("沐沐", 18);
p1.say();// this -> p1
let ss = CreatePerson("rr", 12);
console.log(ss.name);// undefined this -> window
检测某个实例是否是这个类
funtion Fn() {
this.x = 100;
this.getX = function() {
console.log(this.x);
}
}
let f1 = new Fn;
let f2 = new Fn;
// => 检测某个实例是否是这个类
console.log(f1 instanceof Fn);//=> true
console.log(f1 instanceof Array);// => false
console.log(f1 instanceof Object);// => true
// => 所有的实例都是对象数据类型的,而每一个对象数据类型都是Object这个内置对象的实例
console.log(f1.getX === f2.getX);//false
// in: 检测某一个属性是否属于这个对象 attr in object
console.log('getX' in f1);// => true 是它的一个属性
//=> hasOwnProperty: 检测某个属性是否为某个对象"私有属性",这个方法只能检测私有属性
console.log(f1.hasOwnProperty('getX'));// => true
// => 检测某一个属性是否是该对象的"共有属性"
function hasPubOwnProperty (obj, attr) {
// 是他的属性,并且不是私有属性
return (attr in obj) && !obj.hasOwnProperty(attr) === false;
}
- 例子1
function Fn(x, y) {
let sum = 10;
this.total = x + y;
this.say = function() {
console.log('总数为' + this.total);
}
}
let res = Fn(10, 20);//普通函数 非严格模式下this -> window
let f1 = new Fn(10, 20);//构造函数执行
let f2 = new Fn(10, 20);
console.log(f1.sum);// undefined
console.log(f1.total);// 30
console.log(f1 === f2)// false
- 例子2
function Fn() {
this.x = 100;
this.y = 200;
this.getX = function() {
console.log(this.x);
}
}
Fn.prototype.getX = function() {
console.log(this.x);
}
Fn.prototype.getY = function() {
console.log(this.y);
}
let f1 = new Fn;
let f2 = new Fn;
console.log(f1.getX === f2.getX);// false
console.log(f1.getY === f1.getY);// true
console.log(f1.__proto__.getY === Fn.prototype.getY); // true
console.log(f1.__proto__.getX === Fn.prototype.getX);// true
console.log(f1.getX === Fn.prototype.getX); // false
console.log(f1.constructor)// Fn
console.log(Fn.prototype.__proto__.constructor);// Object
f1.getX();// 100
f1.__proto__.getX();// undefined
f2.getY();// 200;
f2.__proto__.getY();//undefined
图解流程图如下:
- 例题3
- 阿里的面试题
function Dog(name) {
this.name = name;
}
Dog.prototype.bark = function() {
console.log('wangwang');
}
Dog.prototype.sayName = function() {
console.log(`my name is ${this.name}`);
}
function _new (ctor, ...args) {
// => 根据后面的结果完成你的代码
// 1.创建空对象, 对象.__proto__ = ctor.protoType
obj = {}
obj.__proto__ = ctor.prototype;
// 2. 像普通函数一样执行,但是需要让函数中的this指向创建的实例对象(实参也要传进去)
let result = ctor.call(obj, ...args);
// 3. 监听方法的返回值,如果是原始值类型则把创建的实例返回...
if(typeof result !== 'object' || result === null) {
return obj;
}
return result;
}
let sanmao = _new(Dog, '三毛');
sanmao.bark();// => wangwang
sanmao.sayName();// => "my name is 三毛"
console.log(sanmao instanceof Dog);// => true
优化写法
function _new (ctor, ...args) {
// => 根据后面的结果完成你的代码
if(!ctor.prototype || ctor === Symbol || ctor === BigInt) {
throw new TypeError('ctor is not a contructor function');
}
// 1.创建空对象, 对象.__proto__ = ctor.protoType
let obj = Object.create(ctor.prototype);
// 2. 像普通函数一样执行,但是需要让函数中的this指向创建的实例对象(实参也要传进去)
let result = ctor.call(obj, ...args);
// 3. 监听方法的返回值,如果是原始值类型则把创建的实例返回...
if (result !== null && /^(object|function)&/.test(typeof result)) return result;
return obj;
}