当前位置 博文首页 > 小丞同学:JS面向对象编程

    小丞同学:JS面向对象编程

    作者:[db:作者] 时间:2021-07-06 21:45

    面向对象编程

    在学习了js高级以及es6之后,再来学习面向对象编程,之前在学习es6canvas的时候已经有接触到了这种思想,感觉还是需要在深入的学习一下,这部分内容牵扯到很多原型链部分的东西,当做复习一下还是很不错的!

    ES5中的面向对象

    面向对象编程(OOP)具有灵活、代码可复用、高度模块化等特点。

    1. 对象是单个实物的抽象

    2. 对象是一个容器,封装了对应的属性方法,属性是对象的状态,方法是对象的行为(完成的任务)

    构造函数实例化对象

    ES5中没有class类的概念,所以面向对象是基于构造函数和原型链的,

    注意:构造函数的名字的第一个字母要大写

    特点

    1. 函数体内使用this关键字,代表了所要生成的对象实例
    2. 生成对象,必须使用new关键字实例化
    function Dog() {
    	this.name = name;
    	this.age = age;
    }
    var dog1 = new Dog('dw', 10)
    

    如果没有使用new关键字,则结果会是undefind,原因是该函数没有返回值

    instanceof的用法

    instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。返回trueorfalse

    通过instanceof来判断当前的的对象是否是实例化出来的,如果是实例化出来的this指向实例化出来的对象,也就是这里的Person,否则作为普通函数来说当前的this指向window

    function Person(name, age){
    	if(this instanceof Person){
    		// this指向了当前的实例,外部使用了关键字new
    		this.name = name;
    		this.age = age;
    	}else{
    		// this指向了window,外部没有使用了关键字new
    		return new Person(name,age);
    }
    

    new命令内部原理

    1. 创建一个空对象
    2. 构造函数的this,继承函数原型
    3. this指向构造函数的对象实例,执行构造函数内容为新对象添加属性和方法
    4. 返回这个对象
    var obj = {}//创建空对象
    obj.__proto__ = Person.prototype;//继承作用域
    Person.call(obj,)//改变this指向
    return obj //返回对象
    

    constructor属性

    每个对象在创建时都会自动拥有一个构造函数属性constructor

    constructor是对象__proto__上的一个属性(如果该对象是函数,则在其prototype上),通常指向生成这个对象的函数,也就是指向构造函数的引用

    obj.constructor === Obj
    

    使用构造函数创建对象的利弊

    1. 代码冗余
    2. 能够共享内部的属性和方法

    原型对象

    function Foo(){};
    var foo = new Foo();
    

    原型对象:Foo.prototype

    实例对象: foo就是实例对象,每一个原型对象中都有一个__proto__,每个实例对象都有一个constructor属性,这个constructor通过继承关系继承来的,它指向了当前的构造函数Foo

    构造函数:用来初始化新创建对象的函数,Foo是构造函数,自动给构造函数赋予一个属性prototype,该属性指向了实例对象的原型对象

    原型对象,实例对象,构造函数三者的关系

    function Foo(){}
    var foo = new Foo()
    

    在这里插入图片描述

    prototype属性的作用

    继承机制:通过原型对象(prototype)实现继承

    原型对象的作用,就是定义所有实例对象共享的属性和方法

    Foo.prototype.name = 'ljc';
    

    原型链

    tips:所有的对象都有自己的原型对象

    原型链对象的原型 => 原型的原型 => 原型的原型的原型 => null

    所有的对象都继承了Object.prototype上的属性和方法

    查找属性和方法的规则:js引擎会先寻找对象本身的属性和方法,如果找不到就到它的原型对象去找,如果还是找不到,就到原型的原型去找,如果直到最顶层的Object.prototype还是找不到,就会返回undefined

    constructor属性注意点:一旦我们修改构造函数的原型对象,为防止引用出现问题,同时也要修改原型对象的constructor属性

    创建新对象拥有数组的方法

    function MyArray(){};//构造函数
    MyArray.prototype = Array.prototype;//复制数组的原型对象,获得方法
    MyArray.prototype.constructor = MyArray;//改变constructor指向
    var arr = new MyArray();//实例化对象
    

    创建对象的n种方式

    1. 对象字面量

    1. 字面量
    var Person = { name: 'ljc' }
    
    1. new关键字
    var obj = new Object();
    obj.name = 'ljc';
    console.log(obj);
    
    1. Object.create(对象)
    var a = {
    	getName:function(){
    		console.log('ljc');
    	}
    }
    
    var b = Object.create(a);
    b.getName();
    

    缺点:代码冗余

    2. 工厂模式

    优点:能够创建多个类似的对象

    function createObj(name,age) {
    	var o = new Object();//创建对象
        //添加属性和方法
    	o.name = name;
    	o.age = age;
    	o.sayName = function() {
    		console.log(this.name);
    	}
        //返回对象
    	return o
    }
    var obj = createObj('ljc',19)//每次调用返回一个对象
    

    缺点:所有的constructor指向都相同,没有解决对象识别问题

    3. 构造函数模式

    function Person(name,age){
    	this.name = name;
    	this.age = age;
    	this.sayName = function(){
    		console.log(this.name);
    	}
    }
    var man = new Person('ljc',19);
    var woman = new Person('dw',18);
    

    通过在外部使用new关键字,将属性和方法通过this绑定到相应的对象上,解决了工厂模式的遗留问题

    缺点:每个对象都会有一个sayName方法,执行的功能是一样的,但是却仍然占用了不同的内存空间,浪费了内存资源

    1. 构造函数扩展模式
    function Person(name,age){
    	this.name = name;
    	this.age = age;
    	this.sayName = sayName;
    }
    function sayName(){
    	console.log(this.name);
    }
    

    sayName方法定义成全局函数,解决了内存浪费的问题

    缺点:污染全局空间

    1. 寄生构造函数模式
    function createObj(name,age) {
    	var o = new Object();//创建对象
        //添加属性和方法
    	o.name = name;
    	o.age = age;
    	o.sayName = function() {
    		console.log(this.name);
    	}
        //返回对象
    	return o
    }
    var obj = new createObj('ljc',19)
    

    结合了工厂模式和构造函数模式:创建一个函数,函数体内部实例化一个对象,并且将对象返回,在外部使用new来实例化对象

    缺点:由于没有使用构造函数,所以instanceof运算符和prototype属性没有意义

    1. 稳妥构造函数模式
    function Person(name){
    	var a = 10;
    	var obj = new Object();
    	obj.sayName = function(){
    		console.log(a);
    		console.log(name);
    	}
    	return o;
    }
    var p1 = Person('ljc');
    p1.sayName();
    

    没有公共属性,并且它的方法也不引用thisname属于函数内部的私有属性,有点像闭包,p1被称为稳妥对象

    缺点:由于没有使用构造函数,所以instanceof运算符和prototype属性没有意义

    4. 原型模式

    将属性方法绑定在prototype上,实现共享

    注意:需要改变constructor指向

    function Person(){}
    Person.prototype = {
    	constructor: Person,
    	name: 'ljc',
    	age: 19,
    	friends:['dw','xy'],
    	sayName:function(){
    		console.log(this.name);
    	}
    }
    var me = new Person();
    var you = new Person();
    

    每个通过Person实例化出来的对象都会继承函数的原型

    缺点:当我们修改其中一个对象的属性时,另一个对象下的也会被修改

    me.friends.push('jc');
    console.log(you.friends);//["dw","xy","jc"]
    

    5. 组合模式

    认同度最高的一种创建自定义对象的模式

    function Person(name,age){
    	// 定制当前对象自己的属性
    	this.name = name;
    	this.age = age;
    	this.friends = ['dw','xy'];
    };
    //定制公共的方法
    Person.prototype = {
    	constructor: Person,
    	sayName: function(){
    		console.log(this.name);
    	}
    }
    var wo = new Person('wo', 18);
    var you = new Person('you', 20);
    

    解决了原型模式状态共享问题,将私有的属性定义在函数内部,共有的方法通过原型去实现继承引用

    下一篇:没有了