进击的JavaScript(对象,继承,单例模式)

1.   JavaScript的面向对象

面向对象:对外统一提供调用接口的编程思想。

对象: 依靠构造器(constructor)利用原型(prototype)构造出来。

任何模式下,同种模式中的创造出来的对象都是独立存在的。

构造方式: (使用构造函数申明的变量需要实例化后才能进行遍历 )

//构造方式定义对象

function CPerson(name,sex,age) {//注意这里 构造函数首字母大写
 this.name = name;    //this指代当前对象 --> p1
 this.sex = sex;
 this.age = age;
 this.show = function () {
 console.log(this.name, this.age, this.sex);
 }
}
var p1 = new CPerson('zhangsan','男','100');
 p1.show();
var p2 = new CPerson('lisi','女','14');
 p2.show();

工厂方式: 

//工厂方式:

   function createObject(name, age) {    //集中实例化的函数   
        var obj = new Object();   
        obj.name = name;  
        obj.age = age;   
        obj.run = function (){  
          return this.name + this.age + '运行中...';  
        };  
         return obj;  
    }  
    var box1 = createObject('Lee', 100);    //第一个实例  
    var box2 = createObject('Jack', 200);   //第二个实例  
    alert(box1.run());  
    alert(box2.run());  //保持独立 

构造方式和工厂模式的不同: 

1. 构造方式不会显示创建对象,将属性值赋值给this,不需要return 对象

2. 工厂模式在内部创建object对象,返回object对象,属性和方法都是付给object对象。

原型模式:函数本身为空内容,利用prototype定义一些属性和方法。可以让所有实例化的对象都拥有它包含的属性和方法。

//原型模式
function Car(){
}

Car.prototype = {
    color: "red",
    doors: 4,
    showColor: function() {
        alert(this.color)
    }
}

var car1 = new Car();
alert(car1.doors)    //4
var car2 = new Car();
car1.showColor();    //red

混合模式:构造+原型

//混合模式:
 function Blog(name, url, friend ) {
      this.name = name;
      this.url = url;
      this.friend = friend;
  }
  
 Blog.prototype.alertInfo = function () {
     console.log('名字:'+this.name + ' 空间:' + this.url + '好友:' +  this.friend);
 }
 
 var blog = new Blog("zhangsan","http://www.baidu.com/",["aaa", "bbb","ccc", "ddd"]);
 var blog2 = new Blog("lisi","http://www.sina.com/",["aaa", "bbb","ccc", "ddd"]);
 	 blog.alertInfo();
 	 blog2.alertInfo();

2.   JavaScript的闭包

闭包:能够访问另一个函数作用域内的变量的函数。

扫描二维码关注公众号,回复: 2800611 查看本文章
function a(){ 
 var i = 0; 
   function b(){ 
	  alert(++i);//++i返回的则是自增后的值
   } 
 return b;
}
var c = a();
c();

特点:函数b在函数a内嵌套,函数a需要返回函数b

用途:1. 读取函数内部变量 2. 让i变量的值保存在内存中

   优点:有利于封装,可以访问局部变量  

   缺点:内存占用浪费资源,容易产生内存泄漏

3.   原型继承

原型: 是利用prototype对象添加属性和方法

原型链:JavaScript在创建对象的时候都有一个__proto__的内置属性,用于指向创建它的函数对象的原型对象ptototype。

var person = function() {}
var p = new person(); //有三个阶段
// 1. var p = {} //创建对象
// 2. p.__proto__ = person.prototype //自带的一个属性
// 3. 创建对象(初始化对象) //person.call(p)
alert(p.__proto__ === person.prototype) //true

原型继承:

function Person(name,age){    //父
    this.name=name;  
    this.age=age;  
}  
Person.prototype.sayHello=function(){  
    alert("使用原型得到Name:"+this.name);  
}  
var per=new Person("张三",21);                     //per.__proto__ === Person.prototype
per.sayHello(); //输出:使用原型得到Name:张三  


