Javascript 笔记

1. Js简介

1.1 什么是语言

计算机就是一个由人来控制的机器,人让它干嘛,它就得干嘛。

我们要学习的语言就是人和计算机交流的工具,人类通过语言来控制、操作计算机。

编程语言和我们说的中文、英文本质上没有区别,只是语法比较特殊。

语言的发展:

  • 纸带机:机器语言

  • 汇编语言:符号语言

  • 现代语言:高级语言

1.2 Js起源

JavaScript诞生于1995年,它的出现主要是用于处理网页中的前端验证。

所谓的前端验证,就是指检查用户输入的内容是否符合一定的规则。(浏览器检查格式,如果对再进行提交,不对直接提示,增强了用户体验)

比如:用户名的长度,密码的长度,邮箱的格式等。

除此之外,大部分的动态效果都需要使用js

1.3 js简介

  • JavaScript是由网景公司发明,起初命名为LiveScript,后来由于SUN公司的介入更名为了JavaScript

  • 1996年微软公司在其最新的IE3浏览器中引入了自己对JavaScript的实现JScript

  • 于是在市面上存在两个版本的JavaScript,一个网景公司的JavaScript和微软的JScript。

  • 为了确保不同的浏览器上运行的JavaScript标准一致,所以几个公司共同定制了JS的标准名命名为ECMAScript。(就是一个标准,也就是文档)

时间表

年份事件
1995年网景公司开发了JavaScript
1996年微软发布了和JavaScript兼容的JScript
1997年ECMAScript第1版(ECMA-262)
1998年ECMAScript第2版
1998年DOM Level1的制定
1998年新型语言DHTML登场
1999年ECMAScript第3版
2000年DOM Level2的制定
2002年ISO/IEC16262:2002的确立
2004年DOM Level3的制定
2005年新型语言AJAX登场
2009年ECMAScript第5版
2009年新型语言HTML5登场

1.4 实现

ECMAScript是一个标准,而这个标准需要由各个厂商去实现。

不同的浏览器厂商对该标准会有不同的实现。

浏览器JavaScript实现方式
FireFoxSpiderMonkey
Internet ExplorerJScript/Chakra
SafariJavaScriptCore
Chromev8 (执行最快的一个引擎)
CarakanCarakan

我们已经知道ECMAScript是JavaScript标准。所以一般情况下,这两个词我们认为是一个意思。

但是实际上JavaScript的含义却要更大一些。

一个完整的JavaScript实现应该由以下三个部分构成:

ECMA:标准

DOM:文档对象模型,提供一组对象,用来操作网页

BOM:浏览器对象模型,提供一组对象,用来操作浏览器
img

1.5 特点

  • 解释型语言(不需要编译,和python一样)

  • 类似于C和Java的语法结构(废话)

  • 动态语言

  • 基于原型的面向对象(是面向对象的语言)

本质上都是,向计算机发送指令,是写在网页上的

1.6 helloworld

**三个输出语句:**用于做测试的

控制浏览器弹出一个警告框

alert("Hello World!");

让计算机在页面中输出一个内容

document.write("Hello World!");

向控制台输出一个内容

console.log("Hello World!");

2. js基础

2.1 基础准备

2.1.1 js编写位置(html页面中)

① 可以将js代码编写到标签的onclick属性中当我们点击按钮时,js代码才会执行

<button onclick="alert(\"Fuck! Do not touch me!\")"></button>  <!-- \" 是用于转义 可以直接写成单引号的 -->

② 可以将js代码写在超链接的href属性中,这样当点击超链接时,没有跳转,会执行js代码

<a href="jacascript:alert('让你点你就点~~')">Try to click me</a>

<a href="jacascript:;">Try to click me</a>  <!--这样处理,点击之后超链接不会进行跳转,不做任何处理-->

③ 虽然可以写在标签的属性中,但是他们属于结构与行为耦合,不方便维护,不推荐使用

可以将js代码编写到script标签, 刷新页面就会立即执行

<script type="text/javascript">   // type 可写可不写,不写默认是这个值
    alert("I'm inner script.");
</script>

④ 可以将js代码编写到外部js文件中,然后通过script标签引入

写到外部文件中可以在不同的页面中同时引用,也可以利用浏览器的缓存机制,推荐使用

<script src="/js/script.js" type="text/javascript"></script>

script标签一旦用于引入外部文件了,就不能在编写代码了,即使编写了浏览器也会忽略

如果需要则可以在创建一个新的script标签用于编写内部代码

注意:js代码是从上到下按照顺序一步一步进行执行的

2.1.2 注释

多行注释,注释中的内容不会被执行,但是可以在源代码中查看

/*
   多行注释...
   多行注释...
   多行注释...
*/

单行注释

// 单行注释
2.1.3 注意点
  1. JS中严格区分大小写

  2. JS中每一条语句以分号;结尾,表示指令完成
    - 如果不写分号,浏览器会自动添加,但是会消耗一些系统资源
    - 而且有些时候,浏览器会加错分号,所以在开发中分号必须写

  3. JS中会忽略多个空格和换行,所以我们可以利用空格和换行对代码进行格式化 (也就是说,缩进与换行对代码不受影响)

