zoukankan      html  css  js  c++  java
  • 一篇笔记带你快速掌握面向对象的Javascript(纯手打)

    /**
     * 创建对象
     */
    
    //1.工厂模式
    //特点:
    //创建的对象无法识别其对象类型,不支持instanceof等判断方法,无法标识不同的对象
    function createObj(name,sex,age){
    	var obj = new Object();
    	obj.name = name;
    	obj.sex = sex;
    	obj.age = age;
    	obj.show = function(){
    		alert(this.name);
    	}
    	return obj;
    }
    var obj = createObj("jackie","male",29);
    console.log(obj);
    
    
    
    //2.构造函数模式
    //特点:
    //使用new创建对象,因此可以使用instanceof,constructor等来识别对象类型
    //new创建的对象,内部会有一个__proto__指针指向构造函数的prototype
    //如果漏写new,会导致构造函数内部this指针指向window,导致严重错误
    //缺点是无法复用公用的方法,创建多个对象时会重复创建多次公用方法
    function CreateObj(name,sex,age){
    	this.name = name;
    	this.sex = sex;
    	this.age = age;
    	this.show = function(){
    		alert(this.name);
    	}
    }
    
    var obj = new CreateObj("jackie","male",29);
    console.log(obj);
    console.log(obj.constructor); //Function CreateObj
    console.log(obj instanceof CreateObj); //true
    console.log(obj instanceof Object); //true
    console.log(obj.__proto__ === CreateObj.prototype); //true
    
    
    
    //3.原型模式
    //所有属性方法均绑在原型上,这样生成的对象打印是空,但是属性和方法可以通过原型链查找获取到
    //在实例上重写原型链已有属性不会改变原型链上的对应属性,就算设置为null也不行,只能屏蔽掉
    //屏蔽掉原型属性后想恢复需要使用delete操作符移除对应实例属性
    //多个实例共享绑在原型链上的属性和方法,且原型只需要初始化的时候创建一次而已
    //可以使用instanceof,constructor,isPrototypeOf等方法来判断对象所属
    //缺点在于属性无法传参数,导致创建的对象属性都相同,方法也是共享,无法体现出对象的独一性
    //引用类型的属性多个对象会同时改变,例如数组
    function CreateObj(){
    
    }
    CreateObj.prototype.name = "jackie";
    CreateObj.prototype.sex = "male";
    CreateObj.prototype.age = 29;
    CreateObj.prototype.show = function(){
    	alert(this.name);
    }
    
    var obj = new CreateObj();
    var obj2 = new CreateObj();
    console.log(obj); // {}
    console.log(obj.name); // jackie
    console.log(obj2.name); //jackie
    obj2.name = "tommy";
    console.log(obj2.name); //tommy
    delete obj2.name;
    console.log(obj2.name); //jackie
    console.log(obj.show === obj2.show); //true
    console.log(obj.constructor); //Function CreateObj
    console.log(obj2 instanceof CreateObj); //true
    console.log(CreateObj.prototype.isPrototypeOf(obj)); //true
    console.log(CreateObj.prototype.constructor === CreateObj); //true
    CreateObj.prototype.arr = [1,2,3];
    obj.arr.push(4);
    console.log(obj2.arr); //[1,2,3,4]
    
    
    
    //4.组合构造函数原型模式
    //属性使用构造函数传参来构造,公用方法绑定在prototype上实现复用
    //可以使用instanceof,constructor,hasOwnProperty,in等方法来判断对象所属
    //此时引用类型数据存在构造函数内,不存在不同对象相互影响的问题
    //结合了构造函数和原型链的优势,解决了两者存在的问题,是目前最为常用的一种方式
    function CreateObj(name,sex,age){
    	this.name = name;
    	this.sex = sex;
    	this.age = age;
    	this.arr = [1,2,3];
    }
    CreateObj.prototype.show = function(){
    	alert(this.name);
    }
    
    var obj = new CreateObj('jackie','male',29);
    console.log(obj);
    console.log(obj.constructor); //Function CreateObj
    console.log(obj instanceof CreateObj); //true
    console.log(obj.hasOwnProperty('sex')); //true
    console.log('show' in obj); //true
    var obj2 = new CreateObj('jackie','male',29);
    obj.arr.push(4);
    console.log(obj.arr); //[1,2,3,4]
    console.log(obj2.arr); //[1,2,3]
    
    
    //5.单例模式
    //只能创建一次,常用于单页面,实现某个页面的具体功能
    //相对于面向过程的散乱写法,这种写法可维护性更好
    var CreateObj = {
    	name: 'jackie',
    	sex: 'male',
    	age: 29,
    	init: function(){
    		console.log(this.name,this.sex,this.age);
    	}
    }
    
    CreateObj.init(); //jackie male 29
    
    
    /**
     * 继承
     */
    
    //1.原型链继承
    //将父类实例赋值给子类的prototype,这样父类的所有方法和属性(无论是构造函数还是原型上定义的)全部都继承给了子类
    //使用instanceof发现子类是子类,父类,Object类的实例,这是由于原型链的关系,一层层往内找,最后终点是Object类
    //继承后子类实例的constructor会被指向父类,因此如果需要,可以手动修正将constructor指回子类,虽然指回后的是可枚举的constructor
    //由于是绑定在原型链上的继承,因此引用类型数据在多个实例内是共享的,会相互影响
    //一个严重缺陷,子类构造函数无法传参数,因为继承来的属性全部在原型链上,和构造函数没有联系,因此继承后子类所有对象的属性都相同
    function Super(age){
    	this.name = 'yinshawn';
    	this.age = age;
    	this.arr = [1,2,3];
    }
    Super.prototype.show = function(){
    	console.log(this.name);
    }
    function Sub(){
    
    }
    Sub.prototype = new Super(29);
    
    var sub = new Sub();
    console.log(sub.name); //yinshawn
    console.log(sub.age); //29
    sub.show(); //yinshawn
    console.log(sub.constructor); //Function Super
    Sub.prototype.constructor = Sub;
    console.log(sub.constructor); //Function Sub
    console.log(sub instanceof Sub); //true
    console.log(sub instanceof Super); //true
    console.log(sub instanceof Object); //true
    var sub2 = new Sub();
    sub.arr.push(4);
    console.log(sub2.arr); //[1,2,3,4]
    
    
    
    //2.构造函数继承
    //通过call或apply在子类构造函数里调用父类构造函数,call(this,param1,param2,param3)或apply(this,arguments)均可
    //此类继承可以在子类的构造函数内传参,使生成的对象真正拥有自己的属性
    //由于是在构造函数内,因此引用类数据不会有多个对象相互影响的问题
    //依然可以使用constructor和instanceof来判断对象所属
    //一个严重缺陷,所有需要继承的属性和方法都需要写在构造函数内,原型链上的方法属性无法继承,如果全部写在构造函数内,无法实现方法复用
    function Super(age,sex){
    	this.name = "jackie";
    	this.age = age;
    	this.sex = sex;
    	this.arr = [1,2,3];
    }
    Super.prototype.show = function(){
    	console.log(this.name);
    }
    function Sub(age,sex){
    	Super.call(this,age,sex);
    	Super.apply(this,arguments);
    }
    
    var sub = new Sub(29);
    console.log(sub.name); //jackie
    console.log(sub.age); //29
    console.log(sub.show); //undefined
    var sub2 = new Sub(29,'female');
    console.log(sub2.sex); //female
    sub2.arr.push(4);
    console.log(sub.arr); //[1,2,3]
    console.log(sub2.arr); //[1,2,3,4]
    console.log(sub instanceof Super); //true
    console.log(sub.constructor); //Function Sub
    
    
    
    //3. 组合构造函数原型继承
    //即结合构造函数继承和原型继承,两者合二为一
    //此时子类构造函数可以传参,不仅可以继承构造函数内的属性方法,也可以继承原型链上的属性方法,自己可以灵活分配
    //唯一美中不足的是会执行两次父类构造函数,而且会生成两组相同的属性,同时存在于原型链和构造函数内
    function Super(age,sex){
    	this.name = "jackie";
    	this.age = age;
    	this.sex = sex;
    	this.arr = [1,2,3];
    }
    Super.prototype.show = function(){
    	console.log(this.name);
    }
    function Sub(age,sex){
    	Super.call(this,age,sex);
    	Super.apply(this,arguments);
    }
    Sub.prototype = new Super();
    Object.defineProperty(Sub.prototype,"constructor",{
    	value: 'Sub',
    	enumerable : false
    });
    
    var sub = new Sub(29,'male');
    console.log(sub.age); //29
    console.log(sub.show); //Function
    console.log(sub instanceof Super); //true
    console.log(sub.constructor); //Sub
    
    
    
    //4.单对象浅复制继承
    //不使用构造函数,直接实现两个对象之间的继承,使用ES5的create方法来继承父类,并自己添加新属性或重载父类属性
    //若考虑兼容性问题,则可自定义函数,实现类似效果
    //使用非标准的__proto__也可实现简单继承
    var Super = {
    	name: 'jackie',
    	age: 29
    }
    
    //方法1
    var Sub = Object.create(Super,{
    	sex : {
    		value: 'male'
    	},
    	age: {
    		value: 92
    	}
    });
     
    console.log(Sub.name); //jackie
    console.log(Sub.sex); //male
    console.log(Sub.age); //92
    
    //方法2
    function create2(obj){
    	var F = function(){};
    	F.prototype = obj;
    	return new F();
    }
    
    var Sub = create2(Super);
    Sub.age = 92;
    console.log(Sub.name); //jackie
    console.log(Sub.age); //92
    
    //方法3
    var Sub = {
    	__proto__: Super,
    	age: 92
    }
    
    console.log(Sub.name); //jackie
    console.log(Sub.age); //92
    
    
    
    //5.寄生组合式完美继承
    //目前最完美的继承方式,主要在构造函数原型组合继承基础上改动
    //改动了其中原型继承里将父类实例赋值给子类的prototype这一段,这里产生的缺陷也就是多调用了一次父类构造函数,而且将原本构造函数内的属性记录在了原型里
    //改动方向是避免调用构造函数,而是使用别的方法来得到父类实例,且这个实例上没有跟构造函数相关的属性,例如Object,Object.create,自定义浅复制函数等
    //主要思路就是将父类prototype通过Object方法或create方法生成一个只带有父类原型属性的副本,将这个副本的constructor指正后赋值给子类prototype
    //这种方法是目前最完美的方法,无明显缺陷
    function Super(age,sex){
    	this.name = "jackie";
    	this.age = age;
    	this.sex = sex;
    	this.arr = [1,2,3];
    }
    Super.prototype.show = function(){
    	console.log(this.name);
    }
    function Sub(age,sex){
    	Super.call(this,age,sex);
    	Super.apply(this,arguments);
    }
    var prototype = Object(Super.prototype); //得到一个父类实例
    prototype.constructor = Sub;
    Sub.prototype = prototype;
    
    var sub = new Sub(28,'male');
    console.log(sub.show); //Function
    console.log(sub.age); //28
    console.log(sub instanceof Super); //true
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  • 相关阅读:
    第一个独立开发的游戏 怪斯特:零 已经上线APP STORE!
    Cocos2d 利用继承Draw方法制作可显示三维数据(宠物三维等)的三角形显示面板
    java 实现 多态的 三要素
    mysql 基础语法掌握~ This is just the beginning.
    rem ~~ 你懂了吗?
    两个css之间的切换
    JavaScript高级程序设计(第3版)
    保持底部~~永远在底部
    文字要对齐!!!
    改变this不要怕!!!
  • 原文地址:https://www.cnblogs.com/raoyunxiao/p/4876605.html
Copyright © 2011-2022 走看看