JavaScript笔记
一、入门
1.js的使用
1.使用<script>
元素的方式有两种:直接放在页面嵌入JavaScript或者包含外部文件
(1)使用<script>
元素嵌入JavaScript代码时,只需要为<script>
指定type属性,再把js代码放入元素内部
<script type="text/javascript"></script>
注意:在<script>
元素内部的代码是从上至下依次执行解释,在解释器对<script>
元素内部所有代码求值完毕之前,页面其余内容不会被浏览器加载或显示
(2)通过<script>
元素来包含外部JavaScript文件,那么一定要使用到src属性 这个属性的值是指向外部JavaScript文件的链接。
<script src = ""> </script>
注意:与嵌入式JavaScript代码一样,在解析外部JavaScript文件(包括下载该文件时),页面处理也会暂时停止
特别注意
在使用带有src属性的<script>
元素不应该在其<script></script>
标签之间再包含额外的JavaScript代码。
如果包含了嵌入的代码,则只会下载并执行外部脚本文件,嵌入的会被忽略哦
2.标签位置
按照惯例,所有<script>
元素应该放在页面的<head>
元素中
目的是把所有的外部文件的引用(css\js)放在相同的位置,但是这也意味着要等到全部JavaScript代码被下载、解析和执行完成后,才可以开始呈现页面的内容(<body>
标签里的)。
这会使那些需要很多js代码的页面在呈现时有明显的延迟,而延迟期间的浏览器窗口会一片空白
因此
JavaScript的引用一般会放在<body>
元素中页面内容的后面
3.延迟脚本(defer)
defer属性的用途是表明脚本在执行会延迟到整个页面都解析完毕后再运行。使用defer属性相当于告诉浏览器立刻下载,但延迟执行。最好只包含一个延迟脚本
<script type="text/javascript" defer="defer" src="index.js"></script>
扩展: HTML5规范要求脚本按照它们出现的先后顺序执行,因此第一个延迟脚本会先于第二个延迟脚本执行,但两个脚本会先于DOMContentLoaded事件触发前执行,最好只包含一个延迟脚本
4. 异步脚本 (async)
与defer类似
- 都用于处理脚本的行为
- 只适用于外部脚本文件,并告诉浏览器立刻下载文件
与defer不同
- 不能保证按照指定的先后顺序(随机)
<script type="text/javascript" async src="index.js"></script>
注意:当引用两个及以上的外部文件时,要确保文件之间不会相互依赖。建议异步脚本不要在加载期间修改DOM
5.HTML和XHTML的区别
XHTML和HTML 4.01 标准没有太多区别,但XTML书写较规范
不同:
- XHTML 元素必须被正确地嵌套。
- XHTML 元素必须被关闭。
- 标签名必须用小写字母。
- XHTML 文档必须拥有根元素
1.XHTML 元素必须被正确地嵌套。
在 HTML 中,某些元素可以像这样彼此不正确地嵌套:
<b><i>This text is bold and italic</b></i>
但在XHTML中,所有的元素要正确嵌套
<b><i>This text is bold and italic</i></b>
2.XHTML 元素必须被关闭 是指双标签必须带上尾标签
错误例子
<p>This is a paragraph
<p>This is another paragraph
正确例子
<p>This is a paragraph</p>
<p>This is another paragraph</p>
3.单标签也必须被关闭
空标签也必须使用结束标签,或者其开始标签必须使用/>结尾。
错误用法
A break: <br>
An image: <img src="happy.gif" alt="Happy face">
正确
A break: <br />
An image: <img src="happy.gif" alt="Happy face" />
4.XHTML 元素必须小写
XHTML 规范定义:标签名和属性对大小写敏感。
错误
<BODY>
<P>This is a paragraph</P>
</BODY>
正确用法
<body>
<p>This is a paragraph</p>
</body>
5.XHTML 文档必须拥有一个根元素
所有的 XHTML 元素必须被嵌套于
<html>
根元素中。其余所有的元素均可有子元素。子元素必须是成对的且被嵌套在其父元素之中。基本的文档结构如下:
<html>
<head> ... </head>
<body> ... </body>
</html>
二、基本概念
1.语法
(1).区分大小写
(2).标识符
- 第一个字符必须是一个字母、下划线(_)或一个美元符号($)
- 其他字符可以是字母】下划线、美元符号或数字
- 要采用驼峰命名法,也就是第一个字母小写,剩下的每隔有意义的单词的首字母大写
(3).注释
// 单行注释
/* 多行注释*/
(4).严格模式
要使整个脚本启用严格模式,可以在顶部添加
"use strict";
在函数的内部上的包含这编译指示,可以指定函数在严格模式下执行
function doSomething() {
"use strict";
// 函数体
}
(5).语句
语句以一个分号结尾,虽然语句结尾的分号不是必需的,但不要省略它,用来增加代码的性能。在开发中,会压缩代码(删除多余的空格)。没有分号会导致压缩错误
2.关键字和保留字
具有一定作用的关键字不能用作标识符
还一些不能作为标识符的保留字,虽然现在没有任何特定的作用,但有可能在以后用做关键字
3.变量
定义变量要用var 操作符,后跟变量名,例如:
var message;
这就定义了一个名为message的变量,该变量可以用来保存任何值(没有初始化的变量,会有一个特殊的值----underfined)。
也可以定义变量的同时设置变量的值
var message = “hi”;
像这样初始化变量并不会把它标记为字符串类型;初始化的过程就是给变量赋了一个值而已,因此 ,可以在修改变量的同时修改值的类型
var message = “hi”;
message = 100; //有效,但不推荐
在使用是要注意全局变量和局部变量
可以出现下面这样省略var操作符,从而创建一个全局变量;
function test(){
message = "hi"; //全局变量
}
test();
alert(message); //hi
像上面这样,只要调用过一次test()函数,这个变量就有了定义,就可以在函数外部的任何地方被访问到(但不推荐,在局部作用域定义的全局变量很难维护,而且有意的忽略var操作符,会由于相应变量不会马上有定义而导致不必要的混乱,而且给未经声明的变量赋值在严格模式下会导致抛出ReferenceEttor错误)
定义多个变量
一条语句可以定义多个变量,如:
var message = "hi",
found = false,
age = 29;
4.数据类型
ECMAscript数据类型具有动态性,所以没有定义其他类型的必要
(1).typeof 操作符
用来检测变量的数据类型
注意:有的时候会返回一些令人迷惑但技术上正确的值
- typeod null 会返回 object ,因为特殊值null会被认为是一个空对象引用
(2).Undefined类型
在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined
var message ;
alert(message == undefined); //true
(3).Null类型
从逻辑上看,null值表示一个空对象指针,所以typeof操作符检测null值 会返回 object
如果定义的变量准备在将来用于保存对象,那么最好把该变量初始化为null,而不是其他值。
if( car != null){
//对car对象执行某些操作
}
null 和 undefined
undefined 值是派生自null的。但两者的用途完全不同
alert(null == undefined) ; //true
(4)Boolean类型
该类型只有两个字面值:true和false。
因为两个值与数字值不是一回事,因此true不一定等于1,false也不一定等于0.
//变量赋Boolean类型值
var found = true;
注意:true和false是区分大小写的。也就是说True和False(以及其他混合大小写形式)都不是boolean值.
想要把一个值转换为其对应的Boolean值,可以调用转型函数Boolean()
var message = "hello";
var messageBoolean = Boolean(message);
至于返回的值是true还是false,取决于转值数据类型及实际值
(5) Number类型
浮点数值
该数值必须包含一个小数点,小数点后面至少有一位数字
注意:如果浮点数本身表示的就是一个整数(如 1.0),那么该值也会被转换为整数
科学计数法
对于极大或者极小的数值,可以使用e表示法(科学计数法)表示浮点数值 。
格式 前面一个数值(可以是整数也可以是浮点数)。中间是一个大写或者小写的字母E,后面是10的幂中的指数,该幂值将用来合前面得的数相乘
意义 e数值前的数值乘以10的指数次幂
例子 3.125e7 等于31250000
数值范围
NAN
非数值的特殊数值。表示一个本要返回数值的操作数未返回数值的情况。
特点
1.任何涉及NAN的操作(例如NAN / 10)都会返回NAN
2. NAN与任何值都不相等,包括NAN本身
针对这两个特点,定义了一个isNAN()函数来帮我们确定参数是否”不是数值”
某些不是数值的值会被转换为数值,如 “10” 或 Boolean值
不能被转换为数值的值会导致这个函数返回true
数值转换
有三个函数 Number() 、parseInt() 和parseFloat()
Number()
- 如果是Boolean值,true和false将分别转换为1和0
- 如果是数字值,只是简单的传入和返回
- 如果是null值,返回0
- 如果是undefined,返回NAN
- 如果是字符串 很多
with语句
with语句的作用是将代码的作用域设置到一个特定的对象中,目的是简化多次编写同一个对象的工作内容
var qs = location.search.substring(1);
var host = location.hostname;
var url = location.href;
上面几行包含location对象,如果用with语句,可以改成如下:
with(location) {
var qs = search.substring(1);
var host = hostname;
var url = href;
}
大量使用with语句会导致性能下降,同时也会造成代码困难,因此在大型开发,不建议使用with语句
(6)检测类型
typeof操作符
用typeof检测一个变量是不是基本数据类型如果变量的值是一个对象或null,则会返回object
var u;
var n = null;
console.log(typeof u); //undefined
console.log(typeof n); //object
instanceof操作符
typeof在检测引用类型的值时作用不大,通常我们更倾向于想知道某个值是什么类型的对象,这是可以用到instanceof
语法
result = variable(变量名) instanceof constructor(类型)
如果变量是给定引用类型,会返回true
alert(person instanceof Object);// 变量person是object吗
根据规定,所有引用类型的值都是Object的实例,因此在检测一个引用类型和object构造函数时,instanceof操作符始终会返回true
当然,如果使用instanceof操作符检测基本类型的值,会返回false,因为基本类型不是对象
ndefined、Null、Boolean、Number都属于基本类型。
Object、Array和Function则属于引用类型
5.作用域
没有块级作用域★
js没有块级作用域会导致理解上的困惑,在其他语言里,由花括号封起来的都有自己的作用域(但就ECMAscript来讲,就是它们自己的执行环境)
if (true) {
var color = "blue";
}
console.log(color); 此时的color = blue
由上,在if语句里面创建了一个变量color ,如果在其他语言里面,color会在if语句执行完后就销毁,但在js里面,if语句里面的声明就将变量添加到当前的执行环境(可以理解为color成为了一个全局变量)。
function(num1,num2){
var sum = num1+num2;
return sum;
}
var result = add(10,20); //30
alert(sum); //由于sum不是有效的变量,会导致错误
但是如果 sum 不用 var 声明,在add()执行结束后,sum也会被访问
function(num1,num2){
sum = num1+num2;
return sum;
}
var result = add(10,20); //30
alert(sum); //30
查询标识符
查询标识符时,搜索过程从作用域的前端开始,向上逐级查询与给定名字匹配的标识符,如果在局部变量中找到了该标识符,搜索过程结束,如果没有再局部环境中没有找到该变量,就会向上搜索,搜索对象将一直追溯到全局变量的变量对象
给我的感觉就是:由近到远
var color = "pink";
function getcolor() {
return color;
}
alert(getcolor()); //blue
------------- 这是一条分界线-------------------
var color = "pink";
function getcolor() {
color = "red";
return color;
}
alert(getcolor()); //red
引用类型
Object类型
我们看到的大多数引用类型都是object类型的实例,虽然object的实例不具备多少功能,但对于应用程序中存储和传输数据而言,是非常理想的选择
创建构造方法的两种方式
- 使用new操作符后跟Object构造函数
var person = new Object()
- 使用对象字面量表示法,对象字面量是对象定义的一种简写新式,目的在于简化创建包含大量属性的对象过程
var person = {
name:"andy",
age:29
};
访问对象属性
下面在使用方括号语法时,应该将要访问的属性以字符串的形式放在方括号中,
- 点表示法 alert(person[“name”])
- 方括号表示法 alert( person.name)
注意:
如果变量名中间包含了一个空格,如My name ,就不能用点表示法来访问它,这时就可以使用方括号表示法
Array类型
与其他语言不一样的是ECMAScript数组的每一项可以保存任何类型的数据也就是说可以数组的第一项来保存字符串,第二位来保存数值,第三个位置来保存对象,以此类推。ECMAScript数组的大小是可以动态调整的,即可以随着数据的添加自动增加以容纳新增数据
创建数组的方式
- 使用Array构造函数
var color = new Array();
如果预先知道数组要保存的项目数量,也可以给构造函数传递该数量,而该数量会自动变成length属性的值
(但这个创建的是给定项数的数组)
var color = new Array(20);
也可以直接传参,(创建得到是只包含参数数量的数组)
var color = new Array("red","pink";)
- Array构造函数时可以省略new操作符
var color = ["red","blue"]; 创建一个包含2个字符串的数组
var name = []; 创建一个空数组
检测数组
instanceof
可用instanceof操作符来确定某个对象是不是数组
var value = [];
if (value instanceof Array) {
alert('这是数组');
}
instanceof的问题在于,他假定单一的全局执行环境,如果网页中包含多个框架,那实际上就存在两个以上的不同全局执行环境,从而存在两个以上不同版本的array构造函数
Array.isArray
为了解决上述问题,新增了Array.isArray方法
if (Array.isArray(value)) {
alert('这是数组');
}
转换方法
toLocaleString()、toString()和valueOf()
每个对象都有 toLocaleString()、toString()和valueOf()方法
var colors = ["red", "green", "blue"];
alert(colors.toString()); //red,green,blue
alert(colors.valueOf());//red,green,blue
alert(colors);//red,green,blue
如上,由于alert()要接收字符串参数,所以会在后台调用toString()方法,因此会得到和toString()方法相同的结果
join()
数组继承的toLocaleString()、toString()和valueOf()方法,在默认情况下会以逗号分隔的字符串的形式返回数组项,使用join() 方法,则可以使用不同的分隔符来创建这个字符串,join()方法只接受 作为分隔符的字符串 这一个参数
注意:不给join()传入任何值,或者传入undefined,则会使用逗号作为分隔符
var colors = ["red", "green", "blue"];
alert(colors.join(",")); //red,green,blue
alert(colors.join("|"));//red|green|blue
栈方法(后进先出)
栈是一种可以限制插入和删除项的数据结构,而栈中项的插入(推入)和移除(弹出),只发生在栈的顶部。ECMAScript为数组提供了push()和pop()方法
pop() 从数值的末尾移除最后一项
push() 接受任意数量的参数,添加到数组末尾
var colors = new Array(); //创建一个数组
var count = colors.push("red", "green");
alert(count); //2
var item = colors.pop();
alert(item);//green
对列方法(先进先出)
shift() 移除数组的第一项,并返回该项
push() 添加参数,放在末尾
var colors = new Array();
var count = colors.push("red", "green");
alert(count); //2
var item = colors.shift();
alert(item); //red
unshift() 在数组前端添加任意项并返回新数组长度
因此unshift()和pop()方法,可以从反方向来模拟对列,即在数组前端添加项,末端移除项
var colors = new Array();
var count = colors.unshift("red", "green");
alert(count); //2
count = colors.unshift("black");
var item = colors.shift();
alert(item); //green
重排序方法
数组中已经存在两个可以直接用来重排序的方法,reverse()和sort()
reverse() 反转数组的顺序
var values = [1, 2, 3, 4, 5];
values.reverse();
alert(values); //5,4,3,2,1
sort() 按升序排列数组项
为了实现排序,sort()方法会调用每个数组项的toString()转型方法,然后比较得到的字符串,即使数组中的每一项都是数值,sort()方法比较的也是字符串
var values = [0, 1, 13, 10, 5];
values.sort();
alert(values); //0,1,10,13,5
如上,虽然数值5小于10,但是字符串比较,10则位于5前面,于是数组的顺序就被修改了
操作方法
concat()
在没有给concat() 传参的情况下,只是复制当前数组并返回副本,如果传递的值不是数组,那么这些值就会被简单的添加到数组的末尾
var colors = ["red", "green", "blue"];
var colors2 = colors.concat("yellow", ["black", "brown"]);
alert(colors2); //red,green,blue,yellow,black,brown
slice()
基于当前数组中的一个或多个项创建一个新数组
var colors = ["red", "green", "blue", "yellow", "black", "brown"];
var colors2 = colors.slice(1);
var colors3 = colors.slice(1, 4);
alert(colors2); //green,blue,yellow,black,brown
alert(colors3); //green,blue,yellow
splice()★★
最强大的数组方法
删除 可以删除任意数量的项,例如splice(0,2)的会删除数组中的前两项
插入可以向指定位置插入任意数量的项,三个参数:(起始位置、要删除的项数,要插入的项)例如splice(2,0,“red”,“green”)会从当前数组位置2插入字符串"red",“green”)
替换可以向指定位置插入任意数量的项,插入项数不必与替换项数相等。例如splice(2,1,“red”,“green”)会删除当前位置2的项,在从位置2开始插入字符串"red",“green”
var color = ["red", "green", "blue", "yellow", "black", "brown"];
var remove = color.splice(0, 1);
alert(color); //green,blue,yellow,black,brown
alert(remove); //red
var remove1 = color.splice(1, 0, "yellow", "orange");
alert(color); //green,yellow,orange,blue,yellow,black,brown
alert(remove1); //空数组
var remove3 = color.splice(0, 1, "red", "purple");
alert(color); //red,purple,yellow,orange,blue,yellow,black,brown
alert(remove3) //green
位置方法
ECMAScript为数组实例添加了两个位置方法:indexOf()和lastIndexOf(),接收两个参数:要查找的项和表示查找起点位置的索引。都返回要查找的项在数组中的位置,没有找到的情况下返回-1
indexOf()从数组的开头(位置0)开始往后找
lastIndexOf()从数组的末尾开始向前找
迭代方法
ECMAScript为数组定义了5个迭代方法,每个方法都接收两个参数,在每一项上运行的函数和运行该函数的作用域对象–影响this的值根绝使用方法不同,函数执行后的返回值可能会也可能不会影响访问的返回值
every()
对数组中的每一项运行给定函数,如果该函数每一项都返回true,则返回true
filter()
对数组中的每一项运行给定函数,返回该函数会返回true的项组成得到数组
var number = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var filterResult = number.filter(function(item, index, array) {
return (item > 2);
});
alert(filterResult);//3,4,5,4,3
forEach()
对数组中的每一项运行给定函数,这个方法没有返回值
var number = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var forResult = number.map(function(item, index, array) {
// 执行某些操作,没有返回值
});
map()
对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组
var number = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var mapResult = number.map(function(item, index, array) {
return (item * 2);
});
alert(mapResult); //2,4,6,8,10,8,6,4,2
some()
对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true
下面是every()和some()的调用
var number = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var everyResult = number.every(function(item, index, array) {
return (item > 2);
});
alert(everyResult); //false
var someResult = number.some(function(item, index, array) {
return (item > 2);
});
alert(someResult); //true
缩小方法
缩小数组的方法;reduce()和reduceRight().这两个方法都会迭代数组的所有项,然后构建一个最终返回的值,
reduce()从第一项开始,遍历到最后
var values = [1, 2, 3, 4, 5];
var sum = values.reduce(function(prev, cur, index, array) {
return prev + cur;
})
alert(sum);//15
第一次执行上面的函数,prev是1,cur是2,第二次prev是3(1+2的结果)cur是3(数组的第三项)以此类推
reduceRight()从最后一项开始,向前遍历到第一项
var values = [1, 2, 3, 4, 5];
var sum = values.reduceRight(function(prev, cur, index, array) {
return prev + cur;
})
alert(sum); //15
第一次prev是5,cur是4
以上两个都接收两个参数,一个在每一项调用的函数和(可选的)作为缩小基础的初始值。传给reduce()和 reduceRight()的函数接收4个参数:前一个值、当前值、项的索引和数组对象
Date类型
Date类型使用UTC(1970年1月1日午夜零时)开始经过的毫秒数来保存日期。Date类型保存的日期可以精确到1970年1月1日之前或之后的285616年
Date.parse()
这个方法接收一个表示日期的字符串参数,然后尝试根据这个字符串返回相应的日期的毫秒数。如果接收的不表示日期,会返回NAN。
var date = new Date(Date.parse("May 25,2004"));
alert(date); //Tue May 25 2004 00:00:00 GMT+0800 (中国标准时间)
var somedate = new Date("May 25,2004");
alert(somedate);//Tue May 25 2004 00:00:00 GMT+0800 (中国标准时间)
Date.parse() 与直接将日期的字符串传递给Date构造函数 作用一样
Date.UTC()
Date.UTC()方法也返回表示日期的毫秒数,但它与Date.parse()使用方法不一样
Date.UTC()参数分别是年份、基于0的月份(一月是0,二月是1,以此类推)、月中的哪一天(1到31)、小时数(0到23)、分钟、秒、毫秒数,但是在上面参数中,只有前两个参数(年月)是必需的,没有提供月中的天数,就假设天数为1,忽略其他参数就通通假设为0。
// GMT时间 表示2000年的1月1日午夜零时
var y2k = new Date(Date.UTC(2000, 01));
//GMT时间 2005年5月5日下午5:55:55
var allFive = new Date(Date.UTC(2005, 4, 5, 17, 55, 55));
alert(allFive);
如同 Date.parse()一样,Date构造函数也会模仿Date.UTC(),但有一点不同,日期和时间都基于本地时区
Date.now()
返回表示调用这个方法时的日期和时间的毫秒数
var start = Date.now();
继承方法
Date类型的toLocateString()方法会按照与浏览器设置的地区想适应的格式返回日期和时间,这意味着格式中会包含AM和PM,但不会包含时区信息。而toString()方法则通常返回带有时区信息的日期和时间,时间一般以军用时间(即小时范围是0到23)表示
toLocateString()和toString()的差别只在调试代码时不叫有用
而Date类型的valueof()方法,则根本不返回字符串,而是返回日期的毫秒表示,因此可以用在比较操作符(大于或小于)来比较日期
RegExp类型
以下面的语法来创建一个正则表达式
var str = / pattern / flags
pattern表示任何简单或复杂的正则表达式,包括字符串、限定符、分组、向前查找或者反向引用。一个或多个flags,用来标明正则表达式的行为
- g:g (global的简写,中文翻译为:全部的/全局的) 表示全局模式,即模式将被应用在所有字符串中,而非在发现第一个匹配项时立刻停止(就是该字符串的全部字符都会寻找一遍)
- i:(ignore的简写,中文翻译为:忽视) 表示不区分大小写模式,即确定匹配项时忽略模式与字符串的大小写
- m:表示多行模式,即在到达一行文本末尾是还会继续查找下一行中是否存在与模式匹配的项
匹配字符串中所有“at”案例
var pattern = /at/g;
匹配第一个“bat”或“cat”,不区分大小写
var pattern = /[bc]at/g;
function函数
函数声明和函数表达式
解析器在向执行环境加载数据时,对函数声明和函数表达式并非一视同仁。
解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问)
函数表达式则要等到解析器执行到它所在的代码行,才会执行
alert(sum(10, 20)); //30
function sum(num1, num2) {
return num1 + num2;
}
以上代码正常运行,因为在执行之前,解析器有一个函数声明提升的过程。
读取并将函数声明添加到执行环境。将函数放置在源代码顶部
alert(sum1); //undefined
var sum1 = function(num1, num2) {
return num1 + num2;
}
以上代码出现错误,是在于函数位于一个初始化语句中,而不是一个函数声明,也就是说,
在执行到函数所在语句之前,变量sum不会保存对函数的引用。所以在函数之前调用就会导致undefined错误
函数属性和方法
每个函数都包含两个属性:length和prototype。
length属性
表示函数希望接收的命名参数的个数
function sayname(name) {
alert(name);
}
function sum(num1, num2) {
return num1 + num2;
}
function sayHi() {
alert('hi');
}
alert(sayname.length); //1
alert(sum.length); //2
alert(sayHi.length); //0
apply()属性和call()属性
以上两个属性的作用都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。
apply()
apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组,其中,第二个参数可以是Array实例,也可以是arguements对象
function sum(num1, num2) {
return num1 + num2;
}
function callnum1(num1, num2) {
return sum.apply(this, arguments);
}
function callnum2(num1, num2) {
return sum.apply(this, [num1, num2]);
}
alert(callnum1(10, 10)); //20
alert(callnum2(10, 10)); //20
在严格模式下,未指定环境对象而调用函数,则this值不会转型为window。除非明确把函数添加到某个对象或者调用apply()或call(),否则this值将会是undefined
call()函数
call()和apply()方法的作用相同,区别是接收参数的方式不同。对于call()方法来说,第一个参数是this值没有变化,变化的是其余参数都直接传递给函数。就是要把所有的参数逐个列举出来
传递参数并不是apply()和call()真正的作用,它们真正强大的地方是能够扩充函数赖以进行的作用域。
window.color = "red";
var o = {
color: "blue"
};
function saycolor() {
alert(this.color);
}
saycolor();//red
saycolor.call(this); //red
saycolor.call(window); //red
saycolor.call(o);//blue
bind()
这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。
window.color = "red";
var o = {
color: "blue"
};
function saycolor() {
alert(this.color);
}
var obj = saycolor.bind(o);
obj();//blue
Boolean类型
Boolean类型的实例重写了valueOf()方法,返回基本类型值true或false,重写了toString方法,返回字符串“true”和“false”。
var objectfalse = new Boolean(false);
var result = objectfalse && true;
alert(result); //true
var objectValue = false;
result = objectValue && true;
alert(result);//false
以上代码,第一行我们用false值创建了一个Boolean对象,将这个对象与基本类型值true构成了逻辑与表达式。但第二行代码是对objectfalse而不是对它的值(false)进行求值。所以因为objectfalse对象在布尔表达式中表达的是true,所以true && true 对于true