2.1.4 字面量和变量

字面量

字面量,都是一些不可改变的值

​ 比如:1 2 3 4 5 1111111111578148151515

​ 字面量都是可以直接使用,但是我们一般都不会直接使用字面量

变量

变量可以用来保存字面量,而且变量的值是可以任意改变的变量更加方便我们使用

所以在开发中都是通过变量去保存一个字面量,而很少直接使用字面量

可以通过变量对字面量进行描述

// 声明变量: 在js中使用var关键字来声明一个变量
var a;
// 为变量赋值
a = 123;
a = 456;
a = 123124223423424;
// 声明和赋值同时进行
var b = 789;
var c = 0;
var age = 80;
console.log(age);
2.1.5 标识符

在JS中所有的可以由我们自主命名的都可以称为是标识符

例如:变量名、函数名、属性名都属于标识符

命名一个标识符时需要遵守如下的规则:

  1. 标识符中可以含有字母、数字、_、$

  2. 标识符不能以数字开头

  3. 标识符不能是ES中的关键字或保留字

  4. 标识符一般都采用驼峰命名法 (这是一个规范,并不是强制要求)

    • 首字母小写,每个单词的开头字母大写,其余字母小写

      ​ helloword -> helloWord

关键字

ifelsedowhilefor
breakcontinuetrycatchfinally
throwtruefalsefunctionreturn
switchcasenulltypeofinstanceof
newvarvoidinwith
defaultdebuggerdeletethis

保留字

classenumextendssuperconstexport
importimplementsletprivatepublicyield
interfacepackageprotectedstatic

其他不建议使用的标识符

booleanbyteshortchar
floatdoubleStringBoolean
DateArrayMathError
TypeErrorURIErrorRangeErrorReferenceError
parselntparseFloatNaNisNaN
throwsnativegotoeval
argumentsisFinitevolatileabstract
synchronizefinalencodeURICOmponentdecodeURIComponent

JS底层保存标识符时实际上是采用的Unicode编码,所以理论上讲,所有的utf-8中含有的内容都可以作为标识符(utf-8中也含有中文,理论上来说中文也是可以作为标识符的,但没有必要)

2.2 数据类型

数据类型指的就是字面量的类型,在JS中一共有六种数据类型

基本数据类型String字符串
基本数据类型Number数值
基本数据类型Boolean布尔值
基本数据类型Null空值
基本数据类型Undefined未定义
引用类型Object对象
2.2.1 String

JS中,字符串需要使用引号引起来

  1. 使用单引号或双引号都可以,但不要混合使用

  2. 同一种引号不能嵌套,双引号不能放双引号,单引号不能放单引号

在字符串中我们可以使用\作为转义字符,当表示一些特殊符号时可以使用\进行转义

  • \"表示"

  • \'表示'

  • \n表示换行

  • \t制表符

  • \\表示\ 注意

var str = "hello";
var str = 'hello'; //单双引号都可以

str = "我说:"今天天气真不错" "  //这个是错误的,引号不能嵌套,下面两个都是可以的
str = "我说:'今天天气真不错' "
str = "我说:\"今天天气真不错\" "
2.2.2 Number

在JS中,所有的数值都是Number类型,包括整数和浮点数(小数)

可以使用一个运算符typeof,来检查一个变量的类型。语法:typeof 变量

  • 检查字符串时,会返回string

  • 检查数值时,会返回number

var a = 123; //整数
console.log(typeof a)  // 输出是number
a = 456.789; //浮点数
a = "123" //字符串
console.log(typeof a)  //输出是string ,是小写
(1) MAX_VALUE

JS中可以表示的数字的最大值

​ Number.MAX_VALUE=1.7976931348623157e+308 , 科学计数法,表示1后面最多308位,不能再大了

如果使用Number表示的数字超过了最大值,则会返回一个Infinity,正无穷

var a = Number.MAX_VALUE * Number.MAX_VALUE;
console.log(a); // Infinity

a = Infinity; // a就是一个字面量,不能加引号,表示正无穷,类型是一个number
console.log(typeof a); // number
(2) MIN_VALUE

大于0的最小值 Number.MIN_VALUE=5e-324

var a = Number.MIN_VALUE * Number.MIN_VALUE;
console.log(a); // 0
  • Infinity表示正无穷

  • -Infinity 表示负无穷

使用typeof检查,Infinity会返回Number

(3) NaN

NaN是一个特殊的数字,表示Not A Number

var a = 'abc' * 'def';
console.log(a); // NaN ,意思是不会算但又需要返回一个值,所以就成了NaN

使用typeof检查一个NaN也会返回number

var b = NaN; //是一个字面量,可以直接进行使用,但不能加引号
console.log(typeof b); // number
(4) 运算精度

