js总结

这些都是我积累的或者在树上看的。都是自己想的。可能不能保证100%正确

1.var与变量作用域 

关于var 我的理解就是在当前域声明了变量。 而变量访问 例如 x=3 这样的语法。 首先在当前域寻找x 找不到就到上层去找 一直找到为止。(如果 一直找不到 就在最顶层 创建 这就是俗话说的全局变量)。

var 是不分位置的。js在执行代码之前会先扫描var 根据位置 在各自的域分配空间(是不是当时就分配内存空间了 其实我是不知道的,但是这样理解更好 我觉得)。

        alert(x);
	alert('go on ')
	//var x;
观察上面的代码 第三行如果注释掉。 会因为 x没有定义 报错。代码也会停止运行。 如果 第三行打开注释。x就是声明的了。 虽然仍然是 undefined 但是 代码却会继续执行。

同时 var x=3 这样的语句 var  x的声明语句和 x=3的赋值语句并不是同时进行的。 例如上面的例子的 var x 改成var x=3;第一个alert并不会输出3. 仍然是 undefined。

首先 我认为 js里面不应该有全局变量这个概念。 任何变量都是某一个对象的属性。而 默认的最顶层的对象就是Global / window。在最顶层写 var x=3.这样的语句 其实 就是window.x=3(可以这么理解 但是 实际上还是有区别的,var 的变量是不可以 delete的 windwo.x是可以delete的 在这里之所以可以看做一样 是因为window只有一个。) 当然 也可以直接写 x=3(强烈不建议。会导致混乱)。我们在任何地方 写了 var x这样的语句  其实 就是给某个对象 添加了x这个属性。

注意 例如这样的代码var a = b = 0;  等价于 b=0; var a=b;如果是在对象内部这样处理的话 b会变成 window下面的属性。

域是没有块状代码这个概念的。在类似java这样的语言。 我们在 if的代码块中 是定义一个 int x,这个x是只能在这个代码快中生效的。但是js 没有这个概念。因为 代码它不是一个对象。

	var x=3;
	function test(){
		if(x==3){
			y=1;
		}else{
			var y;
		}
		alert(y);
	}
	test();
	alert(y);

myname = "global"; // 
function func() {
    alert(myname); // 
    var myname = "local";
    alert(myname); // 
}
func();

相信上面的第一个例子比较好的说明了这个问题。 首先 我们看看 x是等于3的 所以 if 走 else 不走。 那么 var y 就不执行了? 如果var y 不执行 那么这个 y就是 在window 下面的。 就会输出2次1. 可是结果却不是这样的。 y不会输出2次 只有test里面的会被执行。

