- 浏览: 178226 次
- 性别:
- 来自: 西安
文章分类
- 全部博客 (163)
- POI (8)
- Collection容器 (1)
- java.util (2)
- java调用批处理 (1)
- xml (1)
- jfreechart (3)
- SVN (1)
- tomcat中文 (1)
- jquery (6)
- Log4j (1)
- ppt (1)
- js (48)
- ss (1)
- 综合 (1)
- Spring (2)
- 数据库 (6)
- tomcat (1)
- commons-lang包使用 (1)
- AJAX【Jquery】 (3)
- RMI (2)
- OpenLayers (25)
- html (20)
- css (25)
- Google地图 (2)
- java (1)
- Ibatis (1)
- GoogleMaps (1)
- J2EE (2)
- 软件设计 (1)
- 服务器 (1)
- html5 (4)
- cursor (1)
- AngularJs (5)
- 缓存 (1)
- 构建 (2)
- 域名、空间、服务器 (1)
http://www.cnblogs.com/Uncle-Keith/p/5814578.html
http://www.cnblogs.com/Uncle-Keith/p/5776159.html
这次的分享,主要还是想跟大家聊聊Javascript语言中很重要的概念之一,对象。为什么说之一呢?因为Javascript其他重要概念还包括:作用域 作用域链 继承 闭包 函数 继承 数组 ...... 有机会会跟大家分享这些概念的。
以下的介绍会分为如下:
1:前言
2:概述
2.1:对象创建
2.2:对象键名与键值
2.3:对象属性
2.4:对象引用
3:对象属性
3.1:读取属性
3.2:属性赋值
3.3:查看所有属性
3.4:删除属性
3.5:遍历属性
1:前言
Javascript拥有七种数据类型,其中分为两类。原始数据和复杂数据类型。原始数据类型:包括 字符串,数组,数字,布尔值,Null,Undefined。复杂数据类型:包括 对象。
对象是Javascript的核心概念,也是最重要的数据类型。Javascript所有数据都可以视为对象。都可以使用内置的方法。但是除了两个例外,就是Null和Undefined。
代码如下:
1 [1,2,3].toString() // "1,2,3"
2 "ha".toString() // "ha"
3 false.toString() // 'false'
一个对象就是一系列属性的集合,一个属性包含一个名字和一个值。一个属性也可以是函数,这种情况下这个属性被称为方法,可以拿汽车来做一个形象化的对比。
汽车是一个对象,拥有属性颜色,重量,车型,方法便是可以开上马路了。
写在代码中,就是:
复制代码
1 var car = {
2 "color": "red",
3 "weight": "1.4吨",
4 "module": "SUV"
5 "use": function() {
6 return "drive";
7 }
8 };
复制代码
2:概述
2.1:对象创建
1 var o = {
2 "p": "Hello World",
3 "name": "Keith Chou"
4 };
上面的代码中,大括号就定义了一个对象,它被赋值给全局变量o。这个对象(对象的名字随便定义)内部包含一个键值对,p是键名,字符串Hello World是键值。键名和键值用":"分离,不同键值对之前通过","分离,最后一个键值可不用逗号。但是我建议最后都不要加上。右花括号" } "后边要加上分号";"。
对象创建有三种方法:
1 var o1 = {};
2 var o2 = new Object();
3 var o3 = Object.crete(null);
上面三行语句都是等价的。第一种使用花括号来创建一个对象,这是最简便的方法。第二种采用构造函数的写法清晰的表明了意图。第三种写法多用于对象继承的场合。
2.2 键名与键值
复制代码
1 var o = {
2 "say": "Hello World",
3 "name": "Keith Chou",
4 "height": "180",
5 "age": 21
6 };
复制代码
以上用第一种方法创建对象,并赋值给全局变量o。键名即如下值:"say","name","height","weight"。键值即如下值:"Hello World","Keith Chou" ...
对象的所有键名都是字符串,加不加双引号都可以。对象的键值如果是英文,则必须加引号,否则会当成变量处理。如果是数字,加了引号则当成字符串处理,不加引号当成数字类型处理。
复制代码
1 var o = {
2 o1: 180,
3 o2: "180"
4 };
5 o.o1 // 180,数字类型
6 o.o2 // "180" ,字符串类型
复制代码
注意,Javascript的保留字可以不加引号当作键名。
复制代码
1 var o = {
2 for: 1,
3 class: 2
4 };
5
6 o.for //1
7 o.class //2
复制代码
2.3 对象属性
对象的每一个“键名”又称为“属性”(property),它的“键值”又称为属性值,可以是任何数据类型。如果一个属性值为函数,通常把这个属性称为“方法”,它可以像函数那样调用。
复制代码
1 var o = {
2 p: function(x) {
3 return 2 * x;
4 }
5 };
6 o.p(2) //4
复制代码
上面对象申明了一个方法p,它就是一个函数。这里简单说一下,函数声明的三个步骤:function,函数名,函数参数,函数体。其中函数名和函数参数都是可选的,即也可以不使用。不使用的情况下称为匿名函数。
属性可以动态创建,不必在对象声明的时候就指定。
1 var obj = {};
2 obj.keith = 123;
3 obj.rascal = false;
4 obj.keith; // 123
因为对象的方法就是函数,所以也有name属性。
复制代码
1 var obj = {
2 m1: function f() {},
3 m2: function() {}
4 };
5 obj.m1.name // "f"
6 obj.m2.name // " " , 空字符串
复制代码
2.4 对象引用
对于复杂数据类型,如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。也就是 传址传递。
复制代码
var o1 = { a : 1};
var o2 = o1;
o1.a; // 1
o2.a; // 1
o2.a = 11;
o1.a // 11
复制代码
上面o1和o2都指向了同一个对象,当o2修改了o1的属性a时,访问o1的属性a变成11。复杂数据类型的传址传递的特点就是当修改其中一个变量,会影响到其他对象对该变量的访问。
此时,如果取消某一个变量对于原对象的引用,不会影响到另一个变量。
1 var o1 = {};
2 var o2 = o1;
3 var o1 = 1;
4 o2 // { }
上面代码中,o1和o2指向同一个对象,然后o1的值变为1,这时不会对o2产生影响,o2还是指向原来的那个对象。
但是,对于原始数据类型的值,则是传值传递。传值传递的特点就是修改其中一个变量,不会影响到其他变量。也就是只是对该变量copy一份而已。
1 var x = 1;
2 var y = x;
3 x = 2;
4 y; // 1
上面的代码中,全局变量x发生变化,y的值并不变。也就是上面所说的copy了x的值,没有指向同一个内存地址。
3 :对象属性
3.1:读取属性
1 var o = {
2 name: "Keith Chou",
3 born: "1995"
4 };
访问属性有两种方法。
1 o.name // "Keith Chou"
2 o["name"] // "Keith Chou"
第二种方法访问属性的时候必须加上引号,单引号双引号都可以。
3.2:属性的赋值
点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。
1 var o = {};
2 o.p = "abc";
3 o["p"] = "abc";
3.3:查看所有属性
查看一个对象本身的所有属性,可以使用Object.keys 方法。
复制代码
1 var o = {
2 "say": "Hello World",
3 "name": "Keith Chou",
4 "height": "180",
5 "weight": "120"
6 };
7 Object.keys(o);
8 // ["say","name","height","weight"]
复制代码
可以看出,js返回一个数组对象。
3.4:删除属性
Javascript使用delete来删除属性。delete操作符只能用来删除对象本身的属性,而不能用于删除继承自原型的属性。
复制代码
1 var o = { p: 1 };
2 Object.keys(o);
3 // ["p"]
4 delete o.p;
5 o.p;
6 // undefined;
7 Object.keys(o);
8 // [ ]
复制代码
delete删除了o对象的p属性。删除后,再次访问属性就会返回undefined。而且使用Object.keys访问对象属性时,o对象也不再包括任何属性。
toString()方法是对象o继承自原型Object.prototype的一个方法,虽然delete命令返回true,但该属性并没有被删除。
1 var o = {};
2 delete o.toString(); // true
3 o.toString();
注意,delele也可以用于删除一个不存在的属性,不过也不会报错,会返回true。不过这个看起来好像没有什么用处阿。
1 var o = {};
2 delete o.p // true
最后,delete操作符也不能用于删除var命令声明的变量,只能用来删除对象本身的属性。
1 var o = 1;
2 delete o; // false
3 delete window.o // false
上面代码中,o是在全局作用域下声明的一个全局变量,全局变量默认是window对象的属性,默认情况下delete不得删除。
3.5:遍历属性
for...in循环用来遍历一个对象的所有属性。
复制代码
1 var o = {
2 a: 1,
3 b: 2,
4 c: 3
5 };
6 for (var i in o) {
7 console.log(i);
8 } // a , b , c
复制代码
上面代码中,定义了一个对象o,使用for..in循环来在控制台输出o对象中的每一个属性。 var i in o 是指 声明一个变量i,用于遍历o对象中的所有属性。
for...in循环有两个使用注意点:
它遍历的是所有对象可遍历的属性,会跳过不可遍历的属性。
它不仅会遍历对象自身的属性,还会遍历继承的属性。
不管学习什么知识,习惯于把自己所学习的知识列成一个list,会有助于我们理清思路,是一个很好的学习方法。强烈推荐。
以下篇幅有点长,希望读者耐心阅读。
以下内容会分为如下部分:
1.涵义
1.1:this涵义
1.2:this指向的可变性
2.使用场合
2.1:全局环境
2.2:构造函数
2.3:对象的方法
3.使用注意点
3.1:避免多层嵌套this
3.2:避免数组处理方法中的this
3.3:避免回调函数中的this
1.涵义
1.1:this涵义
在我写的一篇关于 构造函数与new关键字 的关系的博文中谈及,new关键字总是会返回一个对象。这个对象可以是new调用构造函数时返回的空对象,也可以是在构造函数中使用return语句返回的复杂数据类型(包括对象,数组等)。
同样,与new关键字相同,this关键字总是返回一个对象。再说的详细一些,就是属性或方法“当前”所在的对象。
复制代码
1 var Keith = {
2 firstName: 'Chou',
3 describe: function() {
4 return this.firstName;
5 }
6 };
7
8 console.log(Keith.describe()); //'Chou'
复制代码
上面代码中,this.firstName表示describe方法当前所在对象的firstName属性。也就是说,在全局作用域下调用describe方法时,describe方法所在的当前对象是Keith,所以就是调用Keith.firstName。
1.2:this指向的可变性
由于对象的属性可以赋给另外一个对象,所以属性所在的当前对象是可变的。也就是说,this的指向是可变的。
按 Ctrl+C 复制代码
var Keith = {
firstName: 'Chou',
describe: function() {
return this.firstName;
}
};
var Rascal={
firstName: 'King'
}
Rascal.describe=Keith.describe;
console.log(Rascal.describe()); //'King'
按 Ctrl+C 复制代码
上面代码中,Keith对象中的describe属性赋给Rascal,于是describe方法中当前所在的对象就是Rascal,所以this.firstName就指向Rascal。因为是传址传递,所以修改firstName会对原对象有影响。如有疑问,请移步 这篇文章 。这个例子可能不便于理解,再看看下面这个例子。
复制代码
1 function f(){
2 return this.firstName;
3 }
4
5 var Keith = {
6 firstName: 'Chou',
7 describe:f
8 };
9
10 var Rascal={
11 firstName: 'King',
12 describe:f
13 }
14
15 console.log(Keith.describe()); //'Chou'
16 console.log(Rascal.describe()); //'King'
复制代码
上面代码中,把方法移到全局作用域下,函数f内部使用了this关键字。随着f所在的对象不同,this指向也就不同。
在全局作用域下this关键字会指向顶层对象(也就是window对象)。
复制代码
1 var name='keith';
2 function person(){
3 var name='rascal';
4 return this.name;
5 }
6
7 console.log(person()); //'keith'
复制代码
上面代码中,返回的是keith而不是rascal。原因在于this指向的是全局作用域。在全局作用域中定义一个函数,默认是指向window对象,而不是函数本身。但是,如果在函数内部不使用var来声明一个局部变量,那结果也会不同。
复制代码
1 var name='keith';
2 function person(){
3 name='rascal';
4 return this.name;
5 }
6
7 console.log(person()); //'rascal'
复制代码
上面代码中,在函数内部没有使用var来声明一个局部变量,那么此时函数内部的name属性不是局部变量,而是全局变量。所以会覆盖掉前面的name属性。如果对于局部变量和全局变量不了解,可以访问 这篇文章 。
只要函数被赋给另外一个变量,this的指向会发生改变。
复制代码
1 var Keith={
2 name:'keith',
3 describe:function(){
4 return this.name;
5 }
6 }
7
8 var name='rascal';
9 var f=Keith.describe;
10 console.log(f()) //'rascal'
复制代码
上面代码中,返回的是rascal,而不是keith。因为Keith.describe被赋值给了f变量,而全局作用域下有一个name变量,所以Keith内部的函数的this指向就会指向f运行时所在的对象(顶层对象,也就是window对象)
总结一下:
1.javascript语言中,一切皆为对象(除了 undefined 和 null 之外),运行环境也是对象,所以函数都是在某个对象之中运行,this就是这个对象(环境)。
2.this的指向是动态的。如果函数在全局作用域中,那么this就会指向全局环境;如果函数位于某个对象中,那么this就会指向该对象。
2.使用场合
this的使用场合可以分为以下几个场合。
2.1:全局环境(全局作用域)
在全局作用域中使用this对象,它指向的就是顶层对象,也就是window对象。
1 function keith() {
2 return (this === window)
3 }
4
5 console.log(keith()) //true
上面代码中,不管是不是在函数内部,只要在全局作用域下运行,this就是指向顶层对象window。
2.2:构造函数
构造函数中的this,指向的是将要创建的对象实例。
复制代码
1 function Keith() {
2 this.sex = 'boy';
3 }
4
5 var person = new Keith();
6 console.log(person.sex); //'boy'
复制代码
上面代码中,在全局作用域下定义了Keith构造函数,然后调用构造函数并赋值给person对象实例。
构造函数创建的三个基本要求:函数名首字母大写;构造函数内部使用this关键字来指向即将生成的对象实例;使用new关键字来调用构造函数并返回对象实例。
如果想更进一步深入了解构造函数与new关键字的关系,请移步至 这篇文章 。
2.3:对象的方法
当A对象的方法被赋予B对象,该方法中的this就从指向A对象变成指向B对象。所以要特别小心,将某个对象的方法赋值个另外一个对象时,会改变this的指向。
复制代码
1 var keith = {
2 sex: 'boy',
3 foo: function() {
4 return this.sex;
5 }
6 };
7 var rascal = {
8 sex: 'girl'
9 };
10 rascal.foo = keith.foo;
11 console.log(keith.foo()); //'boy'
12 console.log(rascal.foo()); //'girl'
复制代码
上面代码中,把keith的foo函数赋值给了rascal,那么this的指向就从keith变成了rascal。这里涉及对象引用的知识,如有疑问,请移步至 这篇文章 。
如果某个方法位于多层对象的内部,这时为了简化书写,把该方法赋值给一个变量,往往会得到不一样的结果。
复制代码
1 var a = {
2 b: {
3 p: 'keith',
4 c: function() {
5 return this.p;
6 }
7 }
8 };
9
10 var person = a.b.c;
11 console.log(person()); //undefined
复制代码
上面代码中,c是两层对象里面的一个方法。为求简便,将其赋值给全局变量person,结果调用时,this指向了顶层对象window。而在window中变量p默认值为undefined。
要解决这个问题,可以只将c所在的对象赋值给person变量,或者是直接调用。
1 var person = a.b;
2 console.log(person.c()); //'keith'
3 console.log(a.b.c()); //'keith'
3.使用注意点
3.1:避免多层嵌套this
当在闭包中使用多层this,则this都会指向window。
复制代码
1 function keith() {
2 console.log(this);
3 return function() {
4 return this;
5 }
6 }
7 keith(); //window
8 keith()(); //window
复制代码
上面代码中,在一个函数中返回另外一个匿名函数是闭包的特点之一,可以看出,当在闭包中使用this对象都会指向全局作用域中的window对象。
如果在函数外包含一个对象,则内部this指向全局作用域,而外部this对象指向当前作用域。
复制代码
1 var o = {
2 f1: function() {
3 console.log(this);
4 (function() {
5 console.log(this)
6 })();
7 }
8 };
9
10 o.f1(); //Object , Window
复制代码
上面代码包含两层this,结果运行后,第一层指向当前对象,第二层指向全局对象。
实际执行的是如下代码。
复制代码
1 function keith() {
2 console.log(this);
3 }
4 var o = {
5 f1: function() {
6 console.log(this);
7 var f2 = keith();
8 }
9 };
10
11 o.f1(); //Object , Window
复制代码
要实现多层this嵌套,有两种解决方法:
一是在第二层中改用一个指向外层this的变量。
复制代码
1 var o = {
2 f1: function() {
3 console.log(this);
4 var that = this;
5 (function() {
6 console.log(that);
7 })();
8 }
9 };
10
11 o.f1(); //Object , Object
复制代码
上面代码中,定义了局部变量that,固定指向了外层的this,然后在内层中使用that,就不会发生this指向的改变。但是如果函数外部内有嵌套一个对象,this还是会指向全局。
二是Javascript中的严格模式。在严格模式下,如果内部函数的this指向了window对象,就会报错。
复制代码
1 var a = {
2 count: 0,
3 fun: function() {
4 'use strict';
5 return this.count++;
6 }
7 }
8
9 var f = a.fun;
10 console.log(f()) //'TypeError: this is undefined'
复制代码
上面代码中,fun方法使用严格模式声明。把a对象中的fun方法赋值给全局变量f,那么this此时指向window对象,在严格模式下,就会报错。如果函数外部没有嵌套一个对象,那么不会报错,而是会返回undefined。
3.2:避免数组处理方法中的this
数组的map和foreach方法,允许提供一个函数作为参数。这个函数内部不应该使用this。
复制代码
1 var keith = {
2 a: 'Hello',
3 b: ['b1', 'b2'],
4 c: function() {
5 this.b.forEach(function(item) {
6 console.log(this.a + ' ' + item);
7 })
8 }
9 };
10 keith.c();
11 //undefined b1
12 //undefined b2
复制代码
上面代码中,forEach方法的回调函数中的this,其实指向的是window对象,因此取不到keith.a的值,同上也属于避免多层嵌套this。也就是说,内层的this不指向外部函数,而是指向顶层对象。
要解决这个方法,可以使用that变量来代替回调函数中的this。
复制代码
1 var keith = {
2 a: 'Hello',
3 b: ['b1', 'b2'],
4 c: function() {
5 var that = this;
6 this.b.forEach(function(item) {
7 console.log(that.a + ' ' + item);
8 })
9 }
10 };
11 keith.c();
12 //Hello b1
13 //Hello b2
复制代码
另外一种方法,就是让this做为forEach方法的第二个参数,来固定它的运行环境。
复制代码
1 var keith = {
2 a: 'Hello',
3 b: ['b1', 'b2'],
4 c: function() {
5 this.b.forEach(function(item) {
6 console.log(this.a + ' ' + item);
7 }, this)
8 }
9 };
10 keith.c();
11 //Hello b1
12 //Hello b2
复制代码
3.3:避免回调函数中的this
回调函数中的this往往会改变指向。
复制代码
1 var o = {
2 f: function() {
3 console.log(this === o);
4 }
5 };
6
7 o.f(); // true;
复制代码
上面代码中,调用o对象的f方法,返回true。
但是,如果将f方法指定给某个按钮的click事件,this的指向就变了。
1 $('button').on('click',o.f);
上面代码中,使用了jquery方法来获取button元素,并绑定click事件。点击按钮后控制台会显示false。原因是此时this不再指向o对象了,而是指向按钮的DOM对象,因为f方法是在按钮对象的环境中被调用的。
总结一下:
a:如果想要多层嵌套this关键字,最常用的解决方法就是使用that变量,固定指向外层的this,然后在内层中使用that变量。就不会发生内层this指向全局的问题。
b:如果在回调函数中使用this关键字,注意this的指向问题。
http://www.cnblogs.com/Uncle-Keith/p/5776159.html
这次的分享,主要还是想跟大家聊聊Javascript语言中很重要的概念之一,对象。为什么说之一呢?因为Javascript其他重要概念还包括:作用域 作用域链 继承 闭包 函数 继承 数组 ...... 有机会会跟大家分享这些概念的。
以下的介绍会分为如下:
1:前言
2:概述
2.1:对象创建
2.2:对象键名与键值
2.3:对象属性
2.4:对象引用
3:对象属性
3.1:读取属性
3.2:属性赋值
3.3:查看所有属性
3.4:删除属性
3.5:遍历属性
1:前言
Javascript拥有七种数据类型,其中分为两类。原始数据和复杂数据类型。原始数据类型:包括 字符串,数组,数字,布尔值,Null,Undefined。复杂数据类型:包括 对象。
对象是Javascript的核心概念,也是最重要的数据类型。Javascript所有数据都可以视为对象。都可以使用内置的方法。但是除了两个例外,就是Null和Undefined。
代码如下:
1 [1,2,3].toString() // "1,2,3"
2 "ha".toString() // "ha"
3 false.toString() // 'false'
一个对象就是一系列属性的集合,一个属性包含一个名字和一个值。一个属性也可以是函数,这种情况下这个属性被称为方法,可以拿汽车来做一个形象化的对比。
汽车是一个对象,拥有属性颜色,重量,车型,方法便是可以开上马路了。
写在代码中,就是:
复制代码
1 var car = {
2 "color": "red",
3 "weight": "1.4吨",
4 "module": "SUV"
5 "use": function() {
6 return "drive";
7 }
8 };
复制代码
2:概述
2.1:对象创建
1 var o = {
2 "p": "Hello World",
3 "name": "Keith Chou"
4 };
上面的代码中,大括号就定义了一个对象,它被赋值给全局变量o。这个对象(对象的名字随便定义)内部包含一个键值对,p是键名,字符串Hello World是键值。键名和键值用":"分离,不同键值对之前通过","分离,最后一个键值可不用逗号。但是我建议最后都不要加上。右花括号" } "后边要加上分号";"。
对象创建有三种方法:
1 var o1 = {};
2 var o2 = new Object();
3 var o3 = Object.crete(null);
上面三行语句都是等价的。第一种使用花括号来创建一个对象,这是最简便的方法。第二种采用构造函数的写法清晰的表明了意图。第三种写法多用于对象继承的场合。
2.2 键名与键值
复制代码
1 var o = {
2 "say": "Hello World",
3 "name": "Keith Chou",
4 "height": "180",
5 "age": 21
6 };
复制代码
以上用第一种方法创建对象,并赋值给全局变量o。键名即如下值:"say","name","height","weight"。键值即如下值:"Hello World","Keith Chou" ...
对象的所有键名都是字符串,加不加双引号都可以。对象的键值如果是英文,则必须加引号,否则会当成变量处理。如果是数字,加了引号则当成字符串处理,不加引号当成数字类型处理。
复制代码
1 var o = {
2 o1: 180,
3 o2: "180"
4 };
5 o.o1 // 180,数字类型
6 o.o2 // "180" ,字符串类型
复制代码
注意,Javascript的保留字可以不加引号当作键名。
复制代码
1 var o = {
2 for: 1,
3 class: 2
4 };
5
6 o.for //1
7 o.class //2
复制代码
2.3 对象属性
对象的每一个“键名”又称为“属性”(property),它的“键值”又称为属性值,可以是任何数据类型。如果一个属性值为函数,通常把这个属性称为“方法”,它可以像函数那样调用。
复制代码
1 var o = {
2 p: function(x) {
3 return 2 * x;
4 }
5 };
6 o.p(2) //4
复制代码
上面对象申明了一个方法p,它就是一个函数。这里简单说一下,函数声明的三个步骤:function,函数名,函数参数,函数体。其中函数名和函数参数都是可选的,即也可以不使用。不使用的情况下称为匿名函数。
属性可以动态创建,不必在对象声明的时候就指定。
1 var obj = {};
2 obj.keith = 123;
3 obj.rascal = false;
4 obj.keith; // 123
因为对象的方法就是函数,所以也有name属性。
复制代码
1 var obj = {
2 m1: function f() {},
3 m2: function() {}
4 };
5 obj.m1.name // "f"
6 obj.m2.name // " " , 空字符串
复制代码
2.4 对象引用
对于复杂数据类型,如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。也就是 传址传递。
复制代码
var o1 = { a : 1};
var o2 = o1;
o1.a; // 1
o2.a; // 1
o2.a = 11;
o1.a // 11
复制代码
上面o1和o2都指向了同一个对象,当o2修改了o1的属性a时,访问o1的属性a变成11。复杂数据类型的传址传递的特点就是当修改其中一个变量,会影响到其他对象对该变量的访问。
此时,如果取消某一个变量对于原对象的引用,不会影响到另一个变量。
1 var o1 = {};
2 var o2 = o1;
3 var o1 = 1;
4 o2 // { }
上面代码中,o1和o2指向同一个对象,然后o1的值变为1,这时不会对o2产生影响,o2还是指向原来的那个对象。
但是,对于原始数据类型的值,则是传值传递。传值传递的特点就是修改其中一个变量,不会影响到其他变量。也就是只是对该变量copy一份而已。
1 var x = 1;
2 var y = x;
3 x = 2;
4 y; // 1
上面的代码中,全局变量x发生变化,y的值并不变。也就是上面所说的copy了x的值,没有指向同一个内存地址。
3 :对象属性
3.1:读取属性
1 var o = {
2 name: "Keith Chou",
3 born: "1995"
4 };
访问属性有两种方法。
1 o.name // "Keith Chou"
2 o["name"] // "Keith Chou"
第二种方法访问属性的时候必须加上引号,单引号双引号都可以。
3.2:属性的赋值
点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。
1 var o = {};
2 o.p = "abc";
3 o["p"] = "abc";
3.3:查看所有属性
查看一个对象本身的所有属性,可以使用Object.keys 方法。
复制代码
1 var o = {
2 "say": "Hello World",
3 "name": "Keith Chou",
4 "height": "180",
5 "weight": "120"
6 };
7 Object.keys(o);
8 // ["say","name","height","weight"]
复制代码
可以看出,js返回一个数组对象。
3.4:删除属性
Javascript使用delete来删除属性。delete操作符只能用来删除对象本身的属性,而不能用于删除继承自原型的属性。
复制代码
1 var o = { p: 1 };
2 Object.keys(o);
3 // ["p"]
4 delete o.p;
5 o.p;
6 // undefined;
7 Object.keys(o);
8 // [ ]
复制代码
delete删除了o对象的p属性。删除后,再次访问属性就会返回undefined。而且使用Object.keys访问对象属性时,o对象也不再包括任何属性。
toString()方法是对象o继承自原型Object.prototype的一个方法,虽然delete命令返回true,但该属性并没有被删除。
1 var o = {};
2 delete o.toString(); // true
3 o.toString();
注意,delele也可以用于删除一个不存在的属性,不过也不会报错,会返回true。不过这个看起来好像没有什么用处阿。
1 var o = {};
2 delete o.p // true
最后,delete操作符也不能用于删除var命令声明的变量,只能用来删除对象本身的属性。
1 var o = 1;
2 delete o; // false
3 delete window.o // false
上面代码中,o是在全局作用域下声明的一个全局变量,全局变量默认是window对象的属性,默认情况下delete不得删除。
3.5:遍历属性
for...in循环用来遍历一个对象的所有属性。
复制代码
1 var o = {
2 a: 1,
3 b: 2,
4 c: 3
5 };
6 for (var i in o) {
7 console.log(i);
8 } // a , b , c
复制代码
上面代码中,定义了一个对象o,使用for..in循环来在控制台输出o对象中的每一个属性。 var i in o 是指 声明一个变量i,用于遍历o对象中的所有属性。
for...in循环有两个使用注意点:
它遍历的是所有对象可遍历的属性,会跳过不可遍历的属性。
它不仅会遍历对象自身的属性,还会遍历继承的属性。
不管学习什么知识,习惯于把自己所学习的知识列成一个list,会有助于我们理清思路,是一个很好的学习方法。强烈推荐。
以下篇幅有点长,希望读者耐心阅读。
以下内容会分为如下部分:
1.涵义
1.1:this涵义
1.2:this指向的可变性
2.使用场合
2.1:全局环境
2.2:构造函数
2.3:对象的方法
3.使用注意点
3.1:避免多层嵌套this
3.2:避免数组处理方法中的this
3.3:避免回调函数中的this
1.涵义
1.1:this涵义
在我写的一篇关于 构造函数与new关键字 的关系的博文中谈及,new关键字总是会返回一个对象。这个对象可以是new调用构造函数时返回的空对象,也可以是在构造函数中使用return语句返回的复杂数据类型(包括对象,数组等)。
同样,与new关键字相同,this关键字总是返回一个对象。再说的详细一些,就是属性或方法“当前”所在的对象。
复制代码
1 var Keith = {
2 firstName: 'Chou',
3 describe: function() {
4 return this.firstName;
5 }
6 };
7
8 console.log(Keith.describe()); //'Chou'
复制代码
上面代码中,this.firstName表示describe方法当前所在对象的firstName属性。也就是说,在全局作用域下调用describe方法时,describe方法所在的当前对象是Keith,所以就是调用Keith.firstName。
1.2:this指向的可变性
由于对象的属性可以赋给另外一个对象,所以属性所在的当前对象是可变的。也就是说,this的指向是可变的。
按 Ctrl+C 复制代码
var Keith = {
firstName: 'Chou',
describe: function() {
return this.firstName;
}
};
var Rascal={
firstName: 'King'
}
Rascal.describe=Keith.describe;
console.log(Rascal.describe()); //'King'
按 Ctrl+C 复制代码
上面代码中,Keith对象中的describe属性赋给Rascal,于是describe方法中当前所在的对象就是Rascal,所以this.firstName就指向Rascal。因为是传址传递,所以修改firstName会对原对象有影响。如有疑问,请移步 这篇文章 。这个例子可能不便于理解,再看看下面这个例子。
复制代码
1 function f(){
2 return this.firstName;
3 }
4
5 var Keith = {
6 firstName: 'Chou',
7 describe:f
8 };
9
10 var Rascal={
11 firstName: 'King',
12 describe:f
13 }
14
15 console.log(Keith.describe()); //'Chou'
16 console.log(Rascal.describe()); //'King'
复制代码
上面代码中,把方法移到全局作用域下,函数f内部使用了this关键字。随着f所在的对象不同,this指向也就不同。
在全局作用域下this关键字会指向顶层对象(也就是window对象)。
复制代码
1 var name='keith';
2 function person(){
3 var name='rascal';
4 return this.name;
5 }
6
7 console.log(person()); //'keith'
复制代码
上面代码中,返回的是keith而不是rascal。原因在于this指向的是全局作用域。在全局作用域中定义一个函数,默认是指向window对象,而不是函数本身。但是,如果在函数内部不使用var来声明一个局部变量,那结果也会不同。
复制代码
1 var name='keith';
2 function person(){
3 name='rascal';
4 return this.name;
5 }
6
7 console.log(person()); //'rascal'
复制代码
上面代码中,在函数内部没有使用var来声明一个局部变量,那么此时函数内部的name属性不是局部变量,而是全局变量。所以会覆盖掉前面的name属性。如果对于局部变量和全局变量不了解,可以访问 这篇文章 。
只要函数被赋给另外一个变量,this的指向会发生改变。
复制代码
1 var Keith={
2 name:'keith',
3 describe:function(){
4 return this.name;
5 }
6 }
7
8 var name='rascal';
9 var f=Keith.describe;
10 console.log(f()) //'rascal'
复制代码
上面代码中,返回的是rascal,而不是keith。因为Keith.describe被赋值给了f变量,而全局作用域下有一个name变量,所以Keith内部的函数的this指向就会指向f运行时所在的对象(顶层对象,也就是window对象)
总结一下:
1.javascript语言中,一切皆为对象(除了 undefined 和 null 之外),运行环境也是对象,所以函数都是在某个对象之中运行,this就是这个对象(环境)。
2.this的指向是动态的。如果函数在全局作用域中,那么this就会指向全局环境;如果函数位于某个对象中,那么this就会指向该对象。
2.使用场合
this的使用场合可以分为以下几个场合。
2.1:全局环境(全局作用域)
在全局作用域中使用this对象,它指向的就是顶层对象,也就是window对象。
1 function keith() {
2 return (this === window)
3 }
4
5 console.log(keith()) //true
上面代码中,不管是不是在函数内部,只要在全局作用域下运行,this就是指向顶层对象window。
2.2:构造函数
构造函数中的this,指向的是将要创建的对象实例。
复制代码
1 function Keith() {
2 this.sex = 'boy';
3 }
4
5 var person = new Keith();
6 console.log(person.sex); //'boy'
复制代码
上面代码中,在全局作用域下定义了Keith构造函数,然后调用构造函数并赋值给person对象实例。
构造函数创建的三个基本要求:函数名首字母大写;构造函数内部使用this关键字来指向即将生成的对象实例;使用new关键字来调用构造函数并返回对象实例。
如果想更进一步深入了解构造函数与new关键字的关系,请移步至 这篇文章 。
2.3:对象的方法
当A对象的方法被赋予B对象,该方法中的this就从指向A对象变成指向B对象。所以要特别小心,将某个对象的方法赋值个另外一个对象时,会改变this的指向。
复制代码
1 var keith = {
2 sex: 'boy',
3 foo: function() {
4 return this.sex;
5 }
6 };
7 var rascal = {
8 sex: 'girl'
9 };
10 rascal.foo = keith.foo;
11 console.log(keith.foo()); //'boy'
12 console.log(rascal.foo()); //'girl'
复制代码
上面代码中,把keith的foo函数赋值给了rascal,那么this的指向就从keith变成了rascal。这里涉及对象引用的知识,如有疑问,请移步至 这篇文章 。
如果某个方法位于多层对象的内部,这时为了简化书写,把该方法赋值给一个变量,往往会得到不一样的结果。
复制代码
1 var a = {
2 b: {
3 p: 'keith',
4 c: function() {
5 return this.p;
6 }
7 }
8 };
9
10 var person = a.b.c;
11 console.log(person()); //undefined
复制代码
上面代码中,c是两层对象里面的一个方法。为求简便,将其赋值给全局变量person,结果调用时,this指向了顶层对象window。而在window中变量p默认值为undefined。
要解决这个问题,可以只将c所在的对象赋值给person变量,或者是直接调用。
1 var person = a.b;
2 console.log(person.c()); //'keith'
3 console.log(a.b.c()); //'keith'
3.使用注意点
3.1:避免多层嵌套this
当在闭包中使用多层this,则this都会指向window。
复制代码
1 function keith() {
2 console.log(this);
3 return function() {
4 return this;
5 }
6 }
7 keith(); //window
8 keith()(); //window
复制代码
上面代码中,在一个函数中返回另外一个匿名函数是闭包的特点之一,可以看出,当在闭包中使用this对象都会指向全局作用域中的window对象。
如果在函数外包含一个对象,则内部this指向全局作用域,而外部this对象指向当前作用域。
复制代码
1 var o = {
2 f1: function() {
3 console.log(this);
4 (function() {
5 console.log(this)
6 })();
7 }
8 };
9
10 o.f1(); //Object , Window
复制代码
上面代码包含两层this,结果运行后,第一层指向当前对象,第二层指向全局对象。
实际执行的是如下代码。
复制代码
1 function keith() {
2 console.log(this);
3 }
4 var o = {
5 f1: function() {
6 console.log(this);
7 var f2 = keith();
8 }
9 };
10
11 o.f1(); //Object , Window
复制代码
要实现多层this嵌套,有两种解决方法:
一是在第二层中改用一个指向外层this的变量。
复制代码
1 var o = {
2 f1: function() {
3 console.log(this);
4 var that = this;
5 (function() {
6 console.log(that);
7 })();
8 }
9 };
10
11 o.f1(); //Object , Object
复制代码
上面代码中,定义了局部变量that,固定指向了外层的this,然后在内层中使用that,就不会发生this指向的改变。但是如果函数外部内有嵌套一个对象,this还是会指向全局。
二是Javascript中的严格模式。在严格模式下,如果内部函数的this指向了window对象,就会报错。
复制代码
1 var a = {
2 count: 0,
3 fun: function() {
4 'use strict';
5 return this.count++;
6 }
7 }
8
9 var f = a.fun;
10 console.log(f()) //'TypeError: this is undefined'
复制代码
上面代码中,fun方法使用严格模式声明。把a对象中的fun方法赋值给全局变量f,那么this此时指向window对象,在严格模式下,就会报错。如果函数外部没有嵌套一个对象,那么不会报错,而是会返回undefined。
3.2:避免数组处理方法中的this
数组的map和foreach方法,允许提供一个函数作为参数。这个函数内部不应该使用this。
复制代码
1 var keith = {
2 a: 'Hello',
3 b: ['b1', 'b2'],
4 c: function() {
5 this.b.forEach(function(item) {
6 console.log(this.a + ' ' + item);
7 })
8 }
9 };
10 keith.c();
11 //undefined b1
12 //undefined b2
复制代码
上面代码中,forEach方法的回调函数中的this,其实指向的是window对象,因此取不到keith.a的值,同上也属于避免多层嵌套this。也就是说,内层的this不指向外部函数,而是指向顶层对象。
要解决这个方法,可以使用that变量来代替回调函数中的this。
复制代码
1 var keith = {
2 a: 'Hello',
3 b: ['b1', 'b2'],
4 c: function() {
5 var that = this;
6 this.b.forEach(function(item) {
7 console.log(that.a + ' ' + item);
8 })
9 }
10 };
11 keith.c();
12 //Hello b1
13 //Hello b2
复制代码
另外一种方法,就是让this做为forEach方法的第二个参数,来固定它的运行环境。
复制代码
1 var keith = {
2 a: 'Hello',
3 b: ['b1', 'b2'],
4 c: function() {
5 this.b.forEach(function(item) {
6 console.log(this.a + ' ' + item);
7 }, this)
8 }
9 };
10 keith.c();
11 //Hello b1
12 //Hello b2
复制代码
3.3:避免回调函数中的this
回调函数中的this往往会改变指向。
复制代码
1 var o = {
2 f: function() {
3 console.log(this === o);
4 }
5 };
6
7 o.f(); // true;
复制代码
上面代码中,调用o对象的f方法,返回true。
但是,如果将f方法指定给某个按钮的click事件,this的指向就变了。
1 $('button').on('click',o.f);
上面代码中,使用了jquery方法来获取button元素,并绑定click事件。点击按钮后控制台会显示false。原因是此时this不再指向o对象了,而是指向按钮的DOM对象,因为f方法是在按钮对象的环境中被调用的。
总结一下:
a:如果想要多层嵌套this关键字,最常用的解决方法就是使用that变量,固定指向外层的this,然后在内层中使用that变量。就不会发生内层this指向全局的问题。
b:如果在回调函数中使用this关键字,注意this的指向问题。
发表评论
-
自定义添加标签函数
2017-05-03 16:36 0<!DOCTYPE html> <ht ... -
快速获取js对象键和值
2017-03-17 00:20 756var o = { "say&quo ... -
javascript eval方法使用
2017-02-01 22:42 607JavaScript eval() 函数 JavaScri ... -
如何判断js文件是否加载完成
2016-12-02 00:41 741[size=medium][color=red][/colo ... -
console.log设置显示颜色
2016-12-02 00:06 1088console.log('%c 1','color:red') ... -
javascript的escape/unescape
2015-12-30 00:07 664javascript的escape/unescape 转移 ... -
JSON.parse()和JSON.stringify()
2015-12-30 00:04 562parse用于从一个字符串中解析出json对象,如 var ... -
百度右侧导航原理
2015-09-09 01:02 813<!DOCTYPE html PUBLIC &q ... -
javascript的prototype继承
2015-08-27 07:51 681goody9807写到 写道 http://www.cn ... -
深入理解javascript之arguments
2015-08-24 08:24 597写道 本文转自:http://blog.csdn.net ... -
js中数组(Array)的排序(sort)注意事项
2015-08-20 07:26 680var arrDemo = new Array(); ... -
js事件冒泡
2015-08-18 07:10 734<!doctype html> <ht ... -
js对象封装
2015-07-27 08:00 631<!doctype html> <htm ... -
html5之后全局js编辑
2015-07-26 18:02 694<script> window.documen ... -
自定义浏览器事件绑定函数
2015-06-26 08:25 386function bind(el, eventType, c ... -
仿jquery获取dom元素
2015-06-19 07:58 742function g(id) { if (id.subst ... -
自定义随机数
2015-04-29 00:08 710//随机生 ... -
js获取元素通用函数
2015-04-27 00:42 713/** * 通用函数. * 1、可以通过ID获取元素 ... -
原生js实现事件切换
2015-04-27 00:16 725function turn(elem) { var cls ... -
js实现div拖动
2015-02-02 22:41 474写道 http://blog.csdn.net/not ...
相关推荐
`Presentations-JavaScriptThis-源码.rar`或`.zip`文件很可能是关于这个主题的一份详细讲解材料,包含了一些示例代码和演示。 1. **`this`的基本概念**: `this`在JavaScript中用于引用当前执行上下文的对象,它的...
在JavaScript中,`this`关键字是一个非常重要的概念,它用于引用当前上下文中的对象。`this`的值在运行时确定,并且根据函数被调用的方式而改变。下面我们将深入探讨`this`的使用方法。 1. **全局作用域与浏览器...
JavaScript中this的指向还没搞明白?来这看看 你就懂啦~
为了正确地使用$(this)对象,我们需要了解JavaScript中this关键字的使用规则,并且正确地使用变量来存储当前函数的this对象。 五、结语 在JavaScript开发中,使用jQuery的$(this)对象需要遵守JavaScript中this...
在这个名为"Presentations-JavaScriptThis"的资料包中,很显然,我们将探讨"this"在JavaScript中的各种用法和应用场景。 首先,我们要明白"this"的基本概念。在JavaScript中,"this"引用的是函数调用时的执行上下文...
Study note on htis keyword in JavaScript
本文对Javascript this函数进行详细介绍,及知识的总结整理,彻底明白js this 函数该如何使用。 this 代码函数调用时, .1直接调用函数则为this则指向window对象 .2类调用时候指向这个类 .3 方法.apply(obg) ;...
这篇文章主要介绍了JavaScript This指向问题详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 各位小伙伴在面试中被面试官问道this指向问题一定不少吧,同时...
本文将详细介绍JavaScript中一种常见的事件处理用法——onclick(this)。 首先,我们需要理解什么是onclick事件处理器。在HTML中,onclick是一个事件属性,用于指定当元素被点击时将调用的JavaScript代码。这个属性...
this.Response.Write("<script language='javascript'>window.close();</script>"); ``` 这段代码的功能是关闭当前打开的窗口。通常用于用户完成某个操作后自动关闭当前窗口的情形。 #### 关闭父窗口 ```...
JavaScript中的`this`关键字是语言的核心特性之一,用于在函数执行上下文中引用当前对象。它在JavaScript中的行为可能与其他面向对象的语言(如Java或C++)中的`this`有所不同,因此理解其工作原理至关重要。 首先...
### JavaScript在PDF文档中的使用指南 #### 一、引言 随着互联网技术的发展与进步,PDF文档因其良好的兼容性及可移植性而被广泛应用。在众多功能中,JavaScript的集成使得PDF文档具备了动态交互能力,极大地提升了...
2.JavaScript this 3.JavaScript 闭包 4.JavaScript 事件 5.javascript 跨域 6.javascript 命名空间 Oject-Oriented 1.JavaScript Expressive 2. Interfaces 3.Introduction 4. Inheritance 5.AOP Jquery ...
2.JavaScript this 3.JavaScript 闭包 4.JavaScript 事件 5.javascript 跨域 6.javascript 命名空间 Oject-Oriented 1.JavaScript Expressive 2. Interfaces 3.Introduction 4. Inheritance 5.AOP Jquery ...
JavaScript this 关键字 面向对象语言中 this 表示当前对象的一个引用。 但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。 在方法中,this 表示该方法所属的对象。 如果单独使用,this ...
### 原生JavaScript实现加载更多效果 在现代Web开发中,“加载更多”是一种非常常见的交互方式,尤其是在数据量较大的情况下。本篇文章将基于提供的代码片段来深入解析如何使用原生JavaScript来实现“上拉加载更多...
JavaScript 中的 `this` 关键字是一个非常核心的概念,它的指向依赖于函数的调用方式,而非定义方式。理解 `this` 的指向对于编写可预测的 JavaScript 代码至关重要。 在全局作用域中,`this` 指向全局对象,对于...
JavaScript中的`this`关键字是一个非常重要的概念,它用于在函数执行时引用当前上下文的对象。在JavaScript中,`this`的绑定遵循四个主要规则:默认绑定、隐式绑定、显式绑定和new绑定。让我们逐一深入理解这些规则...
### 使用JavaScript编写的计算器知识点解析 #### 一、Array.prototype.remove方法实现 在该计算器代码中,`Array.prototype.remove` 方法被定义为一个数组原型的方法,用于移除数组中的某个指定索引位置的元素。 *...
本文将深入探讨JavaScript中`this`关键字的多种使用场景,并对比其他面向对象语言中的`this`。 首先,了解`this`在传统的面向对象编程语言中的用途。在C++、C#、Java等语言中,`this`关键字被用于指向当前对象的...