function Student(){} //子
Student.prototype=new Person("李四",21); //原型继承     Student.__proto__ === Person.prototype

var stu=new Student();                             //stu.__proto__ === Student.prototype
Student.prototype.grade=5;  
Student.prototype.intr=function(){  
    alert(this.grade);  
}  
stu.sayHello();//输出:使用原型得到Name:李四  
stu.intr();//输出:5  

4.  构造函数继承

在子类内部构造父类的对象实现继承。

//构造方法继承

function  Parent(name){  
    this.name=name;  
    this.sayParent=function(){  
        alert("Parent:"+this.name);  
    }  
} 
function  Child(name,age){  
    this.tempMethod=Parent;//用父对象来创建子对象,从而调用父对象的属性和方法
    this.tempMethod(name);  //子对象的参数name传递到父对象中
    this.age=age;  
    this.sayChild=function(){  
        alert("Child:"+this.name+"age:"+this.age);  //this.name调用的是父对象的name
    }  
}
var parent=new Parent("张三");  
parent.sayParent();  
var child=new Child("李四",24);   
child.sayChild(); 

name:  "李四" --> this.tempMethod(name) --> Parent(name) --> this.name=name="李四"

(父对象被子对象继承,所有的属性和方法都将传递到子对象中)

5.   call和apply

用法:(劫持另一个对象的方法,继承另一个对象的属性)

    call :调用一个对象的一个方法,以另一个对象替换当前对象。

    apply : 应用某一个对象的一个方法,用另一个对象替换当前对象。

区别:对象内置方法中的call和apply都可以用于继承,区别在于传参方式不同。

// call aplay继承
function  Person(name,age,love){  
    this.name=name;  
    this.age=age;  
    this.love=love;  
    this.say=function say(){  
        alert("姓名:"+name);  
    }  
}
//call方式  
function student(name,age){  
    Person.call(this,name,age);  //this指代的是当前对象Student,通过继承父元素中的this就通通变为Student
}  
//apply方式  
function teacher(name,love){  
    Person.apply(this,[name,love]);  
    //Person.apply(this,arguments); //跟上句一样的效果,arguments  
}  
var per=new Person("张三",25,"李四");   
per.say();  
var stu=new student("王武",18);
stu.say();  
var tea=new teacher("赵六",16);
tea.say();

常见到使用方法: 

var arr = [1,2,3]

Math.max(arr)    //NaN
Math.max.apply(null,arr) //3

Math.max()  需要传递的参数是枚举的,而apply会将数组转换成一个一个的参数。

第一个参数null是因为需要有一个对象的方法执行这个运算,所以直接传递了null充当这个对象。

进一步了解:

function add(a,b)  {  
    alert(a+b);  
}  
function subs(a,b)  {  
    alert(a-b);  
}   
//add.call(subs,3,1); 
add.apply(subs,[3,1]);  //4

apply中的subs改为null, 或则{} 等对象,都能够成立。

再进一步:(指定了this指代的对象)

function Animal(){    
    this.name = "Animal";    
    this.showName = function(){    
        alert(this.name);    
    }    
}    
function Cat(){    
    this.name = "Cat";    
}    
var animal = new Animal();    
var cat = new Cat();    
      
//animal.showName.call(cat,",");    
animal.showName.apply(cat,[]);     //cat

animal.showName.apply(animal,[])     //animal

   通过call或apply方法,将原本属于Animal对象的showName()方法交给对象cat来使用了,输入结果为"Cat"  。

6. 了解几个关键字

delete: 只能删除自身对象的属性,不能删除原型链中的属性和变量。在JavaScript中作为一元运算符。

callee:指代函数本身。是arguments的一个属性。

var sum = function (n) {
    if (n <= 1)
        return 1;
    else
        return n + arguments.callee(n-1)//调用了函数本身
}
alert(sum(5));

this: 

var x = 1; 
function test() { 
	this.x = 0;  // this指代的是全局变量,改变了全局变量x的值
} 
test(); 
alert(x);//0 

this,apply:

