JS式JavaScript的简称,它是一门弱语言,它可以实现让网页动起来
JS的构成
- 核心(ECMAScript)
- 文档对象模型(DOM)-- Document Object Module
- 浏览器对象模型(BOM)-- Browser Object Module
**ECMAScript:是一种 由Ecma国际(前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言。这种语言在万维网上应用广泛,它往往被称为JavaScript或JScript,但实际上后两者是ECMA-262标准的实现和扩展 **
**BOM: Browser Object Model,提供与浏览器交互的方法和接口 **
**DOM: Document Object Model,提供访问和操作网页内容的方法和接口 **
Js的特点
JavaScript是一种脚本语言并且是一种基于对象和事件驱动的脚本语言。之所以要使用JavaScript不仅仅是因为JavaScript很安全,而且是因为它能与HTML、Java的Applet一起实现在一个web页面中连接多个对象,并与web客户交互作用,开发各种客户端的应用程序,满足人们的各种需求。JavaScript是通过嵌入或调入到标准的HTML语言中实现的,它的出现很好地填补了HTML的缺陷,是Java与HTML语言的桥梁。JavaScript有以下几个基本特点:
- JavaScript是一种脚本编程语言
这里要解释一下什么是脚本语言,也许很多读者之前已经接触过脚本语言,其实脚本语言是一种简单的程序,它是由一些ASCII字符构成,可以直接用记事本等文本编辑器编写,事先也不用编译,只需要利用解释器就可以解释执行。
前面已经介绍过JavaScript是一种脚本语言,是采用小程序段的方式实现编程。正如其它脚本语言一样,JavaScript也是一种解释性语言,它提供了一个容易的开发过程。JavaScript的基本结构形式与其它高级语言类似(如C、C++、VB、Delphi等),但它与这些高级语言不同的是,其它高级语言需要先进行编译然后才能被执行,JavaScript则是在程序运行过程中一条一条被解释执行。JavaScript与HTML结合在一起,极大地方便了用户的使用操作。
- JavaScript是面向对象的语言
JavaScript是一种面向对象的语言,那就是说,它本身也可以创建对象,以及调用对象的操作。因此,JavaScript的诸多功能可以来自于脚本环境中各种对象的调用。
- JavaScript的简单性
之所以说JavaScript是简单的,首先是因为它是一种基于Java的基本语句和控制流之上的简单而紧凑的设计,这对于更进一步学习Java是一个非常好的过渡,其次是因为它的所有变量都是弱类型,并且都没有像其它需要编译的高级语言那样使用严格的数据类型。
- JavaScrip的安全性
JavaScrip就像Java一样是一种非常安全的语言,它不允许访问本地的硬盘,并且不允许把数据存入到服务器上,还不允许对网络文档进行修改和删除,只允许通过浏览器实现信息浏览和动态交互,这样确保了对数据的安全化操作。
- JavaScript的动态性
之所以说JavaScript是动态的,是因为它可以直接对用户或客户的输入操作做出响应,而不必经过web服务器或web服务器程序。
JavaScript对用户的响应是采用事件驱动的方式进行的。简单地说,事件驱动是指在页面中执行了某种操作后产生相应的动作,例如,按下鼠标、选择菜单以及移动窗口等都可以被视为事件,当事件发生后,就会有相应的事件响应该事件。
- JavaScript的跨平台性
JavaScript同Java一样是与操作环境无关的,它只依赖于浏览器,只要客户的计算机浏览器支持JavaScrip,它就可以被正确解释执行。从而实现一次编写,到处运行。
综合以上特点,JavaScrip是一种全新的描述性语言,它可以完全被嵌入到HTML文档中运行。JavaScrip可以在不用任何的网络来回传输控制命令的前提下做到响应使用者的需求事件(如form的输入等)。因此当一个用户输入某一项资料时,它并不用经常传给服务端处理,再传回客户端的过程,而是可以直接被客户端的应用程序自己处理,节省了服务器处理时间。
JS的使用方式
- 行内式
直接在标签内来引入JS代码
<a href="javaScript:alert('你已经领取过了')">领取奖品</a>
<input type="button" value="点击有惊喜" onclick="alert('哈哈哈哈')">
- 内部式
使用<script></script>
标签,将代码写在标签内部
<script>
JavaScript 语言代码;
</script>
- 外部式
通过<script src = "地址"></script>
标签,来引入外部的JS代码,值得注意的是,此时标签内部的JS代码不会生效
<script src="./js/my.js"></script>//引入成功
<script src="./js/my.js">
console.log('此处的代码不会被显示')
</script>
- 嵌入和导入的数量不受限制;
JS的语法规范
标识符
- 标识符只能由数组、字母、下划线、$组成
- 不能以数字开头
- 区分大小写
- 不能是关键字和保留字
- 见名知意
- 小驼峰命名
var 1name;//不可以
var name;
var Name;//与name不同
var myName;//提倡
注释
//单行注释
/*
多行注释
*/
/*
*
* 这个也是多行注释
*
*/
空格
空格的位置不会影响代码的解析,但是不要将关键字或者标识符分开,适当的添加空格可以提高代码的可读性
var name = 123;
console . log ( '1 2 3' );
v ar name;//报错
var name = '王磊';
表达式
JS代码中的;
表示一句代码的结束,当然也可以省略,但是当遇到立即执行函数的情况下是不能省略的
var name = 12
console.log(123)
(function (){
console.log(123)
})();//这里一定要添加分号
var age = 18
JS输入输出方法
console
- console.log() 打印日志信息
- console.dir() 打印详细信息
- console.error() 打印错误信息
- console.warn() 打印警告信息
- console.table() 打印表格信息
window
- window.alter() 弹出警告框
- window.prompt() 获取用户输入
document
- document.write() 向页面写入信息
- document.querySelector() 获取页面元素
![](https://img-blog.csdnimg.cn/img_convert/2143eb139cd74b0c104691ea9d4bbaac.jpeg)
变量声明
在ES6以前我们通常通过var来声明变量。首先要进行变量声明,然后再进行使用
var num = 123;//声明变量num,并且赋值为123
var声明多个变量
var a = 10, b = 20, c;
console.log(delete c, delete b); // false false
console.log(a, b, c); // 10 20 undefined
// 通过逗号隔开的这种声明变量,表示a b c都是var声明的变量
var a = b = c = 10;
console.log(delete a, delete c, delete b); // false true true
console.log(a, b, c); // 10 b is not defined
// 通过声明变量赋值,此时只有a是var声明的,而c=10 b=c 都是没有var声明的 是直接赋值的
基本数据类型
Number
值
number包括整数、浮点数、Infinity和NaN(Not a Number)
方法
Number()
Number()方法会将内容转换为一个数字,如过转换不了会返回NaN
var num = 123;
console.log(Number(num));//123
var str1 = '456';
console.log(Number(str1));//456
var str2 = '你好';
console.log(Number(str2));//NaN
var str3 = '';
console.log(Number(str3));//0
var str4 = ' ';
console.log(Number(str4));//0
var botl = true;
console.log(Number(botl));//1
var bolf = false;
console.log(Number(bolf));//0
var und = undefined;
console.log(Number(und));//NaN
var nul = null;
console.log(Number(nul));//0
var obj = {};
console.log(Number(obj));//NaN
var arr1 = [];
console.log(Number(arr1));//0
var arr2 = [123];
console.log(Number(arr2));//123
var arr3 = ['123'];
console.log(Number(arr3));//123
- 对于boolean类型来说,true和false会对应转变为1和0
- 对于字符串类型来说,会直接忽略引号提取内容,如果是数值,会返回数值,如果没有内容(空/空格),返回0,否则返回NaN
- 对于引用数据类型来说,会首先调用valueOf()方法,如果不能得到数字,再调用String()方法,如果不能得到数字,则返回NaN,例如{}返回’[object Object]';[]->[]->0
isNaN()
isNaN()方法用来检测是不是一个数值,如果是返回false,如果不是返回true
console.log(isNaN(1)); // false
console.log(isNaN(' ')); // false
console.log(isNaN(function () {})); // true
console.log(isNaN('#111')); // true
console.log(isNaN(' 999 ')); // false
console.log(isNaN([])); // false
console.log(isNaN([100])); // false
console.log(isNaN([1, '9'])); // true
console.log(isNaN({})); // true
console.log(isNaN('66 ,')); // true
isNaN方法会首先调用Number()方法,如果能转为数值,isNaN()返回false,如果不能,返回true
isFinite()
isFinite()方法用来检测是不是一个有限的数值
console.log(isFinite(Infinity)); // false
console.log(isFinite(-Infinity)); // false
console.log(isFinite(199999)); // true
console.log(isFinite(' ')); // true
console.log(isFinite(NaN)); // false
console.log(isFinite([1, '9']));false
parseInt()
parseInt()方法用来将变量解析为整数
转换时使用的基数(即多少进制,可选值2/8/10/16)。如果知道要解析的值是十六进制格式的字符串,那么指定基数 16 作为第二个参数,可以保证得到正确的结果,不指定基数意味着让 parseInt()决定如何解析输入的字符串,因此为了避免错误的解析,我们建议无论在什么情况下都明确指定基数。第二个参数不传或为假值时,并且第一个参数没有明确的进制标志如:0x,则默认按10进制处理
console.log(parseInt('')); // NaN
console.log(parseInt(' ')); // NaN
console.log(parseInt(' ')); // NaN
console.log(parseInt('0')); // 0
console.log(parseInt(' 9 ')); // 9
console.log(parseInt(' 9')); // 9
console.log(parseInt('9 ')); // 9
console.log(typeof parseInt('9.99 ')); // 9 'number'
console.log(parseInt('9.9&9 ')); // 9
console.log(parseInt(' %9.9&9 ')); // NaN
console.log(parseInt(' 9.9 9 ')); // 9
console.log(parseInt(' 998 9 ')); // 998
console.log(parseInt(9.888));9
console.log('' * 100); // 0
var num = parseInt("0xAF", 16); // 175
var num1 = parseInt("123",16) // 1*16^2+2*16+3
var num1 = parseInt("AF", 16); // 175
var num2 = parseInt("AF"); // NaN
- 解析将第一个非数字字符之前的数字字符,转换为对应的数字字面值并取整
- 解析纯数字字符串 返回对应数字字面值并取整
- 忽略前面的空格中间的空格不能忽略
parseFloat()
parseFloat()方法用来将变量解析为浮点数
- 字符串中的第一个小数点是有效的,而第二个小数点就是无效的了,因此它后面的字符串将被忽略
"22.34.5"将会被转换为 22.34。 - parseFloat()始终都会忽略前导的零。( parseFloat()只解析十进制值,因此它没有用第二个参数指定基数的用法)
- parseFloat()可以识别前面讨论过的所有浮点数值格式,也包括十进制整数格式。
- 十六进制格式的字符串则始终会被转换成 0。
- 如果字符串包含的是一个可解析为整数的数(没有小数点,或者小数点后都是零) , parseFloat()会返回整数。以下是使用 parseFloat()转换数值的几个典型示例。
console.log(parseFloat('')); // NaN
console.log(parseFloat(' ')); // NaN
console.log(parseFloat(' ')); // NaN
console.log(parseFloat('0')); // 0
console.log(parseFloat(' 9 ')); // 9
console.log(parseFloat(' 9')); // 9
console.log(parseFloat('9 ')); // 9
console.log(typeof parseFloat('9.99 ')); // 9 'number'
console.log(parseFloat('9.9&9 ')); // 9.9
console.log(parseFloat(' %9.9&9 ')); // NaN
console.log(parseFloat(' 9.9 9 ')); // 9.9
console.log(parseFloat(' 998 9 ')); // 998
console.log(parseFloat(9.888));//9.888
console.log('' * 100); // 0
var num1 = parseFloat("1234blue"); //1234
var num2 = parseFloat("0xA"); //0
var num3 = parseFloat("22.5"); //22.5
var num4 = parseFloat("22.34.5"); //22.34
var num5 = parseFloat("0908.5"); //908.5
var num6 = parseFloat("3.125e7"); //31250000
toFixed()
toFixed()用来保留小数,toFixed(数值,小数位数)
var num = 9.88;
console.log(num.toFixed(1));//9.9
console.log(num.toFixed(2));//9.88
String
值
- 单引号是无法换行 反引号是可以换行
- 变量拼接 单双引号用+ 反引号直接输出对应的字符串 变量用${变量名}
单引号
var str = '大家好';
双引号
var str = "大家好"
反引号
var name = '李悦',
from = '贵州',
address = '凯德广场';
// 我是李悦,我来自贵州,我现在住在凯德广场
console.log('我是' + name + ',我来自' + from + ',我现在住在' + address);
console.log(`我是${name},我来自${from},我现在住在${address}`);
方法
String()
将转型函数String()应用于像数字这种拥有toString()方法的数据类型时,底层会自动调用toString()方法。
console.log(String(null))//'null'
console.log(String(undefined))//'undefined'
toString()
转为字符串
- null undefined没有toString()方法
console.log(11.toString());//'11'
console.log(typeof (11).toString());//'number'
console.log(NaN.toString());//'NaN'
console.log(Infinity.toString());//'Infinity'
console.log((-Infinity).toString());//'-Infinity'
console.log((+0).toString());//'0'
console.log((-0).toString());//'0'
console.log((-9999).toString());//'-9999'
console.log((+9999).toString());//'9999'
console.log(true.toString());//'true'
console.log(false.toString());//'false'
var obj = {},arr = [100, 800];
function fn() {};
console.log(obj.toString(), arr.toString(), fn.toString());//'[object Object]' '100,800' 'function fn() {}'
toUpperCase()
英文大写
var str = 'AbcdRfg';
console.log(str.toUpperCase()); // 所有字符全部大写
toLowerCase()
英文小写
var str = 'AbcdRfg';
console.log(str.toLowerCase()); // 所有字符全部小写
toLocaleUpperCase()
本地小众语言大写
var str = 'AbcdRfg';
console.log(str.toLocaleUpperCase());
toLocaleLowerCase()
本地小众语言大写
var str = 'AbcdRfg';
console.log(str.toLocaleLowerCase());
indexOf()
_str.indexOf(searchStr, fromIndex) _
可返回某指定子字符串 在字符串中首次出现位置的下标
searchStr要查找的子字符串(必须), fromIndex从哪个下标位置开始查找(可选)
返回值:下标 如果没有查到 返回-1
var str = 'html,css,js,css';
console.log(str.indexOf('css')); // 5
lastIndexOf()
str.lastIndexOf(searchStr, fromIndex)方法与str.indexOf完全一样,唯一的区别在于查找时:
前者是从右往左查,返回的是子字符串的首字符在父字符串中最后一次出现的位置。后者是从左往右查,返回的是子字符串的首字符在父字符串中首次出现的位置。
var str = 'html,css,js,css';
console.log(str.lastIndexOf('css')); // 12
charAt()
返回指定位置的字符
var str = 'charAt';
console.log(str.charAt(0));
console.log(str.charAt(str.length - 1));
charCodeAt()
返回指定位置的字符ASCII码
var str = 'charAt';
console.log(str.charCodeAt(0)); // 99
fromCharCode()
返回指定的ASCII码对应的字符
console.log(String.fromCharCode(99)); //c
trim()
去除前后空格
var str = ' 1 11 ';
console.log(str.trim());//'111'
substring()
str.substring(start, end) [start, end)
参数 | 描述 |
---|---|
start | 必需。一个非负的整数,规定要提取的子串的第一个字符在 stringObject 中的位置。 |
end | 可选。一个非负的整数,比要提取的子串的最后一个字符在 stringObject 中的位置多 1。如果省略该参数,那么返回的子串会一直到字符串的结尾。 |
- 返回一个新的字符串(原字符串不变),其内容是从 start(包含) 处到 end(不包含)处的所有字符,其长度为 end减 start
- 如果参数 start 与 end相等,那么该方法返回的就是一个空串(即长度为 0 的字符串)。
- 如果 start 比 end大,那么该方法在提取子串之前会先交换这两个参数。
- stringObject.substring() 不接受负的参数。
- 第二个参数为可选值,不传则从开始一直截取到末尾
- 字符串只能从左往右进行截取
var str = 'top,middle,bottom';
console.log(str.substring()); // top,middle,bottom
console.log(str.substring(0)); // top,middle,bottom
console.log(str.substring(0, 3));
console.log(str.substring(3, 0)); // top
console.log(str.substring(3, 3)); // ''
console.log(str.substring(-4, -3)); // ''
slice()
参数 | 描述 |
---|---|
start | 必需。一个整数(接受负数),规定要提取的子串的第一个字符在 stringObject 中的位置。 |
stop | 可选。一个整数(接受负数),如果省略该参数,那么返回的子串会一直到字符串的结尾。 |
- 返回一个新的字符串(原字符串不变),其内容是从 start(包含) 处到 end(不包含) 处的所有字符,其长度为 end减 start
- 函数从尾部索引时是从-1开始,倒数第二个位置是-2,以此类推。
- start与end的位置不能自动交换
- 字符串只能从左往右进行截取
var str = 'left,center,right';
console.log(str.slice()); // left,center,right
console.log(str.slice(0)); // left,center,right
console.log(str.slice(5)); // center,right
console.log(str.slice(0, 4)); // left
console.log(str.slice(4, 0)); // ''
console.log(str.slice(5, -2)); // center,rig
console.log(str.slice(-2, -4)); // ''
substr()
参数 | 描述 |
---|---|
start | 必需。一个整数(接受负数),规定要提取的子串的第一个字符在 stringObject 中的位置。 |
length | 可选。要接收的子字符串的长度,如果省略该参数,那么返回的子串会一直到字符串的结尾。 |
- 返回一个新的字符串(原字符串不变),其内容是从 start(包含)开始,截取长度为length。
- 函数从尾部索引时是从-1开始,倒数第二个位置是-2,以此类推。
- 字符串只能从左往右进行截取
var str = 'size,style,weight';
console.log(str.substr()); // size,style,weight
console.log(str.substr(0)); // size,style,weight
console.log(str.substr(5)); // style,weight
console.log(str.substr(5, 5)); // style
console.log(str.substr(-5, 5)); // eight
Boolean
值
Boolean类型只有两个值true和false
方法
Boolean()
Boolean() 转型函数: 将其他类型转为布尔类型 ,结果为false的情况:+0 -0 NaN ‘’ udnefined null
console.log(Boolean(1));
console.log(Boolean(NaN)); // false
console.log(Boolean(1.99));
console.log(Boolean(-1.99));
console.log(Boolean(-999));
console.log(Boolean(-0)); // false
console.log(Boolean(+0)); // false
console.log(Boolean('')); // false
console.log(Boolean(' '));
console.log(Boolean('0'));
console.log(Boolean('NaN'));
console.log(Boolean('111'));
console.log(Boolean(' '));
console.log(Boolean(' 2 '));
console.log(Boolean(undefined)); // false
console.log(Boolean(null)); // false
var s = [];
var s1 = [100, 200];
var d = {};
var d1 = { name: '11' };
function f() {}
console.log(Boolean(s)); // true
console.log(Boolean(s1)); // true
console.log(Boolean(d)); // true
console.log(Boolean(d1)); // true
console.log(Boolean(f)); // true
Undefined
Undefined 类型只有一个值,即特殊的 undefined。
undefined的情况:
- 定义变量没有赋值
- 函数没有返回值
- 访问对象不存在的属性/方法
- typeof未声明的变量
null
Null类型只有一个值,即特殊的null
alert(null == undefined); //true,仅做判断不做字符串连接时
null 和 undefined 之间的相等操作符(==)总是返回 true,不过要注意的是,这个操作符出于比较的目的会转换其操作数
无论在什么情况下都没有必要把一个变量的值显式地设置为undefined,可是同样的规则对 null 却不适用。换句话说,只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存 null 值。这样做不仅可以体现 null 作为空对象指针的惯例,而且也有助于进一步区分 null 和 undefined。
null和undefined的区别
•null
用来描述空值
– typeof null:返回的是字符串object;
– 通常来讲我们把null看成他自有类型的唯一成员;
•undefined
声明变量未赋值的系统默认状态
– undefined表明只声明了变量没有赋值;
– 如果函数没有返回值,则返回undefined;
– 如果取对象中不存在的属性,则返回undefined;
– 如果取稀疏数组的empty,则返回undefined;
– typeof undefined:返回的是字符串undefined;
– ==认为NULL和undefined是相等的;===则返回false;
- 概念:null是空值 代表空 什么都没有 undefined是没有初值情况下 系统默认给的初始状态
- typeof null—object,typeof undefined: undefined
- 相等:null==undefined 不相等:null === undefined
- 出现的情况不一样
typeof()方法
typeof()用于检测数据类型,操作符可能返回下列某个字符串,()可省略后直接跟值。
- “undefined”——如果这个值未定义;
- “boolean”——如果这个值是布尔值;
- “string”——如果这个值是字符串;
- “number”——如果这个值是数值;
- “object”——如果这个值是对象或 null;
- “function”——如果这个值是函数。
var message = "some string";
console.log(typeof message); //"string"
console.log(typeof(message)); //"string"
引用数据类型
Object
基本操作
声明
var o = new Object;//var o={}
//为实例添加属性并赋值
o.name = "张三";
o.age = 24;
var person = {
name:'张三',
age:24,
say:function(){
console.log('我要讲两句了');
}
}
使用
- 通过点(.)访问对象的属性:person.name;
- 通过点(.)访问对象的方法:person.say();
- 通过[‘属性名’]访问对象的属性:person[‘name’];
- 通过’方法名’访问对象的方法:person’say’;
var person = {
name:'张三',
age:24,
say:function(){
console.log('我要讲两句了');
}
}
console.log(person.name);
console.log(person.say());
console.log(person['name']);
console.log(person['say']());
修改
var person = {
name:'张三',
age:24,
say:function(){
console.log('我要讲两句了');
}
}
person.name = '李四'
删除
var person = {
name:'张三',
age:24,
say:function(){
console.log('我要讲两句了');
}
}
delete person.name;
包装
显示包装对象
通过内置的构造器(Object,Array,Function)来创建一个对象
var num = new Number(1);
var str = new String('字符串');
var bl = new Boolean(true);
console.log(num, str, bl);
隐式包装对象
隐式包装对象又称为临时包装对象,通过基本数据类型构造器(Number、String、Boolean)来构造一个对象。
当基础数据类型使用对象的点语法的时候,底层自动将其包装称为对象 供我们去使用点语法调用函数 调用方法
- Undefined和Null没有构造器
显示包装和隐式包装的区别
隐式包装对象一旦属性引用结束,这个新创建的对象就会被销毁。
方法
in
使用in来判断对象本身或者原型链上是否有某个属性
var obj = { name: 'dahai', age: 19 };
var propName = 'name';
console.log('name' in obj);
console.log(propName in obj);
console.log('xxxqqq' in obj); // false
console.log('toString' in obj);
console.log('hasOwnProperty' in obj); // 只要对象本身或者原型链上有这个属性 就返回true
console.log(obj);
for in
通常我们习惯使用for in
来遍历数组和对象,key取值为键名
var obj1 = {
namess: '惊雷11111',
times: '4min',
zuocis: 'xxx',
zuoqus: 'zzz',
singesr: 'ww'
};
for (key in obj1) {
console.log(key);
console.log(obj1[key]); // obj.name obj.time obj.zuoci
}
for of
key为键值
var obj1 = {
namess: '惊雷11111',
times: '4min',
zuocis: 'xxx',
zuoqus: 'zzz',
singesr: 'ww'
};
for (key in obj1) {
console.log(key);//'惊雷11111''4min''xxx''zzz''ww'
}
set和get
var myAge = 18;
var obj = {
name: 'dahai',
// myAge: 18,
get age() {
return myAge + 1;
// return obj.age + 1;
},
set age(v) {
myAge = v;
// obj.age = v;
}
};
// obj.age; ===> obj.myAge + 1;
// 所谓访问对象的属性 就是取对象属性的值
// obj.name
console.log(obj.age); // 访问触发get方法 访问的结果就是get方法的返回值
obj.age = 90; // 设置会触发set方法 设置给myAge属性
console.log(obj.age); // 91
instanceOf
检查左侧的对象是否是右侧类的实例,如果是返回true;
如果一个对象是一个“父类”的子类的实例,则一样返回true;
var str = new String('11'); // str为String的实例对象
console.log(str instanceof String); // true
console.log(str instanceof Object); // true
console.log(str);
valueOf()
- JavaScript 中的 valueOf() 方法用于返回指定对象的原始值,若对象没有原始值,则将返回对象本身。通常由JavaScript内部调用,而不是在代码中显式调用。
var o = {
valueOf: function(){
return -1;
}
};
o = +o;
// valueOf()方法通常由JavaScript内部调用,而不是在代码中显式调用。
- 默认情况下,valueOf 方法由 Object 后面的每个对象继承。 每个内置的核心对象都会覆盖此方法以返回适当的值。
- JavaScript 的许多内置对象都重写了该函数,以实现更适合自身的功能需要。因此,不同类型对象的 valueOf() 方法的返回值和返回值类型均可能不同。
- 不同类型对象的 valueOf() 方法的返回值:
Array:返回数组对象本身。
Boolean: 返回布尔值
Date:存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。
Function: 返回函数本身。
Number: 返回数字值。
Object:返回对象本身。这是默认情况。
String:返回字符串值。
Math 和 Error 对象没有 valueOf 方法。
- 实例:
// Array:返回数组对象本身
var array = ["ABC", true, 12, -5];
console.log(array.valueOf() === array); // true
// Date:返回当前时间距1970年1月1日午夜的毫秒数
// Sun Aug 18 2013 23:11:59 GMT+0800 (中国标准时间)
var date = new Date(2013, 7, 18, 23, 11, 59, 230);
console.log(date.valueOf()); // 1376838719230
// Number:返回数字值
var num = 15.26540; // 15.2654
num.valueOf() // 15.2654
console.log(num.valueOf() === num); // true
// 布尔:返回布尔值true或false
var bool = true;
console.log(bool.valueOf() === bool); // true
// new一个Boolean对象
var newBool = new Boolean(true); // Boolean {true}
newBool.valueOf() // true
// valueOf()返回的是true,两者的值相等
console.log(newBool.valueOf() == newBool); // true
// 但是不全等,两者类型不相等,前者是boolean类型,后者是object类型
console.log(newBool.valueOf() === newBool); // false
// Function:返回函数本身
function foo(){}
console.log( foo.valueOf() === foo ); // true
var foo2 = new Function("x", "y", "return x + y;");
console.log( foo2.valueOf() === foo2); // true
/*
ƒ anonymous(x,y) {
return x + y;
}
*/
// Object:返回对象本身
var obj = {name: "张三", age: 18};
console.log( obj.valueOf() === obj ); // true
// String:返回字符串值
var str = "http://www.xyz.com";
console.log( str.valueOf() === str ); // true
// new一个字符串对象
// String {"http://www.xyz.com"}
var str2 = new String("http://www.xyz.com");
str2.valueOf() // "http://www.xyz.com"
// 两者的值相等,但不全等,因为类型不同,前者为string类型,后者为object类型
console.log( str2.valueOf() === str2 ); // false
基本数据类型和引用数据类型的区别
- 基本数据类型:number、string、boolean、undefined、null
- 引用数据类型:object
区别:
- 基本数据类型会在栈内存中开辟空间,存储变量名和值;引用数据类型会在栈内存和堆内存中都开辟空间,栈内存中保存变量名和值的地址,真正的值则是存在堆内存中。
- 原始值在做==比较时,比较值相等,引用类型判断引用空间的地址是否相同
- 赋值为原始数据时,是赋值右边的值,赋值为引用数据时,是赋值右边的地址
var name = '王磊';
var obj = {
name:'王磊'
}
隐式转换
两种类型的变量在进行运算或比较时,一种类型会向类一种进行转化,然后再进行比较和运算
加法
- 作为算数运算符 (除string类型外的原始数据类型进行加法运算时)非数字类型,会转为数字类型,通过Number()方法
- 作为字符串连接符(有一个操作数string类型以及引用数据类型时)
减法|乘法|除法
- 非数字类型会转为数字类型
- 如果是原始数据类型会调用Number()方法进行转换
- 如果是引用数据类型会调用自身valueOf方法进行转换,如果转换后不是原始值,则会调用toString方法进行转换,如果转换后不是数字,则会调用Number()进行转换,如果转换后不是数字则会返回NaN。
算数运算符
规则:
- 非数字基础数据类型:在后台调用 Number()将其转换为数值,然后再应用上面的规则。
- 引用数据类型:先调用valueOf() 得到的值无法计算再toString(),然后将toString()方法得到的结放Number()中转换
- NaN与任何数字进行算数运算返回值都为NaN
- 布尔值会转换为1/0
+
- 如果是 Infinity 加 Infinity,则结果是 Infinity;
- 如果是-Infinity 加-Infinity,则结果是-Infinity;
- 如果是 Infinity 加-Infinity,则结果是 NaN;// Infinity +(- Infinity )=NaN
- 如果是+0 加+0,则结果是+0;
- 如果是-0 加-0,则结果是-0;
- 如果是+0 加-0,则结果是+0。//+0-0=+0
如果有一个操作数是字符串,那么就要应用如下规则:
- 如果两个操作数都是字符串,则将第二个操作数与第一个操作数拼接起来;
- 如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接起来;如果有一个操作数是对象、数值或布尔值,则调用它们的 toString()方法取得相应的字符串值,然后再应用前面关于字符串的规则。对于 undefined 和 null,则分别调用 String()函数并取得字符串"undefined"和"null"。
var result = true + false; //1
var result0 = 5 + false; //5
var result1 = 5 + true; //6
var result2 = NaN + 1; //NaN
var result3 = 5 + 3; //8
var result4 = 5 + ''; //'5'
var result5 = 5 + '2';//'52'
var result6 = 5 + null; //5
var result7 = {} + 1; //[object Object]1
var result8 = [] + 1;//'1'
var result9 = undefined + '999';//'undefined999'
var result10 = null + '123456';//'null123456'
var result11 = [] + [];//''
var result12 = [] + {};//'[object Object]'
var result13 = {} + {};//'[object Object][object Object]'
- 加法操作都应优先将操作数转为数字进行运算,转换不成功则为NaN
- 如果涉及到有操作数为字符串,则应将另一操作数转为字符串再进行拼接
- 如果涉及到对象,调用toString() 转为字符串后再运算
-
- 如果有一个操作数是 NaN,则结果是 NaN;
- 如果是 Infinity 减 Infinity,则结果是 NaN;//infinity-infinity=NaN
- 如果是-Infinity 减-Infinity,则结果是 NaN;
- 如果是 Infinity 减-Infinity,则结果是 Infinity;
- 如果是-Infinity 减 Infinity,则结果是-Infinity;
- 如果是+0 减+0,则结果是+0;
- 如果是+0 减-0,则结果是+0;
- 如果是-0 减-0,则结果是+0;
- 如果是-0 减+0,则结果是-0;
var result1 = 5 - true; //4
var result2 = NaN - 1; //NaN
var result3 = 5 - 3; //2
var result4 = 5 - ''; //5
var result5 = 5 - '2';//3
var result6 = 5 - null; //5
var result7 = {} - 1;//NaN
var result8 = [] - 1;//-1
var result9 = new Date() - 1;//时间戳-1
*
乘法操作符由一个星号(*)表示,用于计算两个数值的乘积。
- 如果有一个操作数是 NaN,则结果是 NaN;
- 如果是 Infinity 与 0 相乘,则结果是 NaN;// Infinity*0=NaN
- 如果是 Infinity 与非 0 数值相乘,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
- 如果是 Infinity 与 Infinity 相乘,则结果是 Infinity
console.log(NaN * 1);//NaN
console.log(NaN * Infinity);//NaN
console.log(NaN * (-Infinity));//NaN
console.log(Infinity * (-Infinity)); //-Infinity
console.log(Infinity * Infinity); //Infinity
console.log(Infinity * 1); //Infinity
console.log(Infinity * (-1)); //-Infinity
console.log((-Infinity) * (-1)); //Infinity
console.log((-Infinity) * 1); //-Infinity
console.log(1 * {});//NaN
console.log(1 * []); //0
console.log(1 * [100]); //100
console.log(1 * { q: 1 }); //NaN
/
除法操作符由一个斜线符号(/)表示,执行第二个操作数除第一个操作数的计算
- 如果有一个操作数是 NaN,则结果是 NaN;
- 如果是 Infinity 被 Infinity 除,则结果是 NaN; // Infinity / Infinity = NaN
- 如果是零被零除,则结果是 NaN;
- 如果是非零数被零除,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
- 如果是 Infinity被任何数值除,则结果是Infinity 或-Infinity,取决于有符号操作数的符号;// Infinity/0=Infinity
console.log(NaN / 1);//NaN
console.log(NaN / Infinity);//NaN
console.log(NaN / (-Infinity));//NaN
console.log(Infinity / (-Infinity)); // NaN
console.log(Infinity / Infinity); // NaN
console.log(0 / 0); // NaN
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log(Infinity / 1); // Infinity
console.log(Infinity / (-1)); // -Infinity
console.log((-Infinity) / (-1)); // Infinity
console.log((-Infinity) / 1); // -Infinity
console.log(1 / {}); // NaN
console.log(1 / []); // Infinity
console.log(1 / [100]); // 0.01
console.log(1 / { q: 1 }); // NaN
%
取余操作符由一个百分号(%)表示
- 如果被除数是无穷大值Infinity 而除数是有限大的数值,则结果是 NaN;// Infinity%?=NaN
- 如果被除数是有限大的数值而除数是零,则结果是 NaN;// 5%0=NaN
- 如果是 Infinity 被 Infinity 除,则结果是 NaN; // Infinity % Infinity = NaN
- 如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数; // 5%Infinity = 5
- 如果被除数是零,则结果是零;// 0%1
console.log(Infinity % 0); // NaN
console.log(-Infinity % 0); // NaN
console.log(Infinity % 1); // NaN
console.log(999 % 0); // NaN
console.log(0 % 0); // NaN
console.log(Infinity % Infinity); // NaN
console.log(888 % Infinity); // 888
console.log(0 % 9); // 0
console.log(0 % Infinity); // 0
console.log(0 % (-Infinity)); // 0
console.log(0 % {}); // NaN
console.log(Infinity % {}); // NaN
console.log(Infinity % []); // NaN
console.log([] % Infinity); // 0
console.log([100] % Infinity); // 100
console.log({} % Infinity); // NaN
关系运算符
关系运算符的返回值为Boolean类型,常见的关系运算符为>、<、=、!=、>=、<=、、=
比较规则
- 如果两个操作数都是数值,则执行数值比较。
console.log(2 > 0);
console.log(2 < 0);
console.log(2 > NaN);
console.log(2 > Infinity);
console.log(2 > (-Infinity));
console.log(NaN < NaN);
- 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值。
console.log('abc' < 'abd');
var str = 'cd';
console.log(str.charCodeAt(0));
console.log(str.charCodeAt(1));
console.log('abc' > 'abd');
- 任何操作数与NaN 进行关系比较,结果都是false
console.log({} < NaN);
console.log([] > NaN);
console.log('' < NaN);
console.log(1 > NaN);
console.log(true < NaN);
console.log(undefined < NaN);
console.log(null > NaN);
- 如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较。
console.log(1 > {});
console.log(1 > []);
console.log(1 > [33]);
console.log(1 < undefined);
console.log(1 > null);
console.log(1 > '111');
console.log(1 > '111%');
- 如果操作数是对象,则这个对象将先使用valueOf()转换成原始值,如果结果还不是原始值,则再使用toString()方法转换;在对象转换为原始值之后
- 如果两个操作数都是字符串,则按照字母表的顺序对两个字符串进行比较。
console.log('a' < {});
2. 如果至少有一个操作数不是字符串,则两个操作数都转换成数字进行比较。
console.log(true < {});
console.log(true > []);
- 如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较。
console.log(true < '12')
console.log(true < []);
console.log(true < {});
在使用关系操作符比较两个字符串时,会执行一种奇怪的操作。很多人都会认为,在比较字符串值时,小于的意思是“在字母表中的位置靠前”,而大于则意味着“在字母表中的位置靠后”,但实际上完全不是那么回事。在比较字符串时,实际比较的是两个字符串中对应位置的每个字符的字符编码值。经过这么一番比较之后,再返回一个布尔值。由于大写字母的字符编码全部小于小写字母的字符编码,因此我们就会看到如下所示的奇怪现象:
var result = "Brick" < "alphabet";
在这个例子中,字符串"Brick"被认为小于字符串"alphabet"。原因是字母 B 的字符编码为 66,而字母 a 的字符编码是 97。如果要真正按字母表顺序比较字符串,就必须把两个操作数转换为相同的大小写形式(全部大写或全部小写),然后再执行比较,如下所示:
var result = "Brick".toLowerCase() < "alphabet".toLowerCase();
、=!与=
- 如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false 转换为 0,而true 转换为 1;
- 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;
- 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,toString()用得到的基本类型值按照前面的规则进行比较;
- null 和 undefined 是相等的。
- 要比较相等性之前,不能将 null 和 undefined 转换成其他任何值(null == 0为false)。
- 如果有一个操作数是 NaN,则相等操作符返回 false,而不相等操作符返回 true。
- 如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回 true;否则,返回 false。
[] == '0'; // false 将[]转为字符串再与'0'比较
{} == '[object Object]'; // true 将{}转为字符串再与'[object Object]'比较
[] == 0; // true 将[]转为数字再与0作比较
[] == true; // false
// '' == 1 ---> 0 == 1
[] == false; // true
// '' == false ---> '' == 0 ---> 0 ==0
'abc' == true; 'abc' == 1 NaN == 1
console.log(1 == true);
console.log(1 == false);
console.log(true == true);
console.log('111' == '11');
console.log('whr' == 'w hr');
console.log(null == undefined); // true 规定
console.log(false == undefined); // false
console.log(null == 0); // false *****要比较相等性之前,不能将 null 和 undefined 转换成其他任何值
console.log(null == null);
console.log(undefined == undefined);
console.log(NaN == NaN);
console.log(NaN.toString() == NaN.toString());
console.log(NaN != NaN);
除了在比较之前不转换操作数之外,全等和不全等操作符与相等和不相等操作符没有什么区别。全等操作符由 3 个等于号(===)表示,它只在两个操作数未经转换就相等的情况下返回 true,如下面的例子所示:
var result1 = ("55" == 55); //
var result2 = ("55" === 55); //
不全等操作符由一个叹号后跟两个等于号(!==)表示,它在两个操作数未经转换就不相等的情况下返回 true。例如:
var result1 = ("55" != 55);
var result2 = ("55" !== 55);
记住: null == undefined 会返回 true,因为它们是规定;但 null === undefined 会返回 false,因为它们是不同类型的值。
由于相等和不相等操作符存在类型转换问题,为了保持代码中数据类型的完整性,推荐使用全等和不全等操作符。
console.log('5' == 5);
console.log('5' === 5);
console.log(5 === 5);
console.log('5' !== 5);
console.log('5' != 5);
console.log(null === undefined);
// 注意:全等之引用类型
console.log(11 === 11); // 比较值相等 并且类型相同
console.log({} == {}); // false
console.log({} === {}); // false 引用类型全等 类型一样 引用地址也得一样
var obj1 = {};
var obj2 = obj1;
console.log(obj1 == obj2); // true
console.log(obj1 === obj2); // true
递增递减运算符
和–表示对变量的+1和-1操作,但是和–的相对于变量的位置是有区别的
var age = 29;
console.log(age++);//++在后,先使用变量再自加
console.log(++age);//++在前,先变量自加再使用
var age = 29;
var anotherAge = --age + 2;//29-1+2=28+2
alert(age); //28
alert(anotherAge); //30
var num1 = 2;
var num2 = 20;
var num3 = --num1 + num2;//2-1+20=1+20
var num4 = num1 + num2;//1+20
var num1 = 2;
var num2 = 20;
var num3 = num1-- + num2;//2+20
var num4 = num1 + num2; //1+20
var a = 2;
var b = 3;
var c = (++a) + (b++) + b + (a++) - a;//(2+1)+(3)+4+(3)-4=9
- 在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减 1 的操作。字符串变量变成数值变量。
- 在应用于一个不包含有效数字字符的字符串时,将变量的值设置为 NaN。字符串变量变成数值变量。
- 在应用于布尔值 false 时,先将其转换为 0 再执行加减 1 的操作。布尔值变量变成数值变量。
- 在应用于布尔值 true 时,先将其转换为 1 再执行加减 1 的操作。布尔值变量变成数值变量。
- 在应用于浮点数值时,执行加减 1 的操作。
- 在应用于对象时,先调用对象的 valueOf()方法(后面章节将详细讨论)以取得一个可供操作的值。然后对该值应用前述规则。如果结果是 NaN,则在调用 toString()方法后再应用前述规则。对象变量变成数值变量。
var s1 = " 2";//2
var s2 = "z";//NaN
var b = false;//0
var f = 2.1;//2.1
var o = {
valueOf: function() {
return -1;
}
};
console.log(s1++); //2
console.log(s1); //3
++s2;//NaN
console.log(s2);//NaN
console.log(b++);//0
console.log(b);//1
f--; //2.1
console.log(f--);//1.1
console.log(f);//0.1
o--; //-1
console.log(o--);//-2
console.log(o);//-3
逻辑运算符
逻辑非
逻辑非操作符由一个叹号(!)表示,可以应用于 ECMAScript 中的任何值。无论这个值是什么数据类型,这个操作符都会返回一个布尔值。
alert(!false); //true
alert(!"blue"); //false
alert(!0); //true
alert(!NaN); //true
alert(!""); //true
alert(!12345);//false
同时使用两个逻辑非操作符,也可以用于将一个值转换为与其对应的布尔值,,如下面的例子所示:
alert(!!"blue"); // true
alert(!!0); // false
alert(!!NaN); // false
alert(!!""); // false
alert(!!12345); // true
逻辑与 (遇到假值阻塞)
逻辑与操作符由两个和号(&&)表示,有两个操作数,如下面的例子所示:
var result = true && false;
逻辑与操作属于短路操作,即如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值。对于逻辑与操作而言,如果第一个操作数是 false,则无论第二个操作数是什么值,结果都不再可能是true 了。
**遇到假值阻塞:**表达式从左到右一一判断,若是假值(false),停止判断,返回假值;若没有假值,则返回最后一个真值。
console.log('' && 3); // ''
console.log(9 && 3); // 3
console.log({} && ''); // ''
console.log({} && [] && 8 && new Number() && NaN); // NaN
逻辑或 (遇到真值阻塞)
逻辑或操作符由两个竖线符号(||)表示,有两个操作数,如下面的例子所示:
var result = true || false;
与逻辑与操作符相似,逻辑或操作符也是短路操作符。也就是说,如果第一个操作数的求值结果为true,就不会对第二个操作数求值了。下面看一个例子:
console.log('' || 3); // 3
console.log(9 || 3); // 9
console.log({} || ''); // {}
console.log('' || 0 || false || NaN || undefined || null); // null
**遇到真值阻塞:**表达式从左到右一一判断,若是真值(true),停止判断,返回真值;若没有真值,则返回最后一个假值。
var c = (a = 3) || (b = 4);//返回3
console.log(a);//3
console.log(b);//报错
console.log(c);//3
var c = (a = 0) || (b = 4);//返回4
console.log(a);//0
console.log(b);//4
console.log(c);//4
5 && 6 && 8 && '' && 0 || 1;//''||1 1
5 && 6 && 8 && '' && 0;//''
'' || 2 && 3 || '';//2&&3||'' 3||'' 3
一元加减运算符
一元加操作符以一个加号(+)表示,放在数值前面,对数值不会产生任何影响,如下面的例子所示:
var num = 25;
num = +num; // 仍然是 25
不过,在对非数值应用一元加操作符时,该操作符会像 Number()转型函数一样对这个值执行转换。
var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
}
};
s1 = +s1; // 1
s2 = +s2; // 1.1
s3 = +s3; // NaN
b = +b; // 0
f = +f; // 1.1
o = +o; // -1
一元减操作符主要用于表示负数,例如将 1 转换成-1。下面的例子演示了这个简单的转换过程:
var num = 25;
num = -num; //-25
var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
}
};
s1 = -s1; // -1
s2 = -s2; // -1.1
s3 = -s3; // NaN
b = -b; // -0
f = -f; // -1.1
o = -o; // 1
三目运算符
var max = (num1 > num2) ? num1 : num2;
(num1 > num2)结果为true;返回num1;否则,返回Num2
复合赋值运算符
- 乘/赋值(*=);
- 除/赋值(/=);
- 模/赋值(%=);
- 加/赋值(+=);
- 减/赋值(-=);
var num = 10;
num += 10; // num=num+10
逗号运算符
使用逗号操作符可以在一条语句中执行多个操作,如下面的例子所示:
console.log(num1,num2,num3)
var num1=1, num2=2, num3=3;
逗号操作符多用于声明多个变量;但除此之外,逗号操作符还可以用于赋值。在用于赋值时,逗号操作符总会返回表达式中的最后一项,如下面的例子所示:
var num = (5, 1, 4, 8, 0); // num 的值为 0
由于 0 是表达式中的最后一项,因此 num 的值就是 0。虽然逗号的这种使用方式并不常见,但这个例子可以帮我们理解逗号的这种行为。
函数调用时,值用逗号分开,是传参不是逗号运算
console.log(100,false,{});
if( 100, console.log(false), document.write("文本输出") ){
console.log("内部");
}
var i = 0,
j = 0;
// 初始值 结束判断 每次语句块执行完追加执行
for (i, j; i < 5, j < 10; i++, j++) {
console.log(i, j);
}
console.log(i, j)//20
function fn() { console.log(222); }
if (false, fn(), true) {
console.log(333);
}
变量提升
在代码执行之前,会先进行代码的预解析,将var和function声明的变量进行提升,提升为window的属性(全局变量),并将var声明的变量赋值为undefined,var的提升在function之前
console.log(num);
say();
var num = 100;
function say(){
console.log('hello');
}
console.log(num);
say();
变量提升
var num;
function say(){
consloe.log('hello');
}
console.log(num);//undefined
say();//'hello'
num = 100;
console.log(num);//100
say();//'hello'
变量名一致时会进行覆盖
console.log(num);
var num = 100;
console.log(num);
function num(){
console.log('20');
}
console.log(num);
var num = 50;
console.log(num);
变量提升
var num;
function num(){//覆盖原来的,此时num为一个函数
console.log('20');
}
console.log(num);//f num(){ console.log('20');}
num = 100;
console.log(num);//100
console.log(num);//100
num = 50;
console.log(num);//50
全局作用域
全局作用域是最大的作用域,指向window对象,在全局作用域内声明的变量,在JS代码的时时处处都可以访问
- 全局作用域是最外围的一个执行环境,在web浏览器中,全局执行环境被认为是window对象。
- 所有全局变量和函数都是作为window对象的属性和方法创建的。
- 全局变量拥有全局作用域,在javascript代码中的任何地方都是有定义的。
- 全局作用域直到应用程序退出例如关闭网页或浏览器时才会被销毁。
var num = 13;
function fn(){
console.log(num);
}
fn();//打印13
局部作用域
特点:函数作用域中的所有代码执行完毕后,该作用域被销毁,保存在其中的所有变量和函数定义也随之销毁。
function test(){
var message = 'hi';
}
test();
alert(message); // 报错
作用域链
- 全局作用域变量包括:全局变量(直接声明在全局中不在任何函数体中)成为window的属性、不使用var声明而直接赋值的变量
- 全局作用域直到应用程序退出例如关闭网页或浏览器时才会被销毁
- 局部变量:函数参数、函数内使用var声明的变量
- 函数调用产生局部作用域,函数调用完毕局部作用域销毁,保存在其中的所有变量和函数定义也随之销毁
- 内部作用域可访问外部作用域、外部作用域不可访问内部
- 函数局部作用域有与全局同名的变量,函数内部访问时,优先访问内部的
this
非严格模式下:
- 全局作用域中,this 指向window
- 函数里的this 指向函数的调用者 找不到调用者 就指向window对象
- 构造函数里的this 指向构造函数创建的对象实例
严格模式下:
- 全局作用域中,this指向window对象(与非严格模式一样)
- 全局作用域中函数中的this,指向undefined
- 对象的函数中的this指向调用函数的对象实例(与非严格模式一样)
- 构造函数中的this指向构造函数创建的对象实例(与非严格模式一样)
对象
对象的this指向该对象
function fm() {
console.log( this.a );
}
var obj = {
a: 2,
fn: fm
};
obj.fn(); //2
函数
函数的this指向调用者,对象调用指向对象,没有调用指向window
function fm() {
console.log( this.a );
}
var obj = {
a: 2,
fn: fm
};
obj.fn(); //2
fn();//undefined
改变this指向
call
fn.call(obj, param1,…) 隐式帮我们调用函数
参数:
obj fn内部的this指向的对象
从第二个参数开始,都是传递给fn函数的实参
var a = 89;
var obj = { a: 999 };
function fn(a, b) {
console.log(this.a);
return a + b;
}
var res1 = fn(100, 300);
var res2 = fn.call(obj, 100, 300);
console.log(res1 == res2);
apply
fn.apply(obj, [param1,param2…]) 隐式帮我们调用函数
参数:
obj fn内部的this指向的对象
第二个参数是一个数组,数组的每一个元素都会被当作实参传递给fn
var a = 89;
var obj = { a: 999 };
function fn(a, b) {
console.log(this.a);
return a + b;
}
var res3 = fn.apply(obj, [100, 300]); // fn(100, 300)
console.log(res3); // 400
bind
fn.bind(obj, param1,…) 不会隐式帮我们调用函数 返回一个函数的引用地址
参数:
obj fn内部的this指向的对象
从第二个参数开始,都是传递给fn函数的实参
注意:如果想bind的同时调用函数 就要()在后面表示函数的调用
var a = 89;
var obj = { a: 999 };
function fn(a, b) {
console.log(this.a);
return a + b;
}
var res4 = fn.bind(obj, 100, 300);
console.log(res4()); // 400
var res5 = fn.bind(obj, 100, 300)();
console.log(res5); // 400
var res6 = fn.bind(obj)(100, 300);
console.log(res6); // 400
区别
执行:
- call/apply改变了函数的this上下文后马上执行该函数
- bind则是返回改变了上下文后的函数,不执行该函数
返回值:
- call/apply 返回
fun
的执行结果 - bind返回fun的拷贝,并指定了fun的this指向,保存了fun的参数。