您的位置:首页 > Web前端 > JavaScript

JavaScript深究系列 [一]

2015-06-18 16:38 746 查看
1. JavaScript中 = = = 

  首先,== equality 等同,=== identity 恒等。 ==, 两边值类型不同的时候,要先进行类型转换,再比较。 ===,不做类型转换,类型不同的一定不等。  

  下面,分别说明: 先说 ===,这个比较简单。下面的规则用来判断两个值是否===相等:

如果类型不同,就[不相等]

如果两个都是数值,并且是同一个值,那么[相等];(例外的是,如果其中至少一个是NaN,那么[不相等]。判断一个值是否是NaN,只能用isNaN()来判断)

如果两个都是字符串,每个位置的字符都一样,那么[相等];否则[不相等]。

如果两个值都是true,或者都是false,那么[相等]。

如果两个值都引用同一个对象或函数,那么[相等];否则[不相等]。

如果两个值都是null,或者都是undefined,那么[相等]。

  再说 ==,根据以下规则:

如果两个值类型相同,进行 === 比较。

如果两个值类型不同,他们可能相等。根据下面规则进行类型转换再比较:
a、如果一个是null、一个是undefined,那么[相等]。
b、如果一个是字符串,一个是数值,把字符串转换成数值再进行比较。
c、如果任一值是 true,把它转换成 1 再比较;如果任一值是 false,把它转换成 0 再比较。
d、如果一个是对象,另一个是数值或字符串,把对象转换成基础类型的值再比较。对象转换成基础类型,利用它的toString或者valueOf方法。js核心内置类,会尝试valueOf先于toString;例外的是Date,Date利用的是toString转换。非js核心的对象。
e、任何其他组合,都[不相等]。

举例:
"1" == true
类型不等,true会先转换成数值 1,现在变成 "1" == 1,再把"1"转换成 1,比较 1 == 1, 相等。

= 赋值运算符
== 等于
=== 严格等于
例:
var a = 3;
var b = "3";

a==b 返回 true
a===b 返回 false

因为a,b的类型不一样
===用来进行严格的比较判断


2. JavaScript中NaN  

  NaN “Not a Number”。出现这个数值比较少见,以至于我们可以不理它。当运算无法返回正确的数值时,就会返回“NaN”值。NaN 值非常特殊,因为它“不是数字”,所以任何数跟它都不相等,甚至 NaN 本身也不等于 NaN 。isNaN()计算一个参数,检查它是否为数值。

语法
isNaN(testValue)
参数

testValue :    你想要测试的值。


如果把不是数字的变量强制转换为数字也会报这个,例如:parseInt("非数字字符串")。

3. JavaScript的数据类型都有什么?

  基本数据类型5:String,boolean,Number,Undefined, Null

  应用数据类型1:Object(Array,Date,RegExp,Function)

4. JavaScript中的typeof运算符

  typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型。它返回值是一个字符串,该字符串说明运算数的类型。

你 知道下面typeof运算的结果吗?

typeof(1);
typeof(NaN);
typeof(Number.MIN_VALUE);
typeof(Infinity);
typeof("123");
typeof(true);
typeof(window);
typeof(document);
typeof(null);
typeof(eval);
typeof(Date);
typeof(sss);
typeof(undefined);

看 看你会几个?


typeof是一个一元运算符,它返回的结果 始终是一个字符串,对不同的操作数,它返回不同的结果。具体的规则如下:

对于数字类型的操作数而言, typeof 返回的值是 number。比如说:typeof(1),返回的值就是number。上面是举的常规数字,对于非常规的数字类型而言,其结果返回的也是number。比如typeof(NaN),NaN在JavaScript中代表的是特殊非数字值,虽然它本身是一个数字类型。在JavaScript中,特殊的数字类型还有几种:

Infinity 表示无穷大特殊值
NaN            特殊的非数字值
Number.MAX_VALUE     可表示的最大数字
Number.MIN_VALUE     可表示的最小数字(与零最接近)
Number.NaN         特殊的非数字值
Number.POSITIVE_INFINITY 表示正无穷大的特殊值
Number.NEGATIVE_INFINITY  表 示负无穷大的特殊值

以上特殊类型,在用typeof进行运算进,其结果都将是number。