在JS中整数的运算基本可以保证精确

如果使用JS进行浮点运算,可能得到一个不精确的结果

var a = 0.1 + 0.2; //本质就是在计算机转成二进制运算时,无法对小数进行准确的表示
console.log(a); // 0.30000000000000004

所以千万不要使用JS进行对精确度要求比较高的运算,尤其是对钱的计算,这些精密计算应该放到服务器进行处理,而不是前端页面

2.2.3 Boolean

布尔值只有两个,主要用来做逻辑判断

  • true表示真

  • false表示假

使用typeof检查一个布尔值时,会返回boolean

2.2.4 Null

Null(空值)类型的值只有一个,就是null

null这个值专门用来表示一个为空的对象

使用typeof检查一个null值时,会返回object

var a3 = null;
console.log(a3); // null
console.log(typeof a3); // object
2.2.5 Undefined

Undefined(未定义)类型的值只有一个,就是undefind

当声明一个变量,但是并不给变量赋值时,它的值就是undefined

使用typeof检查一个undefined时,也会返回undefined

var a4;
console.log(a4); // undefind
console.log(typeof a4); // undefind
2.2.6 强制类型转换(基本数据类型)

指将一个数据类型强制转换为其他的数据类型

类型转换主要指,将其他的数据类型,转换为StringNumberBoolean

(1) 其他类型转换成String

方法一调用被转换数据类型的toString()方法

该方法不会影响到原变量,它会将转换的结果返回, 也就是说 xxx.toString() 返回新的值,不改变原值

// Number转换为String
var a1 = 123;
var b1 = a1.toString();
console.log(typeof a1); // number
console.log(typeof b1); // string
// Boolean转换为String
var a2 = true;
var b2 = a2.toString();
console.log(typeof a2); // boolean
console.log(typeof b2); // string

但是注意:nullundefined这两个值没有toString(),如果调用他们的方法,会报错

// Null转换为String
var a3 = null;
var b3 = a3.toString(); // UncaughtTypeError: Cannot read property 'toString' of null
console.log(typeof a3); 
console.log(typeof b3);
// Undefined转换为String
var a4 = undefined;
var b4 = a4.toString(); // UncaughtTypeError: Cannot read property 'toString' of undefined
console.log(typeof a4); 
console.log(typeof b4);

方法二调用String()函数,并将被转换的数据作为参数传递给函数

使用String()函数做强制类型转换时,对于NumberBoolean实际上就是调用的toString()方法

但是对于nullundefined,就不会调用toString()方法,而是将

  • null直接转换为"null"

  • undefined 直接转换为"undefined"

// Number转换为String
var a1 = 123;
var b1 = String(a1);
console.log(typeof a1); // number
console.log(typeof b1); // string
// Boolean转换为String
var a2 = true;
var b2 = String(a2);
console.log(typeof a2); // boolean
console.log(typeof b2); // string
// Null转换为String
var a3 = null;
var b3 = String(a3);
console.log(typeof a3); // object
console.log(typeof b3); // string
// Undefined转换为String
var a4 = undefined;
var b4 = String(a4);
console.log(typeof a4); // undefined
console.log(typeof b4); // string
(2) 其他数据类型转换为Number

方法一:使用Number()函数

  • 字符串 --> 数字

    • 如果是纯数字的字符串,则直接将其转换为数字
    • 如果字符串中有非数字的内容,则转换为NaN
    • 如果字符串是一个空串或者是一个全是空格的字符串,则转换为0
// ① 纯数字的字符串
var a1 = '123';         
a1 = Number(a1);
console.log(typeof a1); // number
console.log(a1); 	    // 123
// ② 非数字的内容
// var a2 = 'abc';         
var a2 = undefined;
a2 = Number(a2);
console.log(typeof a2); // number
console.log(a2);        // NaN 
// ③ 空串
// var a3 = ' ';    空格  
var a3 = null;       空
a3 = Number(a3);        
console.log(typeof a3); // number
console.log(a3);        // 0
  • 布尔 --> 数字

    • true转成1
    • false转成0
var a4 = true;
a4 = Number(a4);
console.log(typeof a4); // number
console.log(a4);        // 1
var a5 = false;
a5 = Number(a5);
console.log(typeof a5); // number
console.log(a5);        // 0

方法二:专门用来对付字符串 ,对字符串进行有效提取

  • parseInt()把一个字符串转换为一个整数:可以将一个字符串中的有效整数部分取出来,然后转换为Number

  • parseFloat()把一个字符串转换为一个浮点数:可以同时将一个字符串中的有效小数部分取出来,然后转换为Number既取整数又取小数

  • 如果对非String使用parseInt()parseFloat(),它会先将其转换为String,然后再操作

/* parseInt */
var a1 = "123";
a1 = parseInt(a1);
console.log(typeof a1); // number
console.log(a1);        // 123

var a2 = "123.456";
a2 = parseInt(a2);
console.log(typeof a2); // number
console.log(a2);        // 123

var a3 = "123px";
a3 = parseInt(a3);
console.log(typeof a3); // number
console.log(a3);        // 123 

123a567 => 123
b123a567 =>NaN


// var a4 = null;
// var a4 = undefined;
// var a4 = '';
// var a4 = 'abc';
// var a4 = true;
var a4 = false;   过程: false => 'false' => NaN
a4 = parseInt(a4);
console.log(typeof a4); // number
console.log(a4);        // NaN
(3)其他数据类型转换为Boolean

**方法一:**使用Boolean()函数

  • 数字-—->布尔

    • 除了0NaN,其余的都是true
  • 字符串-—->布尔

    • 除了空串,其余的都是true
  • nullundefined都会转换为false

  • 对象也会转换为true

    // - 数字-—->布尔
    //   - 除了`0`和`NaN`,其余的都是`true`
    // var a1 = 0;
    var a1 = NaN;
    a1 = Boolean(a1);
    console.log(a1); // false
    var a2 = 123;
    a2 = Boolean(a2);
    console.log(a2); // true
    // - 字符串-—->布尔
    //   - 除了空串,其余的都是`true`
    var a3 = "123";
    a3 = Boolean(a3);
    console.log(a3); // true
    var a4 = " ";
    a4 = Boolean(a4);
    console.log(a4); // true
    var a5 = "";
    a5 = Boolean(a5);
    console.log(a5); // false
    // - `null`和`undefined`都会转换为`false`
    // var a6 = null;
    var a6 = undefined;
    a6 = Boolean(a6);
    console.log(a6); // false
    

    方法二: 隐式类型转换

    为任意的数据类型做两次非运算,即可将其转换为布尔值(下一节会介绍)

    var a = "123";
    var b = !!a;
    console.log("a="+a+",b="+b); // a=true,b=true
    
(4) 其他进制的数字

在js中,如果需要表示16进制的数字,则需要以0x开头

如果需要表示8进制的数字,则需要以0开头

如果需要表示2进制的数字,则需要以0b开头,但是不是所有的浏览器都支持

// 十六进制数字
var a = 0x10;
console.log(a); // 16
a = 0xff;
console.log(a); // 255
a = 0xCafe;
console.log(a); // 51966
a = "0x70";
a = parseInt(a,16);
console.log(a); // 112
// 八进制数字
a = 070;
console.log(a); // 56
a = "070";
a = parseInt(a,8);
console.log(a); // 56
// 二进制数字
a = 0b10;
console.log(a); // 2

2.3 运算符

pass

2.4 流程控制

pass

2.5 对象

JS中数据类型

  • String 字符串

  • Number数值

  • Boolean 布尔值

  • Null空值

  • Undefined 未定义

以上这五种类型属于基本数据类型,以后我们看到的值只要不是上边的5种,全都是对象

基本数据类型都是单一的值"hello" 123 true,值和值之间没有任何的联系。

在JS中来表示一个人的信息(name gender age):

var name = "孙悟空";
var gender = "男";
var age = 18;

如果使用基本数据类型的数据,我们所创建的变量都是独立,不能成为一个整体。

对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性。

2.5.1 对象的分类
(1) 内建对象

由ES标准中定义的对象,在任何的ES的实现中都可以使用 (浏览器或者是node.js都可以使用)

常见内建对象有以下,都可以直接通过new调用构造函数创建对象实例:

  • Object、Function、Array、Date、RegExp,String、Number、Boolean、

  • Error(EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError)

// Math
Math.sqrt(2);
// String
String(2);
// Number
Number("2");
(2) 宿主对象

由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象,不需要创建对象,直接使用

比如 BOM DOM

// console
console.log("hello");
// document
document.write("hello");

JavaScript实现包括三部分:

组成作用地位例子
ES(ECMAScript)描述JS语法和基本对象核心
DOM(Document Object Model 文档对象模型)HTML和XML的应用程序接口,处理网页内容的方法和接口W3C标准document
BOM(Browser Object Model 浏览器对象模型)描述与浏览器进行交互的方法和接口,处理浏览器窗口和框架浏览器厂商对DOM的实现window
(3) 自定义对象 (最难的)

由开发人员自己创建的对象

使用new关键字调用的函数,是构造函数constructor,构造函数是专门用来创建对象的

函数使用typeof检查一个对象时,会返回object

在对象中保存的值称为属性

  • 添加或修改对象属性的语法:对象.属性名=属性值;

  • 读取对象属性的语法:对象.属性名

  • 删除对象属性的语法:delete 对象.属性名;

/*
要使用对象(塑料袋),必须先创建一个对象 var obj = new Object();
*/

//创建对象,使用new关键字调用的函数,是构造函数constructor,构造函数是专门用来创建对象的
var obj = new Object();
// 向obj中添加一个name属性
obj.name = "孙悟空";
// 向obj中添加一个gender属性
obj.gender = "男";
// 向obj中添加一个age属性
obj.age = "18";
// 打印obj
console.log(typeof obj); // object
console.log(obj); // {"age":"18","gender":"男","name":"孙悟空"}
console.log(obj.name); // 孙悟空

注意:如果读取对象中没有的属性,不会报错而是会返回undefined

属性名

对象的属性名不强制要求遵守标识符的规范,什么乱七八糟的名字都可以使用,但是我们使用是还是尽量按照标识符的规范去做

如果要使用特殊的属性名,不能采用.的方式来操作,而需要使用另一种语法:对象["属性名"]=属性值,读取时也需要采用这种方式

obj["name"] = "齐天大圣";
console.log(obj["name"]); // 齐天大圣

使用[]这种形式去操作属性,更加的灵活,在[]中可以直接传递一个变量,这样变量值是哪个就会读取哪个属性

var n = "nihao";
obj[n] = "你好";
console.log(obj[n]); // 你好

回顾.[]new这几个运算符的优先级是最高的

属性值

JS对象的属性值,可以是任意的数据类型,包括对象

var obj2 = new Object();
obj2.name = "猪八戒";
obj.bro = obj2;
console.log(obj.bro.name); // 猪八戒
in 运算符

通过该运算符可以检查一个对象中是否含有指定的属性

如果有则返回true,没有则返回false

语法:"属性名" in 对象

console.log("test" in obj); // false
console.log("name" in obj); // true
2.5.2 基本数据类型和引用数据类型

基本数据类型 String Number Boolean Null Undefined

引用数据类型 Object

(1) 基本数据类型
  • JS中的变量都是保存到栈内存中的,基本数据类型的值直接在栈内存中存储

  • 值与值之间是独立存在,修改一个变量不会影响其他的变量

var a = 1;
var b = a;  // 此时,b将a所保存的值复制了一份,保存到自己的值里面,所以 a 的 1 与 b 的 1 本质上不是同一个
console.log("a=" + a + ", b=" + b); // a=1, b=1
b = 2;
console.log("a=" + a + ", b=" + b); // a=1, b=2
(2) 引用数据类型
  • 对象是保存到堆内存中的

  • 每创建一个新的对象,就会在堆内存中开辟出一个新的空间,而变量保存的是对象的内存地址(对象的引用)

  • 如果两个变量保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也会受到影响

var obj3 = obj;
obj3.name = "斗战胜佛";
console.log(obj.name);  // 斗战胜佛
console.log(obj3.name); // 斗战胜佛
(3) 比较
  • 当比较两个基本数据类型的值时,就是比较值。
  • 而比较两个引用数据类型时,它是比较的对象的内存地址,如果两个对象是一摸一样的,但是地址不同,它也会返回false
var o1 = new Object();
var o2 = new Object();
o1["name"] = "周瑜";
o2["name"] = "周瑜";
console.log(o1 == o2); // false
2.5.3 对象字面量

使用对象字面量,可以在创建对象时,直接指定对象属性的语法:{属性名: 属性值, 属性名: 属性值...}

对象字面量的属性名可以加引号也可以不加(建议不加),如果要使用一些特殊的名字,则必须加引号

属性名和属性值是一组一组的名值对结构,名和值之间使用:连接,多个名值对之间使用,隔开

如果一个属性之后没有其他的属性了,就不要写,

var obj = {
    name: "孙悟空",
    age: 1000,
    gender: "男",
    bor:{
        name: "猪八戒"
    }
}
console.log(obj); // {"age":1000,"bor":{"name":"猪八戒"},"gender":"男","name":"孙悟空"}
2.5.4 方法

对象的属性值可以是任何的数据类型,也可以是个函数(下一节知识)

函数也可以称为对象的属性,如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法

调用函数就说调用对象的方法,但是它只是名称上的区别没有其他的区别

var obj2 = {
    name: "猪八戒",
    age: 18,
    sayName: function() {
        console.log(obj2.name);
    }
};
obj2.sayName(); // 猪八戒
2.5.5 枚举对象中的属性

使用for...in语句语法:

for(var 变量 in 对象) {
	语句...
}

for...in语句对象中有几个属性,循环体就会执行几次

每次执行时,会将对象中的一个属性的名字赋值给变量

var obj = {
    name: "孙悟空",
    age: 1000,
    gender: "男",
    address: "花果山"
};
for(var key in obj){
    console.log(key + "=" + obj.key);
    // name=undefined
    // age=undefined
    // gender=undefined
    // address=undefined
    console.log(key + "=" + obj[key]);
    // name=孙悟空
    // age=1000
    // gender=男
    // address=花果山
} 

/*  取出来的 key = "name"
			key = "age"
			...
	所以只能是使用[]来进行取值		*/

2.6 函数

函数也是一个对象,可以封装一些功能(代码),在需要时可以执行这些功能(代码),可以保存一些代码在需要的时候调用

使用typeof检查一个函数对象时,会返回function

