javascript 面向对象编程

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>oop.html</title>
	
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">
    <meta name="keywords" content="keyword1,keyword2,keyword3">
    <meta name="description" content="this is my page">
    <meta name="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
	<script type="text/javascript" src="../js/jquery-1.11.3.js"></script>

  </head>
  
  <body>
	<div id="div"></div>
	<script type="text/javascript">
	// <![CDATA[
		//如果你需要在没有硬编码的window标识符下访问全局对象,你可以在任何层级的函数作用域中做如下操作:
		var global = (function () {
			return this;
		})();
		function show(str) {
			$("#div").append($("<p></p>").text("" + str));
		}

		//在 ECMAScript 中,所有对象并非同等创建的。
		//一般来说,可以创建并使用的对象有三种:本地对象、内置对象和宿主对象。
		//ECMA-262 把本地对象(native object)定义为“独立于宿主环境的 ECMAScript 实现提供的对象”。
		//•Object
		//•Function
		//•Array
		//•String
		//•Boolean
		//•Number
		//•Date
		//•RegExp
		//•Error
		//•EvalError
		//•RangeError
		//•ReferenceError
		//•SyntaxError
		//•TypeError
		//•URIError
		//ECMA-262 把内置对象(built-in object)定义为“由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现”。
		//这意味着开发者不必明确实例化内置对象,它已被实例化了。ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。
		//所有非本地对象都是宿主对象(host object),即由 ECMAScript 实现的宿主环境提供的对象。
		//所有 BOM 和 DOM 对象都是宿主对象。
		

		//ECMAScript是一种面向对象语言,支持基于原型的委托式继承。
		
		//多态
		//一个函数可以应用于不同的对象,就像原生对象的特性(因为这个值在进入执行上下文时确定的):
		function test() {
			show([this.a, this.b]);
		}
		test.call({a: 10, b: 20}); 			// 10, 20
		test.call({a: 100, b: 200});		// 100, 200
		
		//封装
		//在JavaScript里通过在变量前加下划线来达到“private”和“protected”数据的目的(但这只是命名规范)。
		//通过函数的静态作用域链特性来持有局部变量,以实现封装
		function ObjectA() {
			// "private" a
			var _a; 
			this.getA = function _getA() {
		    	return _a;
		  	};
			this.setA = function _setA(a) {
		    	_a = a;
		  	};
		}
		var obj1 = new ObjectA();
		obj1.setA(10);
		show(obj1._a); 		// undefined
		show(obj1.getA()); 	// 10
		
		var obj2 = new ObjectA();
		obj2.setA(20);
		show(obj1.getA());	//10
		show(obj2.getA());	//20
		
		//多重继承
		// helper for augmentation
		Object.extend = function (destination, source) {
			for (property in source)
		  		if (source.hasOwnProperty(property))
		    		destination[property] = source[property];
			return destination;
		};
		
		var X = {a: 10, b: 20};
		var Y = {c: 30, d: 40};
		Object.extend(X, Y); 				// mix Y into X
		show([X.a, X.b, X.c, X.d]); 		//10, 20, 30, 40
		
		//数据类型
		//标准规范里定义了9种数据类型,但只有6种是在ECMAScript程序里可以直接访问的,它们是:Undefined、Null、Boolean、String、Number、Object。
		//另外3种类型只能在实现级别访问(ECMAScript对象是不能使用这些类型的)并用于规范来解释一些操作行为、保存中间值。
		//这3种类型是:Reference、List和Completion。
		//Reference是用来解释delete、typeof、this这样的操作符,并且包含一个基对象和一个属性名称。
		//List描述的是参数列表的行为(在new表达式和函数调用的时候)。
		//Completion是用来解释行为break、continue、return和throw语句的。
		
		//ES5规范规定,静态对象不能扩展新的属性,并且它的属性页不能删除或者修改。他们是所谓的冻结对象,可以通过应用Object.freeze(o)方法得到。
		var foo = {x: 10};
		// 冻结对象
		Object.freeze(foo);
		show(Object.isFrozen(foo)); // true
		// 不能修改
		foo.x = 100;
		// 不能扩展
		foo.y = 200;
		// 不能删除
		delete foo.x;
		show([foo.x, foo.y]); 		//[10, undefined]
		
		//在ES5规范里,也使用Object.preventExtensions(o)方法防止扩展,或者使用Object.defineProperty(o)方法来定义属性:
		var bar = {x : 10};
		Object.defineProperty(bar, "y", {
			value: 20,
			writable: false, // 只读
			configurable: false // 不可配置
		});
		// 不能修改
		bar.y = 200;
		// 不能删除
		delete bar.y; // false
		// 防止扩展
		Object.preventExtensions(bar);
		show(Object.isExtensible(bar)); // false
		// 不能添加新属性
		bar.z = 30;
		show([bar.x, bar.y]); 	//{x: 10, y: 20}
		show(bar.z);			//undefined
		
		//属性的特性
		//所有的属性(property) 都可以有很多特性(attributes)。
		//1.{ReadOnly}——忽略向属性赋值的写操作尝,但只读属性可以由宿主环境行为改变——也就是说不是“恒定值” ;
		//2.{DontEnum}——属性不能被for..in循环枚举
		//3.{DontDelete}——delete操作符的行为被忽略(即删不掉);
		//4.{Internal}——内部属性,没有名字(仅在实现层面使用),ECMAScript里无法访问这样的属性。
		//注意,在ES5里{ReadOnly},{DontEnum}和{DontDelete}被重新命名为[[Writable]],[[Enumerable]]和[[Configurable]],
		//可以手工通过Object.defineProperty或类似的方法来管理这些属性。
		var fooAttr = {};
		Object.defineProperty(fooAttr, "x", {
			value: 10,
			writable: true, 		// 即{ReadOnly} = false
			enumerable: false, 		// 即{DontEnum} = true
		  	configurable: true 		// 即{DontDelete} = false
		});
		// 通过descriptor获取特性集attributes
		var desc = Object.getOwnPropertyDescriptor(fooAttr, "x");
		show([desc.enumerable, desc.writable]); 		// [false, true]
		
		//对象转换valueOf
		//将对象转化成原始值可以用valueOf方法,如果不用new关键字就是将对象转化成原始值,就相当于隐式的valueOf方法调用:
		var aaa = new Number(1);
		var primitiveA = Number(aaa); 			// 隐式"valueOf"调用
		var alsoPrimitiveA = aaa.valueOf(); 	// 显式调用
		show([
			typeof aaa, 					// "object"
			typeof primitiveA, 				// "number"
			typeof alsoPrimitiveA 			// "number"
		]);
		//valueOf的默认值会根据对象的类型改变(如果不被覆盖的话)
		var bbb = new Number(1);
		var ccc = new Number(2);
		show(bbb + ccc); 	// 3
		// 甚至
		var ddd = {
			x: 10,
			y: 20,
			valueOf: function () {
				return this.x + this.y;
		 	}
		};
		var eee = {
			x: 30,
			y: 40,
		  	// 和ccc的valueOf功能一样
		  	valueOf: ddd.valueOf
		};
		show(ddd + eee); 	// 100
		
		//构造函数是一个函数,用来创建并初始化新创建的对象。
		//对象创建(内存分配)是由构造函数的内部方法[[Construct]]负责的。该内部方法的行为是定义好的,所有的构造函数都是使用该方法来为新对象分配内存的。
		//而初始化是通过新建对象上调用该函数来管理的,这是由构造函数的内部方法[[Call]]来负责任的。
		//内部方法[[Construct]]是通过使用带new运算符的构造函数来激活的。
		
		//instanceof操作符的特性
		//我们是通过构造函数的prototype属性来显式引用原型的,这和instanceof操作符有关。该操作符是和原型链一起工作的,而不是构造函数。
		//所有instanceof运算符只需要一个对象属性——obj.[[Prototype]],在原型链中从Object.prototype开始检查其是否存在。
		//instanceof运算符是通过构造函数里的内部方法[[HasInstance]]来激活的。
		function ClassB() { }
		function ClassC() { }
		var objb = new ClassB();
		var __proto = {};
		ClassC.prototype = __proto;
		objb.__proto__ = __proto;
		show([objb instanceof ClassC, objb instanceof ClassB]); 	// true,false
		
		//下面的模板可以封装成一个非常方便的工具函数,其目的是连接原型的时候不是根据构造函数的实际名称。
		function inherit(child, parent) {
			var F = function () {};
			F.prototype = parent.prototype;
			child.prototype = new F();
			child.prototype.constructor = child;
			child.superproto = parent.prototype;
			return child;
		}
		//把中间的构造函数放到外面,就可以优化前面的代码(因此,只有一个函数被创建),然后重用它:
		var inherit = (function(){
			function F() {}
			return function (child, parent) {
		    	F.prototype = parent.prototype;
		    	child.prototype = new F;
		    	child.prototype.constructor = child;
		   		child.superproto = parent.prototype;
		   		return child;
			};
		})();
		//ES5为原型链标准化了这个工具函数,那就是Object.create方法。
		Object.create = Object.create || function (parent, properties) {
			function F() {}
			F.prototype = parent;
			var child = new F;
			for (var k in properties) {
				child[k] = properties[k].value;
			}
			return child;
		};
		
		// 用法
		var foocreate = {x: 10};
		var barcreate = Object.create(foocreate, {y: {value: 20}});
		show([barcreate.x, barcreate.y]); // 10, 20

	// ]]>
	</script>
  </body>
</html>

猜你喜欢

转载自jaesonchen.iteye.com/blog/2287480
今日推荐