1. JS函数
1.1 函数(Function)是什么?
函数(方法)是由事件驱动的或者当它被调用时执行的可重复使用的代码块 —— 官方说明
向来觉得官方的文档是有些生硬的,举个例子:
函数可以看做是功能(以一辆汽车为例,如下图),这些都可以看做成是方法
刹车
油门
鸣笛
档位
- 这些功能任何一个里面都有很多个零件的配合,共同完成某一个任务,我们只需要去调用(踩刹车,踩油门,按喇叭,挂挡),功能就会执行
- 函数也是一样的,它内部封装了一些操作,只有我们去调用的时候才会执行
1.2 一个最简单的函数及触发方法
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>我的第一个方法</title> </head> <body> <button onclick="myFunction()">点击触发函数</button> <script> // 必须有 function关键字,命名通常为驼峰命名,首字母小写 function myFunction(){ alert("这是我的函数"); } </script> </body> </html>
1.3 带参数的函数(形参与实参)
- 形参 : 函数中定义的变量(此时是没有值的,只是一个代称)
- 实参 : 在运行时的函数调用时传入的参数(实际的值)
- js中,方法中即使定义了形参,调用时不传实参也不会报错
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>形参与实参</title> </head> <body> <!-- 这里的5和2是实参 --> <button onclick="addNum(5, 2)">计算5+2的值</button> <script> // 此处的num1,与num2便是形参 function addNum(num1, num2){ alert(num1 + num2) } </script> </body> </html>
1.4 带有返回值的函数 ———— return
function fn(a, b){ return a*b; } // 调用并给num赋值 let num = fn(3, 5); console.log(num) // 得到15
1.5 js函数内置对象 ———— arguments(重点,考点)
- 它是函数一创建就有的
- 是一个类数组(并不是真正的数组)
- 方法调用时,可以得到所有传进来的参数
- 你传多少,我就能拿到多少
function fn(){ console.log(arguments) } fn(1, 2, 3, 4);
经典应用 ———— 求一组参数的总和
function fn(){ let sum = 0; for(let i = 0; i < arguments.length; i++){ sum += arguments[i]; } // 返回 sum return sum } let allSum = fn(1, 2, 3, 4); console.log(allSum) // 得到10
1.6 函数内的变量
在函数内的定义的变量均为局部变量
函数运行完之后就会销毁(垃圾回收机制),所以外界无法访问
变量应尽量避免重名(局部与全局变量可能会混淆,导致一些意料之外的问题)
function fn() { // 此为局部变量 let a = 5; console.log(a) } fn(); console.log(a) // 此处报错,无法访问
1.7 匿名函数(难点)
- 顾名思义指的是没有名字的函数
- 必须采用下面的语法,否则会报错
(function (){ //由于没有执行该匿名函数,所以不会执行匿名函数体内的语句。 console.log("666"); })
匿名自执行函数(类似于JS的单例模式)
(function (){ console.log("666"); // 此处会打印666 })()
2. JS事件
HTML 事件是发生在 HTML 元素上的事情。
JavaScript 可以触发这些事件。
可以看做是用户的某些操作,或者说业务需要监听的某些操作
2.1 HTML事件
HTML 页面完成加载
HTML input 字段改变时
HTML 按钮被点击
常用事件整理2.2 JavaScript 事件一般用于做什么?
- 页面加载时触发事件
- 页面关闭时触发事件
- 用户点击按钮执行动作
- 验证用户输入内容的合法性
- …(用户的一切操作都可以监听)
2.3 事件实例
<input id="test" type="button" value="提交"/> <script> // 页面加载完触发 window.onload = function(){ let test = document.getElementById("test"); test.addEventListener("click",myfun2); test.addEventListener("click",myfun1); } function myfun1(){ alert("你好1"); } function myfun2(){ alert("你好2"); } </script>
3. JavaScript 对象
在JS里 —— 万物皆为对象
- 字符串也可以是一个对象
- 日期是一个对象
- 数学和正则表达式也是对象
- 数组是一个对象
- 函数也可以是对象
- …
3.1 对象定义
- 对象是变量的容器
- 写法以键值对的方式(键名:键值)
- 键值对称之为对象的属性
- 循环对象一般用 for in
// 对象定义 let person = { firstName:"ouyang", lastName:"xiu", age:18 }; // 循环对象 for(let key in person){ console.log(key); // 键名 console.log(person[key]) // 键值 }
3.2 大厂经典面试题分析
let obj = Object.create(null) 与 let obj = {} 有什么区别?
对象字面量创建对象与 Object.create(null)创建对象有什么区别?
一开始是有点懵的,不都是创建对象么,能有啥不同,后面我去试了一下,结果发现还蛮有意思:
let obj = {}; let obj2 = Object.create(null); console.log(obj); console.log(obj2)
控制台打印
- 乍一看,好像没啥区别,都是一个花括号
- 然而,展开后,确实大有不同
Object.create(null)创建的对象是非常纯净的,没有任何其它元素
而另一个let创建的对象是带有_proto_的,下面有一些方法与属性,这便是js的原型链继承,它继承了Object的方法和属性。这便是区别。
所以这种区别导致了使用场景不同
如果需要对象的继承属性和方法,那就使用 let obj = {};
如果只需要一个纯净的对象,那就使用 Object.create(null)
比如说,我只需要用对象来保存一些数据,然后进行循环取用,提高循环效率。
这个时候如果对象有原型链,那便会在循环的时候去循环它的各个属性和方法
然而这不是必要的,我们只是要他里面的元素而已,前者会影响循环效率
4. JavaScript prototype(原型对象)
- 此属性是函数特有的
- 每个函数都会默认添加一个
- 用于继承属性和方法
// 创建构造函数 function Person(name, age) { this.age = age; this.name= name; this.fn = function(){ console.log(this.name) } }
// 创建实例 let person1 = new Person("小明", 18); let person2 = new Person("小红", 20); person1.fn(); // 继承父级的方法 person2.fn(); console.log(person1) console.log(person2)
执行结果
- 要添加一个新的属性需要在在构造器函数中添加:
function Person(name, age, sex) { // sex为新属性 this.sex = sex; this.age = age; this.name= name; this.fn = function(){ console.log(this.name) } }
4.1 prototype 继承
所有的 JavaScript 对象都会从一个 prototype(原型对象)中继承属性和方法:
Date 对象从 Date.prototype 继承
Array 对象从 Array.prototype 继承
Person 对象从 Person.prototype 继承
所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例
JavaScript 对象有一个指向一个原型对象的链
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾(逐级查找)
Date 对象, Array 对象, 以及 Person 对象从 Object.prototype 继承。
4.2 添加属性和方法
function Person(name, age, sex) { // sex为新属性 this.sex = sex; this.age = age; this.name= name; this.fn = function(){ console.log(this.name) } } Person.prototype.newVal = "我是新添加在原型上的值"; let person1 = new Person("小明", 18); console.log(person1)
一样可以通过继承拿到