解释下这段代码: 首先 js 会扫描代码 var 无论在哪里都会执行声明。 然后 var 是一定要挂靠在对象上面的。 在这个例子里面 var 就挂靠在了 test 这个方法上面。(这里的挂靠是我自己瞎想的词。我理解就是 在这个对象域里面 分配了空间 给 var 的变量。因为是跟对象挂靠的。 所以 每创建一个变量。都会有一个新的 变量 这也是 跟prototype 本质的区别 这点 我之后再总结


看第二个例子:第一个alert 是 undefined 这个是比较关键的。

2.函数的定义

在我理解中 在某一个地方 写上一个 function xxx(){}. 很多时候 跟 var 是一样的。 一个function 就是一个对象。 它也是需要像变量一样挂靠在某个对象上面。 它同样没有块的概念。 考虑下面代码
	test();
	if(false){
		function test(){
			alert('test1')
		}
	}else{
		//function test(){
			//alert('test2')
		//}
	}

因为false 所以 第一个不走。但是 test 仍然会执行。 但是需要注意的是 如果 else里面的代码打开 我的测试 会输出test2 并且如果条件给成 true 仍然是 第二个 test2 说明 他是 按顺序从上到下 先扫描的。后面的覆盖了前面的。
有的书上说 这种行为不确定 有的浏览器是第一个(firefox是第一个。。在firefox中 在检查函数声明的时候。就忽略了代码块中的) 有的是第二个!!!这里和变量是不同的。慎用 

函数 一定要不要写在代码块里面 即使有的书上说 命名函数表达式(var x=function test(){}) 不会受到影响 也不要这么做。你无法保证每个浏览器是否一致 。

关于 命名函数表达式 我们也需要知道 一点
var x=function test(){};
这样的语句  在外部 将访问不到 test 。而在内部 却可以访问。

3.parseInt以及类似的字符串以及数字之间的装换。

在js里面 其实我并不喜欢用类似的方法来装换字符串或数字。当然 如果你真的明白如何用。肯定是没有问题的。但是有一些人会对这些方法的参数不了解。只是用,出了bug 还莫名其妙。 比如简单的 “081”这个字符串转化成 数字。如果你想要的是81(我想绝大部分人想要的是81吧) 那么试试parseInt(“081”)? 结果很奇怪吧(貌似比较新的浏览器是没有这个问题的。) 其实原因很简单。 0开头的字符串当做了8进制处理 parseInt(“081”,10)这样就ok了。第二个参数是进制。当然这些细节掌握最好了 但是我更喜欢用其他的方法来处理。

字符串 转化成 数字  “081”-0; 没错 用减法 会自动转化数据;

数字转化成字符串  当然是 +“”这样的操作了。(另外 数字是有 toString 方法 参数也是进制的 可以转成对应进制的字符串,当然 要用变量来调用 不可以用字面量。)

4.this与new

按照javascript语言精粹中所说,如果在一个函数前面带上new来调用该函数,那么将创建一个隐藏连接到该函数的prototype成员的新对象,同时this将被绑定到那个新对象上。

到底什么意思?  

前半句 很好理解。 一个函数 无论 new 多少个 其实都共用一个 prototype。无论是函数 还是 变量 都只有一个。 一个改变都改变。有点java的静态变量的感觉。 需要注意的是 prototype 定义的东西 会被 this. 里面的东西屏蔽掉。比如说

一个 function test(){ this.x=4; test.prototype.x=5;} var t=new test(); alert(t.x); 就是4.

后半句 我保持怀疑态度。他说把this绑定到新对象 是什么意识?

什么叫绑定。 一个最基本的道理 如果是绑定的 那么一个修改 另外一个应该是会跟着变的。但是事实不是。 我理解是 拷贝。 而不是绑定。 拷贝了一个this 域的所有东西。

然后我们看一下 下面的代码

function x(a){
	var xx=4*a;
	x.xx=1*a;
	x.prototype.xx=2*a;
	this.xx=3*a;
}
//x.xx=1;
var x1=new x(1);
var x2=new x(10);

首先 我们要明白 这对代码 主要产生了3个对象  x ,x1,x2.  其中 x是一个比较特殊的对象 他是一个函数。他拥有一些 函数才有的特性。比如 可以用new 操作符来操作。



上面的图片是谷歌浏览器 看到的3个对象。一个个来解释。

图片表明 x 是一个函数对象。他的 原型(propotype)是 原型里面 有一个 构造函数 还有 一个xx变量。这个 就是我们 x.propotype.xx 来创建的。这个变量在内存中只有一个。 无论new多少 new x() 原型都是一个 就叫x 里面的东西也只有一份。直接var 的变量 和this.xx 却是 每new 一个 都会复制一份。 var 出来的变量。只有访问域的概念。 在这个里面完全看不出来。而 this的就很明显了。 每个new的 独享自己的 this。 this 其实 就是x,x1,x2本身。我们看下面的代码:

function test(){
		test.prototype.tell=function(){
			alert(this.x);
		}
	}
	var t=new test();
	t.x=10;
	t.tell()
在这里 很明显 t.x 就是 方法里面的this.x;当然这个 只能说明 new 出来的是适合的。 x1,x2是适合的。其实 x也是适合的。只不过因为x只是一个函数对象。本身不在运算环境中。所以我们很少注意。比如下面代码:

	function test(){
		var x=1;
		this.x=2;
	}
	test.x=10;
	test.tell=function(){
		alert(this.x);
	}
	test.tell();

言简意赅的说 this到底是什么? 就是调用当前方法的对象。

关于 prototype 其实存在一条链。 叫原型练。 看上面的哪张图。 里面的__proto__属性就是原型链。表明了x1的原型来自于x ,x的原型来自于 object。
 

5.闭包

闭包应该是 js中最重要的特性了。什么叫闭包:闭包是可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。

很拗口 很难懂。 一个代码说明一下 什么事最简单的闭包

function test(){
	var i=1;
	var j=function test2(a){
		i+=a;
		alert(i);
	}
	return j;
}
var jj=test();
jj(1);
jj(1);
jj(1);

上面就是一个最简单的闭包。上面的变量 i 就是 所谓的 自由变量。 这个变量作为 test的局部变量。在test 执行完之后 应该就被销毁。并且没有东西会再访问到它。 但是 由于test2的存在。导致了 jj 这个对象 居然能够访问到 i,并且导致 i不被释放。

其实从广义上讲 任何一个 function 都可以成为闭包。因为它总能访问外部变量。但是 我认为这样理解闭包是不够正确的。闭包的关键不是能够访问外部变量。而是 外部变量的环境已经消失了 仍然能够访问外部变量 

当然 闭包很危险 也很有用。我们 举例一下

function init(){
	for(var i=0;i<3;i++){
		$('a:eq('+i+')').click(function(){
			alert(i);
		})
	}
}
init();

超级经典的例子。我们想要的是 3个 a标签 点击 分别弹出的是 0,1,2 可是结果却是 全是弹出的3。

有人解释说 因为i是全局的,后面的方法没有立即执行。遍历完了 i当然变成3了。 

其实 就是闭包。click事件里面的 function 应用了 i。即使 i的环境已经消失。仍然能够访问这i;

这也是闭包的作用。可以维护一个变量。不被其他污染,同时只有一个。

要解决这个问题,还是用闭包解决。

function init(){
	for(var i=0;i<3;i++){
		$('a:eq('+i+')').click(
			(function(no){
				return function(){
					alert(no);
				}
			})(i)
		)
	}
}
init();

当然这里不仅有闭包的知识 还有函数直接运行的知识。 例如 (function(){})()或者 (function(){}())这样的写法 就是将这个匿名函数直接执行。 在上面的例子里面 我们的匿名方法 直接运行 将 i的值传入了 里面的闭包中。里面的 匿名函数 将维护传入的 no值。这样 会行程3个互不干扰的闭包。

6。JSON

什么事 json  javascript object Notation 这其实是一个数据交换的协议。就好像xml这样。 我们在平时 称呼 {“x”:1}这样的东西 为一个 json对象。从定义上面其实是不对的。只有当他是字符串的时候。我们才称它为json字符串。当然 这种咬文嚼字的定义了解就好。不用深究。

简单的规范 就不提了 需要注意的是 :json字符串中 必须用 双引号  单引号 是错的 即使转义 也是错的。不要跟js语法混淆(这个还给我造成过麻烦 ,后台返回 json 字符串的时候 我自己组装 用 单引号 总出错。。)

7.原型链

js中 利用一个原型链来实现 类似继承的实现。这个特性很重要,但是我的开发过程中实际上基本用到的不多。
在js中 任何一个对象 都有一个隐藏的属性 __proto__这就是原型。当我们在访问这个对象的某一个属性的时候。如果没有找到的话,就会去他的原型当中去找,直到找到为止!
var a = {
	x:'x',
	alert:function(){
		alert(this.x);
	},
	alert2:function (){
		return function(){
			alert(this.x);
		}
	}
}
var b={
	x:"b",
	__proto__:a
}
 b.alert();
 var myAlert = b.alert2();
myAlert();
var x='windowx';
myAlert();
上面的例子说明了原型链 以及 this 作用域的一些问题。 原型链 不改变this 的作用域。 第一个alert 方法 里面的 this 因为 这个方法是 b调用的。所以 这个this 就是 b。而 第一次调用 myAlert 回事 undefined 是因为 这是调用 是全局调用。 其实就是 window.myAlert()。 也就是说 是window调用的。这时候 this指向的是 window。
但是 需要注意的是,在里面访问的局部变量 却不是window中的变量。

这里顺带 要说一下 之前的new
之前的将创建一个隐藏连接到该函数的prototype成员的新对象 其实就是
将new 出来的 对象的 __proto__属性 设置为 对象的 prototype 
function test2(){
}
var t = new test2();
alert(t.__proto__===test2.prototype)

8 上下文


上下文 就是代码执行的环境。 里面有他需要的所有东西。 js 每进入一个函数都会产生新的上下文。一个方法 重复调用 也会产生不同的上下文

上下文主要包含三个组成部分:

变量对象 (variable object):   

 变量对象在不同的上下文中使用不同的对象。 他是执行上下文相关的数据作用域。 储存着定义在上下文中的变量(!!!函数表达式则不被不被包含于变量对象)函数声明

全局的变量对象 就是 global 对象。(在外面普通浏览器中 就是 那个 window对象)

在一个函数上下文中,变量对象被表示为活动对象(activation object)。 在这个函数调用的时候 就会产生这个对象

this指针(this value):

作用域链(scope chain):

这里有一个经典的例子

Object.prototype.x = 10;

var w = 20;
var y = 30;

// 在SpiderMonkey全局对象里
// 例如,全局上下文的变量对象是从"Object.prototype"继承到的
// 所以我们可以得到?/font>没有声明的全局变量?/font>
// 因为可以从原型链中获取

console.log(x); // 10

(function foo() {

  // "foo" 是局部变量
  var w = 40;
  var x = 100;

  // "x" 可以从"Object.prototype"得到,注意值是10哦
  // 因为{z: 50}是从它那里继承的

  with ({z: 50}) {
    console.log(w, x, y , z); // 40, 10, 30, 50
  }

  // 在"with"对象从作用域链删除之后
  // x又可以从foo的上下文中得到了,注意这次值又回到了100哦
  // "w" 也是局部变量
  console.log(x, w); // 100, 40

  // 在浏览器里
  // 我们可以通过如下语句来得到全局的w值
  console.log(window.w); // 20

})();

这里我有一个自己的看法,找不到明确的文字证明我的想法是否正确 但是 的确感觉很像的样子:

我觉的作用域链和原型链是很像的。而且 作用域链就是利用原型链实现的。对于一个上小文中定义的变量 就是绑定在 变量对象(或者类似变量对象的对象)上面的,当然 这个对象 也可以有原型链,而这个原型链 就指向了创建他上下文。

with的操作 就是将大括号里面的上小文 里面的变量对象的 原型链指向了 小括号里面的对象。 

考虑 为什么 上面的例子 with 里面输出是10. 因为 现在 当前上下文中 的变量对象中 寻找x 没有找到 就到 这个对象的原型链中查找。(我们定义一个对象 就是 new 了一个 object  所以 就可以通过原型链查找到) 下面的例子 应该可以 给与一定的证明

function test(){
	var x=1;
}
//test.prototype.x=2;
var t =new test();
with(t){
	alert(x)
}
但是 之后的例子 不能完全的支持我的想法。 比如 下面的

// 全局变量 "x"
var x = 10;

// 全局function
function foo() {
  console.log(x);
}

(function (funArg) {

  // 局部变量 "x"
  var x = 20;

  // 这不会有歧义
  // 因为我们使用"foo"函数的[[Scope]]里保存的全局变量"x",
  // 并不是caller作用域的"x"

  funArg(); // 10, 而不是20

})(foo); // 将foo作为一个"funarg"传递下去

按照我的想法 在执行的时候。 furArg()创建的上下文中变量对象的原型链 指向的是 调用这个函数的的上下文的变量对象。可是事实上 不是的。 又找了点资料 貌似 js 中使用的 是 静态作用域。

我的理解是 在函数声明的时候 就已经创建了这个函数的变量对象(姑且这么称呼)。 在调用这个函数 创建新的函数上下文的时候。 上下文中的激活对象 就是从函数的变量对象中复制过来的(地址)。
又或者 是这样的: 在一个函数声明 的时候(或者函数表达式执行的时候)我们就给这个函数的某一块 附加一些参数。这些参数 就是 这个函数的作用域 以及 声明这个函数所在的上下文的作用域。 

假设一个函数 x执行 创建了一个上下文 存在这样变量 a=1 这个 函数中 创建了 另一个函数 y。里面有一个变量b。 那么y上下文里面的作用域就包含 y里面的变量 b,也包含x的作用域。

总而言之。 这种特性  也是产生 闭包的根本原因。

------------------------------------------------

for ( var i in man) {
   if (man.hasOwnProperty(i)) { // 过滤
      console.log(i, ":", man[i]);
   }

}
--------------------------------------------

// 反面示例
var property = "name";
alert(eval("obj." + property));
// 更好的
var property = "name";
alert(obj[property]);

// 反面示例
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);


// 更好的
setTimeout(myFunc, 1000);
setTimeout( function () {
   myFunc(1, 2, 3);
}, 1000);
------------------------------------------------------------------------------------------------------------------------------------------------

nan  undefind

 string  new string


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值