对于字符串类型, typeof 返回的值是 string。比如typeof("123")返回的值是string。

对于布尔类型, typeof 返回的值是 boolean 。比如typeof(true)返回的值是boolean。

对于对象、数组、null 返回的值是 object 。比如typeof(window),typeof(document),typeof(null)返回的值都是object。

对于函数类型,返回的值是 function。比如:typeof(eval),typeof(Date)返回的值都是function。

如果运算数是没有定义的(比如说不存在的变量、函数或者undefined),将返回undefined。比如:typeof(sss)、typeof(undefined)都返回undefined。

5. JavaScript中的隐含参数

  arguments:arguments 该对象代表正在执行的函数和调用它的函数的参数。[function.]arguments
参数。function:选项。当前正在执行的 Function 对象的名字。n:选项。要传递给 Function 对象的从0开始的参数值索引。说明Arguments是进行函数调用时,除了指定的参数外,还另外创建的一个隐藏对象。Arguments是一个类似数组但不是数组的对象,说它类似数组是因为其具有数组一样的访问性质及方式,可以由arguments
来访问对应的单个参数的值,并拥有数组长度属性length。还有就是arguments对象存储的是实际传递给函数的参数,而不局限于函数声明所定义的参数列表,而且不能显式创建 arguments对象。arguments对象只有函数开始时才可用。

//arguments 对象的用法
function ArgTest(a, b){
var i, s = "The ArgTest function expected ";
var numargs = arguments.length;     // 获取被传递参数的数值。
var expargs = ArgTest.length;       // 获取期望参数的数值。
if (expargs < 2)
s += expargs + " argument. ";
else
s += expargs + " arguments. ";
if (numargs < 2)
s += numargs + " was passed.";
else
s += numargs + " were passed.";
s += " "
for (i =0 ; i < numargs; i++){      // 获取参数内容。
s += "    Arg " + i + " = " + arguments + " ";
}
return(s);                          // 返回参数列表。
}


6. 如何判断某变量是否为数组数据类型 ?

if(typeof Array.isArray==="undefined") {
  Array.isArray = function(arg){
    return Object.prototype.toString.call(arg)==="[object Array]"
  };
}


7.已知ID的Input输入框,希望获取这个输入框的输入值,怎么做?(不使用第三方框架)

document.getElementById("ID").value


8.希望获取到页面中所有的checkbox怎么做?(不使用第三方框架)