var x = 0;
function test() { 
	alert(this.x);//this代表对象o 
} 
var o = {}; 
o.x = 2; 
o.m = test; 
o.m(); //1 
o.m.apply();     //1
o.m.apply(o);    //0

7. 对象冒充

对象冒充,是指将父类的属性和方法一起传给子类作为特权属性和特权方法  

function Person(name,age){  
    this.name = name;  
    this.age = age;  
    this.sayHi = function(){  
        alert('hi');  
    }  
}  
Person.prototype.walk = function(){ //此方法没有继承,调用报错 
    alert('walk.......');  
}  
function Student(name,age,grade){  
    //是指将父类的属性和方法一起传给子类作为特权属性和特权方法。  
    this.newMethod = Person;  
    this.newMethod(name,age);  
    delete this.newMethod;//如果不删除,newMethod还有Person的prototype方法walk  
    this.grade = grade;  
}  
var s1 = new Student('xiaoming',10,3);  //s1作为Student的对象,拥有父类和子类的属性
console.log(s1.name);      //xiaomming
console.log(s1.age);        //10

console.log(s1.walk());   //   VM1415:19 Uncaught TypeError: s1.walk is not a function at <anonymous>:19:16

//Student { name="xiaoming", age=10, grade=3, sayHi=function() }  
//s1.walk();//报错 s1.walk is not a function  

结论:Student类只继承了Person类的特权属性和方法,并没有继承Person类的共有属性和方法(如:walk())。 

8. 设计模式

GoF定义:设计模式是在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。

设计模式: 复用他人经验。

优点:1. 行之有效的解决方法; 2. 易于修改和维护  3. 便于交流和沟通

单例模式:

保证一个类仅有一个实例,并提供一个访问它的全局访问点。(即一个类只能实例化出一个对象)

方法: 在每一次创建实例之前判断,不存在则创建,否则返回。

function Minister(name) { // 大臣
	this.name = name;
}
Minister.prototype.say = function () {
	console.log(this.name + ':大王,冤枉啊!');
};
var Emperor = (function () {	//立即执行函数
	var instance = null; //相当于私有属性,外部无法进行访问

	function Emperor() {
		if (instance) {
			return instance;
		}
		this.name = '大王';
		this.id = Math.random();
		return instance = this; //构造函数中this相当于实例化的对象 Emperor
	}
	Emperor.prototype.say = function () {
		console.log(this.name + this.id + ':滚……');
	};

	return Emperor;		//返回这个构造函数
})();
var minister1 = new Minister('张三');
var emperor1 = new Emperor();    //实例化
var minister2 = new Minister('李四');
var emperor2 = new Emperor();
var minister3 = new Minister('王二麻子');
var emperor3 = new Emperor();
minister1.say();
emperor1.say();
minister2.say();
emperor2.say();
minister3.say();
emperor3.say();

具有JavaScript特色的单例模式:

// 通用惰性单例
function createLoginLayer() {
	var loginLayer = document.createElement('div');
	loginLayer.id = 'loginLayer';
	loginLayer.innerHTML = '登录窗口';
	loginLayer.style.display = 'none';
	document.body.appendChild(loginLayer);
	return loginLayer;
}
function createMaskLayer() {
	var maskLayer = document.createElement('div');
	maskLayer.id = 'maskLayer';
	maskLayer.style.display = 'none';
	document.body.appendChild(maskLayer);
	return maskLayer;
}
function getSingleton(fn) {
	var instance = null;

	return function () {
		return instance || (instance = fn.apply(null, arguments));//假如有参数的话
	};
}
var createSingletonLoginLayer = getSingleton(createLoginLayer);
var createSingletonMaskLayer = getSingleton(createMaskLayer);
document.getElementById('loginBtn').onclick = function () {
	var loginLayer = createSingletonLoginLayer();
	var maskLayer = createSingletonMaskLayer();
	loginLayer.style.display = 'block';
	maskLayer.style.display = 'block';
};

猜你喜欢

转载自blog.csdn.net/weixin_41892205/article/details/81700109
今日推荐