2.6.1 创建函数的方式
(1) 通过new进行创建
// 创建一个函数对象
// 可以将要封装的代码以字符串的形式传递给构造函数
var fun = new Function("console.log('Hello World.');");
// 封装到函数中的代码不会立即执行
// 函数中的代码会在函数调用的时候执行
// 调用函数语法:函数对象()
// 当调用函数时,函数中封装的代码会按照顺序执行
fun(); // Hello World.
(2) 使用函数声明
function 函数名([形参1, 形参2...形参N]) {
	语句...
}
// 调用函数
函数名();   //常用
(3) 使用函数表达式(匿名函数)
var 函数名 = function([形参1, 形参2...形参N]) {
	语句...
};
// 调用函数
函数名();
    
//示例如下:
var fun1 = function(){
    console.log("Hello world.");
    alert("Hello World!");
    document.write("Helloworld");
};
fun1();
2.6.2 参数

定义一个用来求两个数和的函数

可以在函数的()中来指定一个或多个形参(形式参数)多个形参之间使用,隔开,声明形参就相当于在函数内部声明了对应的变量

在调用函数时,可以在()中指定实参(实际参数)

  • 调用函数时解析器不会检查实参的类型。所以要注意,是否有可能会接收到非法的参数,如果有可能则需要对参数进行类型的检查

  • 调用函数时,解析器也不会检查实参的数量,多余实参不会被赋值。如果实参的数量少于形参的数量,则没有对应实参的形参将是undefined (意思就是,传入的实参可多也可少,不会影响函数的执行,至于是否异常就是执行函数本身的问题了)

// 创建一个函数,用来计算三个数的和
function sum(a, b, c) {
    alert(a + b + c);
}
sum(1, 2, 3, 4); // 6

实参可以是任意的数据类型,也可以是一个对象。当我们的参数过多时,可以将参数封装到一个对象

function sayHello(o){
    console.log("我是" + o.name
                + ",今年我" + o.age 
                + "岁了,我是一个" + o.gender 
                + "人,我住在" + o.address);
}			
var obj = {
    name: "孙悟空",
    age: 1000,
    gender: "男",
    address: "花果山"
};
sayHello(obj); // 我是孙悟空,今年我1000岁了,我是一个男人,我住在花果山

实参可以是一个对象,也可以是一个函数

function calCirc(radius) {
    return Math.PI * Math.pow(radius, 2);
}
function fun(a){
    console.log("a = " + a);
}
fun(calCirc);  
// a = function calCirc(radius) {
//     return Math.PI * Math.pow(radius, 2);
// }
fun(calCirc(10)); // a = 314.1592653589793
2.6.3 返回值

可以使用return来设置函数的返回值语法:return 值

return后的值将会作为函数的执行结果返回,可以定义一个变量,来接收该结果

在函数中return后的语句都不会执行

如果return语句后不跟任何值,就相当于返回一个undefined;如果函数中不写return,则也会返回undefined

return后可以跟任意类型的值

// 创建一个函数,用来计算三个数的和
function sum(a, b, c) {
    // var result = a + b + c;
    // return result;
    return a + b + c;
}

// 调用函数
// 变量result的值就是函数的执行结果
// 函数返回什么result的值就是什么
var result = sum(1, 2, 3);
console.log("result = " + result);
2.6.4 自执行函数

函数定义完,立即被调用,这种函数叫做立即执行函数

立即执行函数往往只会执行一次

(function (形参){})(实参)
!function(形参){}(实参)

//示例如下:
// 函数对象()
(function(){
   console.log("I'm anoymous function.");
})(); // I'm anoymous function.

!function(a, b){
   console.log(a + b);
}(2,3); // 5

2.7 作用域(Scope)

作用域指一个变量的作用的范围

在JS中一共有两种作用域:

  • 全局作用域

  • 函数作用域

2.7.1 全局作用域

直接编写在script标签中的JS代码,都在全局作用域

全局作用域在页面打开时创建,在页面关闭时销毁

在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,由浏览器创建,可以直接使用

在全局作用域中:

  • 创建的变量都会作为window对象的属性保存

  • 创建的函数都会作为window对象的方法保存

全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问的到

var a = 3;
console.log(window.a); //3
console.log(a); //3

b = 3;
console.log(b); //3
2.7.2 变量和函数声明提前

使用var关键字声明的变量,会在所有的代码执行之前被声明

但是如果声明变量时不使用var关键字,则变量不会被声明提前

// 1、变量的声明提前
console.log("a = " + a); // a = undefined
var a = "abc";
// ======相当于======
var a;
console.log("a = " + a); // a = undefined
a = "abc";

// 2、没有变量的声明提前,报错
console.log("b = " + b); // UncaughtReferenceError: b is not defined
b = "abc";
// ======相当于======
console.log("b = " + b); // UncaughtReferenceError: b is not defined
window.b = "abc";

使用函数声明形式创建的函数function, 它会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数