var domList = document.getElementsByTagName(‘input');
var checkBoxList = [];
var len = domList.length;  //缓存到局部变量
while (len--) {  //使用while的效率会比for循环更高   
  if (domList[len].type == ‘checkbox') {     
    checkBoxList.push(domList[len]);   
  }
}


9. 设置一个已知ID的DIV的html内容为xxxx,字体颜色设置为黑色(不使用第三方框架)

var dom = document.getElementById("ID”);
dom.innerHTML = "xxxx”
dom.style.color = "#000”


10. 当一个DOM节点被点击时候,我们希望能够执行一个函数,应该怎么做?

直接在DOM里绑定事件:<div onclick=”test()”></div>

在JS里通过onclick绑定:xxx.onclick = test

通过事件添加进行绑定:addEventListener(xxx, ‘click', test)

11. 什么是Ajax和JSON,它们的优缺点。

  Ajax是异步JavaScript和XML,用于在Web页面中实现异步数据交互。优点:可以使得页面不重载全部内容的情况下加载局部内容,降低数据传输量(这在加快页面加载速度方面,效果显著);避免用户不断刷新或者跳转页面,提高用户体验。缺点:对搜索引擎不友好;要实现ajax下的前后退功能成本较大;可能造成请求数的增加;跨域问题限制。

  JSON是一种轻量级的数据交换格式,ECMA的一个子集。优点:轻量级、易于人的阅读和编写,便于机器(JavaScript)解析,支持复合数据类型(数组、对象、字符串、数字)

12. 解释如下代码执行结果

var a;
alert(typeof a); // undefined
alert(b); // 报错


解释::Undefined是一个只有一个值的数据类型,这个值就是"undefined”,在使用var声明变量但并未对其赋值进行初始化时,这个变量的值就是undefined。而b由于未声明将报错。注意未申明的变量和声明了未赋值的是不一样的。

var a = null;
alert(typeof a); //object


解释::null是一个只有一个值的数据类型,这个值就是null。表示一个空指针对象,所以用typeof检测会返回”object”。

var undefined;
undefined == null; // true
1 == true;  // true
2 == true;  // false
0 == false; // true
0 == '';   // true
NaN == NaN; // false
[] == false; // true
[] == ![];  // false


解释如下:

1 undefined与null相等,但不恒等(===)
2 一个是number一个是string时,会尝试将string转换为number
3 尝试将boolean转换为number,0或1
4 尝试将Object转换成number或string,取决于另外一个对比量的类型
5 所以,对于0、空字符串的判断,建议使用 "===” 。"===”会先判断两边的值类型,类型不匹配时为false。


相等运算符 (==、!=)
如果两表达式的类型不同,则试图将它们转换为字符串、数字或 Boolean 量。
NaN 与包括其本身在内的任何值都不相等。
负零等于正零。
null 与 null 和 undefined 相等。
相同的字符串、数值上相等的数字、相同的对象、相同的 Boolean 值或者(当类型不同时)能被强制转化为上述情况之一,均被认为是相等的。
其他比较均被认为是不相等的。

恒等运算符 (===、!==)
除了不进行类型转换,并且类型必须相同以外,这些运算符与相等运算符的作用是一样的。


为了验证上面这些效果,我们这样来做:在Chrome浏览器的地址栏中直接输入javascript:alert(123);直接进行调试,如下:



代码执行后,结果为string。我们在浏览器Chrome中,依次输入如下:

注意在Chrome中复制这些javascript代码的时候,它会默认的自动隐藏掉javascript这个字母,所以这个字母你要手动的打出来的。

javascript:alert(Number(''));  //0
javascript:alert(Number(""));  //0
javascript:alert(Number(123));  //123
javascript:alert(Number('123'));  //123
javascript:alert(Number('abc'));  //NaN
javascript:alert(Number('a3b2c'));  //NaN


javascript(alert(Boolean([])));  //true
javascript(alert(Boolean(![])));  //false
javascript:alert((Boolean([]))==(Boolean(![])));  //false
javascript:alert((Boolean(![]))==(Boolean(![])));  //true


13. javascript中有几种强制类型转换?

  在 javascript 中有3中强制类型转换: Boolean (value), Number(value), String(value)

我们这样来做。

14. javascript中将string转换成number类型

  javascript中,可以通过以下3种方法来将string值转换成number:调用Number()来对string进行值类型转换;parseInt();parseFloat()。

15. 看代码,给答案 (体会加一个字符串'1' 和 减去一个字符串'1'的不同)

var foo = "11"+2-"1";
console.log(foo);
console.log(typeof foo);

测试:javascript:alert("11"+2);  //112


答案:执行完后foo的值为111,foo的类型为Number。

var foo = "11"+2+"1"; //体会加一个字符串'1' 和 减去一个字符串'1'的不同
console.log(foo);
console.log(typeof foo); 


答案:执行完后foo的值为1121(此处是字符串拼接),foo的类型为String。

var a = new Object();
a.value = 1;
b = a;
b.value = 2;
alert(a.value);  


答案::2(考察引用数据类型细节)

16. 已知数组var stringArray = ["This”, "is”, "Baidu”, "Campus”],Alert出”This is Baidu Campus”。

答案::alert(stringArray.join(" "))

17. 已知有字符串foo="get-element-by-id",写一个function将其转化成驼峰表示法"getElementById"。

考查基础API

function combo(msg){
  var arr = msg.split("-");
  var len = arr.length;  //将arr.length存储在一个局部变量可以提高for循环效率
  for(var i=1;i<len;i++){
    arr[i]=arr[i].charAt(0).toUpperCase()+arr[i].substr(1,arr[i].length-1);
  }
  msg=arr.join("");
  return msg;
}


18. JavaScript中匿名函数

  匿名函数,就是没有名字的函数。此时函数的定义有以下三种方式:

// 最常规的定义匿名函数的方法:返回值+函数名+参数
function double(x){
return 2 * x;
}


// 这种方法使用了Function的构造函数,把参数列表和函数体都作为字符串,不建议使用。
var double = new Function('x', 'return 2 * x;');


//  右边是匿名函数,函数执行后,又将函数值赋给了变量square
var square= function(x) { return 2* x; }


说完了函数的定义,那么我们再说说函数的创建:

//  第一种函数创建的方法,实质上是定义了suqre函数。
var square= function(x) { return 2* x; }


//  在第一个括号内,创建了一个匿名函数;第二个函数用户调用该匿名函数,并传入参数。 约定优于配置。
(function(x, y){
alert(x + y);
})(2, 3);


19. JavaScript中函数的闭包

  闭包的英文单词是closuer,这是javascript中的特色。使用闭包的好处就是,它能大大的减少我们的代码量。闭包说通俗些,就是函数的嵌套。内层函数可以使用外层函数的全部变量,即使外层函数已经执行完毕了。

function checkClosure(){
var str = 'rain-man';
setTimeout(
function(){ alert(str); } //这是一个匿名函数
, 2000);
}
checkClosure();


这个例子看上去十分的简单,仔细分析下它的执行过程还是有许多知识点的:checkClosure函数的执行是瞬间的(也许用时只是0.00001毫秒),在checkClosure的函数体内创建了一个变量str,在checkClosure执行完毕之后str并没有被释放,这是因为setTimeout内的匿名函数存在这对str的引用。待到2秒后函数体内的匿名函数被执行完毕,str才被释放。

function forTimeout(x, y){
alert(x + y);
}
function delay(x , y  , time){
setTimeout('forTimeout(' +  x + ',' +  y + ')' , time);
}
/**
* 上面的delay函数十分难以阅读,也不容易编写,但如果使用闭包就可以让代码更加清晰
* function delay(x , y , time){
*     setTimeout(
*         function(){
*             forTimeout(x , y)
*         }
*     , time);
* }
*/


附:结合一下,来说说匿名函数和函数闭包的结合的具体使用:匿名函数最大的作用是创建闭包;并且还可以创建命名空间;以减少全局变量的使用。

var oEvent = {};
(function(){
var addEvent = function(){ /*代码的实现省略了*/ };
function removeEvent(){}

oEvent.addEvent = addEvent;
oEvent.removeEvent = removeEvent;
})();


上面代码中,addEvent和removeEvent都是局部变量,但我们可以通过全局变量oEvent来使用它,这就大大减少了全局变量的使用,增强了网页的安全性。我们使用此代码如下:oEvent.addEvent(document.getElementById('box') , 'click' , function(){});

var rainman = (function(x , y){
return x + y;
})(2 , 3);
/**
* 也可以写成下面的形式,因为第一个括号只是帮助我们阅读,但是不推荐使用下面这种书写格式。
* var rainman = function(x , y){
*    return x + y;
* }(2 , 3);
*/


上面代码中,我们创建了变量rainman,并通过调用匿名函数初始化为5。

var outer = null;

(function(){
var one = 1;
function inner (){
one += 1;
alert(one);
}
outer = inner;
})();

outer();    //2
outer();    //3
outer();    //4


这段代码中的变量one是一个局部变量(因为它被定义在一个函数之内),因此外部是不可以访问的。但是这里我们创建了inner函数,inner函数是可以访问变量one的;又将全局变量outer引用了inner,所以三次调用outer会弹出递增的结果。

/**
* <body>
* <ul>
*     <li>one</li>
*     <li>two</li>
*     <li>three</li>
*     <li>one</li>
* </ul>
*/

var lists = document.getElementsByTagName('li');
for(var i = 0 , len = lists.length ; i < len ; i++){
lists[ i ].onmouseover = function(){
alert(i);
};
}


你会发现当鼠标移过每一个<li>;元素时,总是弹出4,而不是我们期待的元素下标。这是为什么呢?注意事项里已经讲了(最终值)。显然这种解释过于简单,当mouseover事件调用监听函数时,首先在匿名函数( function(){ alert(i); })内部查找是否定义了 i,结果是没有定义;因此它会向上查找,查找结果是已经定义了,并且i的值是4(循环后的i值);所以,最终每次弹出的都是4。理由:闭包允许内层函数引用父类函数中的变量,但是该变量必须是最终值。解决方案有如下三种:

var lists = document.getElementsByTagName('li');
for(var i = 0 , len = lists.length ; i < len ; i++){
(function(index){
lists[ index ].onmouseover = function(){
alert(index);
};
})(i);
}


var lists = document.getElementsByTagName('li');
for(var i = 0, len = lists.length; i < len; i++){
lists[ i ].$$index = i;    //通过在Dom元素上绑定$$index属性记录下标
lists[ i ].onmouseover = function(){
alert(this.$$index);
};
}


function eventListener(list, index){
list.onmouseover = function(){
alert(index);
};
}
var lists = document.getElementsByTagName('li');
for(var i = 0 , len = lists.length ; i < len ; i++){
eventListener(lists[ i ] , i);
}


20. 什么是JavaScript中的作用域和作用域链

  任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。

  全局作用域(Global Scope),在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域:

var authorName="山边小溪";
function doSomething(){
var blogName="梦想天空";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(authorName); //山边小溪
alert(blogName); //脚本错误
doSomething(); //梦想天空
innerSay() //脚本错误


在代码中,最外层函数和在最外层函数外面定义的变量拥有全局作用域。

function doSomething(){
var authorName="山边小溪";
blogName="梦想天空";
alert(authorName);
}
doSomething(); //山边小溪
alert(blogName); //梦想天空
alert(authorName); //脚本错误


代码中,所有末定义直接赋值的变量自动声明为拥有全局作用域。变量blogName拥有全局作用域,而authorName在函数外部无法访问到。并且,所有window对象的属性拥有全局作用域。一般情况下,window对象的内置属性都拥有全局作用域,例如window.name、window.location、window.top等等。

  局部作用域(Local Scope),和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部,所有在一些地方也会看到有人把这种作用域称为函数作用域,例如下列代码中的blogName和函数innerSay都只拥有局部作用域。

function doSomething(){
var blogName="梦想天空";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(blogName); //脚本错误
innerSay(); //脚本错误


  作用域链,在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。当一个函数创建后,它的作用域链会被创建此函数的作用域中可访问的数据对象填充。例如定义下面这样一个函数:

function add(num1,num2) {
var sum = num1 + num2;
return sum;
}


在函数add创建时,它的作用域链中会填入一个全局对象,该全局对象包含了所有全局变量,如下图所示(注意:图片只例举了全部变量中的一部分):



函数add的作用域将会在执行时用到。例如执行如下代码:
var
total = add(5,10);
执行此函数时会创建一个称为“运行期上下文(execution context)”的内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。新的作用域链如下图所示:



在函数执行过程中,没遇到一个变量,都会经历一次标识符解析过程以决定从哪里获取和存储数据。该过程从作用域链头部,也就是从活动对象开始搜索,查找同名的标识符,如果找到了就使用这个标识符对应的变量,如果没找到继续搜索作用域链中的下一个对象,如果搜索完所有对象都未找到,则认为该标识符未定义。函数执行过程中,每个标识符都要经历这样的搜索过程。

详情参考:/article/1210737.html

21. JavaScript中普通函数的定义和使用

22. JavaScript中的内存泄露

  先来说说JavaScript中的垃圾回收:JavaScript不需要手动地释放内存,它使用一种自动垃圾回收机制(garbage collection)。当一个对象无用的时候,即程序中无变量引用这个对象时,就会从内存中释放掉这个变量。

   var s = [ 1, 2 ,3];
var s = null;
//这样原始的数组[1 ,2 ,3]就会被释放掉了。


循环引用:三个对象A、B、C。A->B->C :A的某一属性引用着B,同样C也被B的属性引用着。如果将A清除,那么B、C也被释放。

  A->B->C->B :这里增加了C的某一属性引用B对象,如果这是清除A,那么B、C不会被释放,因为B和C之间产生了循环引用。示例代码如下:

var a = {};
a.pro = { a:100 };
a.pro.pro = { b:100 };
a = null ;
//这种情况下,{a:100}和{b:100}就同时也被释放了。

var obj = {};
obj.pro = { a : 100 };
obj.pro.pro = { b : 200 };
var two = obj.pro.pro;
obj = null;
//这种情况下 {b:200}不会被释放掉,而{a:100}被释放了。

http://www.jb51.net/article/56847.htm
答案:

答案:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: