Javascript函数、构造函数、原型、类和对象

简介: 函数 函数是JavaScript中特殊的对象,对函数执行typeof运算会返回字符串"function",因为函数也是对象,他们可以拥有属性和方法。 静态方法 函数在JS中定义了类的名字,任何添加到函数的属性都是类字段和类方法(类比Java中类的static variable 和 static method),下面代码起到Java里面static method的效果: va

函数

函数是JavaScript中特殊的对象,对函数执行typeof运算会返回字符串"function",因为函数也是对象,他们可以拥有属性和方法。

静态方法

函数在JS中定义了类的名字,任何添加到函数的属性都是类字段和类方法(类比Java中类的static variable 和 static method),下面代码起到Java里面static method的效果:

		var foo = function(){};
		foo.printLog = function(){
			if (arguments.length != 0)
			{
				console.log(Array.prototype.join.call(arguments, " - "));
			}
		};
		foo.printLog("Test", "Static Method");

构造函数

如果函数或者方法的调用之前加上new关键字,他就构成了构造函数的调用.,

构造函数的调用和普通函数,方法的调用在实参处理,调用上下文和返回值方面有不同

(1).实参处理不同

凡是没有形参的构造函数调用都可以省略圆括号


(2)调用上下文的不同

调用构造函数创建一个新的空对象,这个对象继承自构造函数的prototype(原型).构造函数试图初始化这个新对象,并把这个新对象当做构造函数的调用上下文,所以在构造函数中this关键字可以用来引用这个新对象,也就能够在构造函数中初始化这个新对象

注意: 尽管构造函数看起来像一个方法调用,它依然会使用这个新对象作为调用上下文。也就是说,在表达式new o.m() 中,调用上下文并不是o.

例子1-2:

		function A()  
		{  
			this.a = 123; 
			this.init();
		}  
		A.prototype = {
			get: function(){console.log('The value of A is ' + this.a);},
			init: function(){
					console.log('do init here'); 
					this.a=567;
				 }
		}
		var obj = new A;
		obj.get();

(3)返回值不同

构造函数通常不使用return关键字调用完毕之后会返回一个对象(就是新创建的这个对象)


this关键字

this是一个关键字,不是变量也不是属性.

this关键字没有作用域的限制,他只有下面几种情况

(1)一个函数被当做方法调用,则函数中的this指向的是调用它的对象

(2)一个函数被当做函数调用,则函数中的this指向的全局对象(非严格模式)或者是undefined(严格模式下)

(3)函数被当做构造函数调用,this就指向构造函数创建的新对象

例子:

		var a = {name:'frank',age:30};//创建一个新对象  
		function A()  
		{  
			console.log(this);
		}  
		A.call(a); //对象a的方法调用:this代表对象a,因为通过call的调用上下文是a 
		A();//全局函数调用:this代表全局变量window
		new A();//构造函数调用: this代表新创建的对象A {}


函数原型,每一个函数都包含一个prototype属性,而且这个prototype包含唯一一个属性constructor指向构造函数对象,当将函数用做构造函数的时候,新创建的对象会从原型对象上继承属性,按照惯例,构造函数首字母要大写:

		function Foo(){};//Constructor

		Foo.prototype = {
			constructor:Foo;//因为重写了prototype,需要显示的将constructor定义在此
			userName:"Frank"};
		var fooInstance = new Foo();
		console.log(fooInstance.userName);//As an instance of Foo, it inherited all attributes from Foo's prototype
		console.log(Foo.userName);// 函数对象Foo并没有userName属性,所以是undefined,但是Foo的原型对象有,并且被fooIntance继承
		console.log(fooInstance.constructor === Foo);


注意:每个函数自身就是个对象,所以可以被赋值和像参数一样传递,但同时,它也可以被用作构造函数,用来创建其他对象。

构造函数的prototype是被所有实例共享的,例如:

<script type="text/javascript">
	function Person(){};
	Person.prototype = 
		{
			constructor : Person,
			name : "Frank",
			friends : ["Coco","Nancy"],
			sayName: function(){ alert(this.name);}
		};
	var p1 = new Person();
	var p2 = new Person();
	p1.friends.push("Van");
	console.log(p1.friends);
	console.log(p2.friends);
	p1.sayName();

</script>

因为p1和p2共享prototype对象,所以p1的friends改变会影响到p2,这显然不是我们想要的,我们希望每个Person实例有自己单独的属性,但同时,我们又希望对一些公共方法可以共享,以节省内存。

构造方法和原型组合模式

构造方法用于定义实例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,同时又共享着对方法的引用,最大限度地节省了内存。有点类似于继承,但区别是prototype是单例的。

修改后的写法:

<script type="text/javascript">
	function Person(name, friends){
		this.name = name;
		this.friends = friends;
	};
	Person.prototype = 
		{
			constructor : Person,
			sayName: function(){ console.log(this.name);}
		};
	var p1 = new Person("Frank",["coco","nancy"]);
	var p2 = new Person("Daniel",["coco","nancy"]);
	p1.friends.push("Van");
	console.log(p1.friends);
	console.log(p2.friends);
	p1.sayName();
	p2.sayName();
</script>


函数直接量(function literal),匿名函数 (anonymous function)

作为命名空间的函数

在函数中声明的变量在整个函数体内都是可见的,在函数的外部是不可见的(局部变量)。不在任何函数中声明的变量是全局变量,在整个JavaScript程序中都可见。

一种惯用法是用自调用匿名函数(self-invoking anonymous function) 来实现这个命名空间技术,其写法如下

function(){

//模块代码

  })();

因为默认情况下,JS是运行在全局的namespace下,而对全局变量的暴露是非常危险的,因为任何无意的修改和覆盖都会来带意想不到的错误。因此在JS开发中,尽量不要定义全局变量。在JS框架开发中此条法则体现的尤为明显,因为假如框架暴露过多的全局变量,一旦被用户修改,就可能导致框架不可用。

所以在JQuery中,整个框架通过 window.jQuery = window.$ = jQuery; 只向外部暴露了2个全局变量,即著名的$和JQuery

详细请见jQuery源码分析: http://nuysoft.iteye.com/blog/1177451

对象

JavaScript 中,除了数字、true、false、null和undefined之外,其他值都是对象,每个对象拥有三个相关的对象属性(object attribute)

  • 对象的原型(prototype)指向另一个对象,本对象的属性继承自它的原型对象。对象继承是通过原型链实现的
  • 对象的类(class)是一个标识对象类型的字符串
  • 对象的扩展标记(extensible flag)指明了是否可以向该对象添加新属性

对象继承


所有通过对象直接量(Object literals)创建的对象都具有同一个原型对象Object.prototype,对象的属性继承自原型对象,对象之所以会继承是因为属性的查询过程是,搜索对象的原型链,直到根原型,如果还没有找到标识为undefined。
		var o = {};// o 从 Object.prototype 继承对象属性
		o.x =1; // 定义新属性x
		var p = inherit(o);//p继承o和Object.prototype
		p.y = 2;
		var q = inherit(p);//q继承p、o和Object.prototype
		q.z =3 ;
		console.log(q.x + q.y);
		console.log(q.toString() + q.a);//toString继承自Object.prototype, q.a is undefined

		function inherit(parent){
			f = function (){};//定义一个空构造函数
			f.prototype = parent; //将其原型属性设置为p
			return new f();//使用f()创建p的继承对象
		};

上面代码对象在内存中的示意图:



对象工厂

工厂方法这个设计模式在JS中也是经常用到,下面以jQuery源码为例,看一下对象工厂的运用。

	<script language="javascript">
		console.log("Start");

		(function(window){//自调用函数
		   var //定义本地变量
			   core_version = "1.0.0",

			   jQuery = function(){//这是一个工厂方法,专门用来产生jQuery对象
					return new jQuery.fn.init();//下面的prototype赋值使得init函数和jQuery函数据有相同的prototype,即jQuery对象
				};
			
			jQuery.fn = jQuery.prototype = {
				jquery: core_version,
				constructor: jQuery,
				init: function(){
					return this;
				},
				debug: function(){console.log("debugging")}
			};
			
			// Give the init function the jQuery prototype for later instantiation
			jQuery.fn.init.prototype = jQuery.fn; 

			window.jQuery = window.$ = jQuery;//将本地变量jQuery设置为全局变量
		}(window));//传入全局变量window

		$().debug();//$()将返回一个通过工厂方法产生的对象。
		console.log("Current version is "+$().jquery);
	</script>