fun1(); // fun1...
fun2(); // UncaughtTypeError: fun2 is not a function
// 函数声明,会被提前创建
function fun1(){
    console.log("fun1...");
}
// 函数表达式,不会被提前创建(变量会被提前声明,但函数不会被提前创建)
var fun2 = function(){
    console.log("fun2...");
}
2.7.3 函数作用域

调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁

每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的

  • 在函数作用域中可以访问到全局作用域的变量

  • 在全局作用域中无法访问到函数作用域的变量

当在函数作用域操作一个变量时,它会先在自身作用域中寻找,

  • 如果有就直接使用

  • 如果没有则向上一级作用域中寻找,直到找到全局作用域

  • 如果全局作用域中依然没有找到,则会报错

在函数中要访问全局变量可以使用window对象

var a = 10;
function fun2(){
    var a = 20;

    function fun3(){
        var a = 30;
        console.log("fun3 ==> a = " + a);  // fun3 ==> a = 30
    }

    fun3();

    console.log("fun2 ==>a = " + a); // fun2 ==>a = 20
    console.log("a = " + window.a); // a = 10
}
fun2(); 
console.log("a = " + a); // a = 10

在函数作用域也有声明提前的特性,使用var关键字声明的变量,会在函数中所有的代码执行之前被声明

函数声明也会在函数中所有的代码执行之前执行

// 在函数作用域也有声明提前的特性,使用`var`关键字声明的变量,会在函数中所有的代码执行之前被声明
function func1(){
    console.log(a);
    var a = "func1";

    // 函数声明也会在函数中所有的代码执行之前执行
    func2(); // fun2...
    function func2(){
        console.log("fun2...");
    }
}
func1(); // undefined

在函数中,不适用var声明的变量都会成为全局变量

// 函数声明且调用
func3();
function func3() {
    a = 4;
}
console.log("a = " + window.a);  // a = 4
console.log("a = " + window["a"]);   // a = 4
console.log("a = " + a);    // a = 4
// 函数声明不调用
function func4() {
    b = 4;
}
console.log("b = " + window.b);  // b = 4
console.log("b = " + window["b"]);   // b = 4
console.log("b = " + b);    // UncaughtReferenceError: b is not defined

定义形参就相当于在函数作用域中声明了变量

var e = 10;
function fun5(e){
    console.log(e);
}
fun5(); // undefined
fun5(55);  // 55

3. js高级

3.1 函数高级

3.1.1 函数的概念
1 什么是函数
  • 实现特定功能的 n 条语句的封装体
  • 只有函数是可以执行的,其它类型的数据不能执行
  • 凡是通过 new Function() 创建的对象都是函数对象(本质)
2 为什么要用函数?
  • 提高代码复用
  • 便于阅读交流
3 定义函数
  • 函数声明
  • 表达式
//函数声明
function fn1(){
    console.log('fn1()')
}
const fn2 = function(){
    console.log('fn2()')
};

//表达式
const fn2 = () => console.log('fn2()')   //这个是箭头函数吗,看不太懂
3.1.2 调用(执行) 函数
  1. test() 直接调用, this = window
  2. obj.test() 通过对象调用 this = obj
  3. var obj = new test() new 调用 this = obj
  4. test.call/apply(obj) 临时让 test 成为 obj 的方法进行调用 this = obj 改变this指向

image-20210705185535337

    var obj = {}
    //此处不能使用箭头函数,因为箭头函数会改变this指向
    function test2 () {
      this.xxx = 'shangguigu'
    }
    // obj.test2()  不能直接, 根本就没有
    test2.call(obj)  // 可以让一个函数成为指定任意对象的方法进行调用
    console.log(obj.xxx)   // 输出为 shangguigu 
3.1.3 回调函数
(1) 什么函数才是回调函数?
  • 你定义的
  • 你没有调
  • 但最终它执行了(在某个时刻或某个条件下)
(2) 常见的回调函数?
  • dom事件回调函数 ==>发生事件的dom元素
  • 定时器回调函数 ===>window
  • ajax请求回调函数(后面讲)
  • 生命周期回调函数(后面讲)
  // dom事件回调函数
 document.getElementById('btn').onclick = function () {
     alert(this.innerHTML)
 }
 // 定时器回调函数
 setTimeout(function () {  
     alert('到点了'+this)}, 2000)  // 2s后调用函数
3.1.4 IIFE (自调用函数)
  1. 全称: Immediately-Invoked Function Expression 自调用函数

  2. 作用:

    • 隐藏实现
    • 不会污染外部(一般指全局)命名空间 (函数外与函数内无关)
 (function () { //匿名函数自调用
      var a = 3
      console.log(a + 3)
    })()
 console.log(a) // a is not defined  可以说明不会污染外部命名空间

  • 用它来编码js模块
 //此处前方为何要一个`;`-->因为自调用函数外部有一个()包裹,可能与前方以()结尾的代码被一起认为是函数调用
  //不加分号可能会被认为这样 console.log(a)(IIFE)
 ;(function () {//不会污染外部(全局)命名空间-->举例
      let a = 1;
      function test () { console.log(++a) } //声明一个局部函数test
      window.$ = function () {  return {test: test} }// 向外暴露一个全局函数
    })()
  test ()  //test is not defined
  $().test() // 1. $是一个函数 2. $执行后返回的是一个对象
3.1.5 函数中的this
(1) this是什么?
  • 任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window
  • 所有函数内部都有一个变量this
  • 它的值是调用函数的当前对象
(2) 如何确定this的值?
  • test(): window
  • p.test(): p
  • var obj = new test(): 新创建的对象,也就是obj
  • p.call(obj): obj
3.1.6 原型与原型链
(1) 原型 [prototype]
  1. 函数的prototype属性
  • 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
  • 原型对象中有一个属性constructor, 它指向函数对象

  1. 给原型对象添加属性(一般都是方法)
  • 作用: 函数的所有实例对象自动拥有原型中的属性(方法)
  // 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
    console.log(Date.prototype, typeof Date.prototype)
    function Fun () { }
    console.log(Fun.prototype)  // 默认指向一个Object空对象(没有我们的属性)

    // 原型对象中有一个属性constructor, 它指向函数对象
    console.log(Date.prototype.constructor===Date)
    console.log(Fun.prototype.constructor===Fun)

    //给原型对象添加属性(一般是方法) ===>实例对象可以访问
    Fun.prototype.test = function () { console.log('test()') }
    var fun = new Fun()
    fun.test()
(2) 显式原型与隐式原型
  1. 每个函数function都有一个prototype,即显式原型(属性)

  2. 每个实例对象都有一个[__ proto __],可称为隐式原型(属性)

  3. 对象的隐式原型的值为其对应构造函数的显式原型的值 实例对象.__proto__ === 对应构造函数.prototype

  4. 内存结构

  1. 总结:
  • 函数的[prototype]属性: 在定义函数时自动添加的, 默认值是一个空Object对象
  • 对象的[__ proto __]属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
  • 程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)
  //定义构造函数
  function Fn() {
   // 内部默认执行语句: this.prototype = {}
    }
  // 1. 每个函数function都有一个prototype,即显式原型属性, 默认指向一个空的Object对象
  console.log(Fn.prototype)
  // 2. 每个实例对象都有一个__proto__,可称为隐式原型
  //创建实例对象
  var fn = new Fn()  // 内部默认执行语句: this.__proto__ = Fn.prototype
  console.log(fn.__proto__)
  // 3. 对象的隐式原型的值为其对应构造函数的显式原型的值
  console.log(Fn.prototype===fn.__proto__) // true
  //给原型添加方法
  Fn.prototype.test = function () {
    console.log('test()')
  }
  //通过实例调用原型的方法
  fn.test()
(3) 原型链
① 原型链
  • 访问一个对象的属性时,
    • 先在自身属性中查找,找到返回
    • 如果没有, 再沿着[__ proto __]这条链向上查找, 找到返回
    • 如果最终没找到, 返回undefined

  • 别名: 隐式原型链
  • 作用: 查找对象的属性(方法)
②构造函数/原型/实例对象的关系(图解)
  1. var o1 = new Object();
    var o2 = {}; //这两个是创建对象的两种方法
    
  2. function Foo(){  }  等价于 var Foo = new Function()
    

ps:所有函数的[__ proto __]都是一样的

③ 属性问题
  • 读取对象的属性值时: 会自动到原型链中查找

  • 设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值

  • 方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上

   function Fn() { }
   Fn.prototype.a = 'xxx'
   var fn1 = new Fn()
   console.log(fn1.a, fn1) //xxx Fn{}

   var fn2 = new Fn()
   fn2.a = 'yyy'
   console.log(fn1.a, fn2.a, fn2) //xxx yyy  Fn{a: "yyy"}

   function Person(name, age) {
     this.name = name
     this.age = age
   }
   Person.prototype.setName = function (name) {
     this.name = name
   }
   var p1 = new Person('Tom', 12)
   p1.setName('Bob')
   console.log(p1)  //Person {name: "Bob", age: 12}

   var p2 = new Person('Jack', 12)
   p2.setName('Cat')
   console.log(p2) //Person {name: "Cat", age: 12}
   console.log(p1.__proto__===p2.__proto__) // true   -->所以方法一般定义在原型中
(4) instanceof
  1. instanceof是如何判断的?
  • 表达式: A instanceof B
  • 如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false
  1. Function是通过new自己产生的实例
 /*
 案例1
  */
 function Foo() {  }
 var f1 = new Foo()
 console.log(f1 instanceof Foo) // true
 console.log(f1 instanceof Object) // true

 /*
 案例2
  */
 console.log(Object instanceof Function) // true
 console.log(Object instanceof Object) // true
 console.log(Function instanceof Function) // true
 console.log(Function instanceof Object) // true

 function Foo() {}
 console.log(Object instanceof  Foo) // false

3.2 箭头函数

使用 =(){}来代替 function()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值