目录
相关文章
|
3天前
|
JavaScript 前端开发
在JavaScript中,函数原型(Function Prototype)是一个特殊的对象
JavaScript中的函数原型是一个特殊对象,它为所有函数实例提供共享的方法和属性。每个函数在创建时都有一个`prototype`属性,指向原型对象。利用原型,我们可以向所有实例添加方法和属性,实现继承。例如,我们定义一个`Person`函数,向其原型添加`greet`方法,然后创建实例`john`和`jane`,它们都能调用这个方法。尽管可以直接在原型上添加方法,但推荐在构造函数内部定义以封装数据和逻辑。
8 2
|
3天前
|
JavaScript 前端开发
JavaScript 提供了多种方法来操作 DOM(文档对象模型)
【5月更文挑战第11天】JavaScript 用于DOM操作的方法包括获取元素(getElementById, getElementsByClassName等)、修改内容(innerHTML, innerText, textContent)、改变属性、添加/删除元素(appendChild, removeChild)和调整样式。此外,addEventListener用于监听事件。注意要考虑兼容性和性能当使用这些技术。
6 2
|
5天前
|
前端开发 JavaScript 数据处理
在JavaScript中,异步函数是指什么
【5月更文挑战第9天】JavaScript中的异步函数用于处理非立即完成的操作,如定时器、网络请求等。它们可通过回调函数、Promise或async/await来实现。示例展示了如何使用async/await模拟网络请求:定义异步函数fetchData返回Promise,在另一异步函数processData中使用await等待结果并处理。当fetchData的Promise解析时,data变量接收结果并继续执行后续代码。注意,调用异步函数不会阻塞执行,而是会在适当时间点继续。
10 0
|
5天前
|
自然语言处理 JavaScript 前端开发
在JavaScript中,this关键字的行为可能会因函数的调用方式而异
【5月更文挑战第9天】JavaScript中的`this`关键字行为取决于函数调用方式。在非严格模式下,直接调用函数时`this`指全局对象,严格模式下为`undefined`。作为对象方法调用时,`this`指向该对象。用`new`调用构造函数时,`this`指向新实例。通过`call`、`apply`、`bind`可手动设置`this`值。在回调和事件处理中,`this`可能不直观,箭头函数和绑定方法可帮助管理`this`的行为。
10 1
|
5天前
|
JavaScript 前端开发 网络架构
JavaScript中的箭头函数是一种新的函数表达形式
【5月更文挑战第9天】JavaScript的箭头函数以简洁语法简化函数定义,其特性包括:1) 不绑定自身this,继承上下文的this,适合回调和事件处理;2) 没有arguments对象,需用剩余参数语法访问参数;3) 不能用作构造函数,无new调用;4) 没有prototype属性,不支持基于原型的继承。箭头函数在特定场景下优化了this处理,但使用时要注意与普通函数的差异。
8 2
|
6天前
|
存储 JavaScript 前端开发
JavaScript对象方法详解
JavaScript对象方法详解
15 1
|
7天前
|
JavaScript 前端开发
js的一些内置函数
js的一些内置函数
7 1
|
8月前
|
JavaScript 前端开发 Java
JavaScript 高级2 :构造函数和原型
JavaScript 高级2 :构造函数和原型
61 0
|
JavaScript 前端开发
🍉JavaScript进阶——构造函数和原型
🍉JavaScript进阶——构造函数和原型
81 7
🍉JavaScript进阶——构造函数和原型
|
JavaScript 前端开发
Javascript面向对象——创建对象、构造函数的原型
Javascript面向对象——创建对象、构造函数的原型