提示:以下是本篇文章正文内容,下面案例可供参考
更多web技术可参考 https://developer.mozilla.org/zh-CN/
一、作用域
作用域规定了变量能够被访问的范围,离开这个范围变量便不能被访问。
1.局部作用域
局部作用域分为函数作用域和块作用域
在函数内部声明的变量只能在函数内部被访问,外部无法直接访问。
在JavaScript中被{ }包裹的代码为代码块,代码块内部声明的变量外部可能无法访问。let声明的变量和const声明的常量会产生块作用域,var声明的变量不会产生块作用域。推荐使用let或const。
2.全局作用域
script标签和.js文件的最外层就是全局作用域,在此声明的变量可以被函数内部访问,任何其它作用域都可以被访问。尽可能少的声明全局变量,防止全局变量被污染。
3.作用域链
作用域链本质上是底层的变量查找机制。
在函数被执行时,会优先查找当前作用域中查找变量。
如果当前作用域查找不到会逐级查找父级作用域直至全局作用域。
4.垃圾回收机制
JS中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收
内存的生命周期
(1)内存分配
声明变量,函数,对象时,系统会自动为它们分配内存。
(2)内存使用
即读写内存,也就是使用函数,变量等。
(3)内存回收
使用完毕,由垃圾回收器自动回收不再使用的内存
全局变量一般不会回收(关闭页面回收)
一般情况,局部变量的值不用了会自动回收
程序中分配的内存由于某种原因未释放或无法释放叫做内存泄漏
5.闭包
一个函数对周围状态的引用绑定在一起,内层函数中访问到其外层函数的作用域。
简单理解:闭包=内层函数+外层函数的变量
闭包的简单写法
function outer(){
const a=1
function f(){
console.log(a)
}
f()
}
outer()
闭包的基本格式
function outer() {
let i = 1
function fn() {
console.log(i)
}
return fn
}
const fun = outer()
fun() // 1
//外层函数使用内部函数时,内部函数会保存外层函数的变量,形成闭包
闭包的作用:封闭数据,提供操作,外部也可以访问函数内部的变量
5.变量提升
在JS中,它允许变量声明之前即被访问(仅存在于var声明变量)
把所有var声明的变量提升到当前作用域的最前面,只提升声明,不提升赋值
var num
console.log(num + '个');
num = 10;
console.log(num)
let或const声明的变量不存在变量提升
ES6引入了块级作用域,用let或const声明变量,让代码写法更规范
二、函数进阶
1.函数提升
函数提升指函数在声明之前即可被调用
会把所有函数声明提升到当前作用域的最前面
只提升函数声明,不提升函数调用
//调用函数
fn()
//声明函数
function fn(){
console.log('函数提升')
}
2.函数参数
(1)动态参数
arguments是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参
function getSum() {
// arguments 动态参数 只存在于函数里面
// 是伪数组
console.log(arguments) // [Arguments] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }
}
getSum(1, 2, 3, 4, 5)
(2)剩余参数
…是语法符号,置于最末函数形参之前,用于获取多余的实参
借助…获取的剩余实参,是个真数组
function getSum(a, b, ...arr) {
console.log(arr)
}
getSum(1, 2)
getSum(1, 2, 3, 4, 5)
实际开发中建议多使用剩余参数
(3)展开运算符
展开运算符… 将一个数组进行展开
const arr1 = [1, 2, 3, 4, 5]
console.log(...arr1); //1 2 3 4 5
可以用在求数组最大值或最小值,合并数组等
const arr1 = [1, 2, 3, 4, 5]
console.log(Math.max(...arr1)); //5
console.log(Math.min(...arr1)); //1
const arr2 = [...arr1, 6, 7, 8, 9]
console.log(arr2) //[1, 2, 3, 4, 5, 6, 7, 8, 9]
3.箭头函数
箭头函数的语法比函数表达式更简洁,属于表达式函数,不存在函数提升
箭头函数没有arguments动态参数,但有…args剩余参数
箭头函数的this是上一层作用域的this指向
const fn = () => {
console.log(123)
}
fn() // 123
只有一个形参时,可以省略()
const fn = x => {
console.log(x)
}
fn(123) // 123
只有一行代码时,可以省略{ }
const fn = x => console.log(x)
fn(123) // 123
只有一行代码时,可以省略return
const fn = x => x + x
console.log(fn(1)) // 2
箭头函数可以直接返回一个对象
const fn = (uname) => ({ name: uname })
console.log(fn('张三')) // {name: "张三"}
三、解构赋值
解构赋值是一种快速为变量赋值的简洁语法,本质上仍是为变量赋值
1.数组解构
数组解构是将数组的单元值快速批量赋值给一系列变量的简洁语法
const arr = [1, 2, 3]
const [min, avg, max] = arr
console.log(min, avg, max) // 1 2 3
let a = 1
let b = 2;
[a, b] = [b, a]
console.log(a, b) // 2 1
JS前面必须加分号的情况
立即执行函数
(function t() {})();
;(function t() { })()
使用数组时
//数组开头的,特别是前面有语句的一定要加;
;[a, b] = [b, a]
实例
const pc = ['惠普', '联想', '戴尔']
const [hp, lx, de] = pc
console.log(hp, lx, de) //惠普 联想 戴尔
function getValue() {
return [10, 1];
}
let [max, min] = getValue()
console.log(max, min) // 10 1
let [a, b, ...c] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(a, b, c) // 1 2 [3, 4, 5, 6, 7, 8, 9]
//防止undefined,设置默认值
const [phone ='手机', computer = '电脑'] = ['小米']
console.log(phone, computer) // 小米 电脑
//按需导入赋值
let [a, b, , d] = [1, 2, 3, 4]
console.log(a, b, d) // 1 2 4
//多维数组
let arr = [1, 2, [3, 4, 5]]
let [a, b, [c]] = arr
console.log(a, b, c) // 1 2 3
console.log(arr[2]) // [3, 4, 5]
console.log(arr[2][0]) // 3
2.对象解构
对象解构是将对象属性和方法快速批量赋值给一系列变量的简洁语法
(1)对象解构
// let obj = {
// name: '张三',
// age: 18,
// sex: '男'
// }
// let {} = obj
let { name, age, sex } = { name: '张三', age: 18, sex: '男' } //等于 let name = obj.name
console.log(name, age, sex) // 张三 18 男
let { name: username, age, sex } = { name: '张三', age: 18, sex: '男' }
//等于 let name = obj.name
// 变量名和属性名必须相同, 变量解构的变量名可以改名,旧变量名: 新变量名
console.log(username, age, sex) // 张三 18 男
(2)数组对象解构
let obj = [{
name: '张三',
age: 18,
sex: '男'
}]
let [{ name, age, sex }] = obj
console.log(name, age, sex) // 张三 18 男
(3)多级对象解构
let goods = {
name: '苹果',
other: {
price: 10,
color: '红色',
size: '70mm'
},
}
let { name, other: { price, color, size } } = goods
console.log(name, price, color, size) // 苹果 10 红色 70mm
实例,利用对象解构只要msg中的data
let msg = {
"code": 200,
"msg": "success",
"data": [
{
"id": 1,
"name": "张三",
"age": 18
},
{
"id": 2,
"name": "李四",
"age": 20
},
{
"id": 3,
"name": "王五",
"age": 22
}
]
}
//利用解构只要data
// let { data } = msg
// 避免和msg的data冲突
function render({ data: myData }) {
//let {data} = arr
// 形参是{data},实参是msg,把实参给形参,然后把形参解构出来
console.log(myData)
}
render(msg)
四、遍历数组
forEach方法用于调用数组的每个元素,并将元素传递给回调函数。主要用来遍历数组的每个元素
let arr = ['red', 'green', 'blue']
arr.forEach(function (item, index) {
console.log(item, index) // red 0 green 1 blue 2
})
五、创建对象的方式
1.利用对象字面量创建对象
let people = {
name: '张三'
}
2.利用new Object创建对象
let people = new Object(
{
name: '张三'
}
)
let people = new Object()
people.name = '张三'
console.log(people) // {name: "张三"}
3.利用构造函数创建对象
构造函数主要用来初始化对象,通过使用构造函数可以快速创建多个类似的对象
构造函数命名以大写字母开头,只能由“new”操作符执行
使用“new”关键字调用函数的行为被称为实例化
实例化构造函数没有参数时可以省略( )
构造函数内部无需写return,返回值即为新创建的对象
构造函数内部return返回的值无效,所以不需要写return
new Object ( ) new Date ( ) 也是实例化构造函数
function people(name, age) {
this.name = name,
this.age = age
}
let p1 = new people('张三', 18)
let p2 = new people('李四', 20)
console.log(p1) // people {name: "张三", age: 18}
console.log(p2) // people {name: "李四", age: 20}
实例化执行过程:创建新对象,构造函数this指向新对象,执行构造函数,修改this,添加新属性,返回新对象
(1)实例成员
通过构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员
function people(name, age) {
this.name = name,
this.age = age
}
let p1 = new people('张三', 18)
p1.name = '王五' // 实例属性
p1.sayhi = function () {
console.log('hi')
} // 实例方法
(2)静态成员
构造函数的属性和方法称为静态成员
function people(name) {
this.name = name
}
people.id = 1 // 静态属性
people.sayhi = function () {
console.log('hi') // 静态方法
}
六、内置构造函数
1.Object
用于创建普通对象(更推荐使用字面量方式声明对象)
let people = new Object(
{
name: '张三'
}
)
静态方法只有构造函数Object可以调用
Object.keys静态方法获取对象中所有属性名(返回一个数组)
let people = {
name: '张三',
age: 18
}
let arr1 = Object.keys(people)
console.log(arr1) // ["name", "age"]
Object.values 静态方法获取对象中所有属性值(返回一个数组)
let people = {
name: '张三',
age: 18
}
let arr2 = Object.values(people)
console.log(arr2) // ["张三", 18]
Object.assign 静态方法常用于对象拷贝
let people = {
name: '张三',
age: 18
}
let obj = {}
Object.assign(obj, people)
console.log(obj) // {name: "张三", age: 18}
2.Array
用于创建数组(建议使用字面量来创建)
数组常见方法:forEach(遍历数组)、filter(过滤数组)、map(迭代数组)、reduce(累计器)
Array.from() 将伪数组转为数组
3.String
String() 构造函数创建 String 对象。当作为函数调用时,它返回 String 类型的原始值。
.length 长度属性
4.Number
Number() 构造函数创建 Number 对象。当作为函数调用时,它返回 Number 类型的原始值。
七、原型
1.原型(prototype)
每个对象(object)都有一个私有属性指向另一个名为原型(prototype)的对象。
构造函数通过原型分配的函数是所有对象共有的
所有对象的实例可以共享定义在原型对象上的方法
构造函数和原型对象的 this 指向 实例化对象
function people(name, age) {
this.name = name, //公共的属性写到构造函数中
this.age = age
}
people.prototype.sayhi = function () { //公共的方法写到原型对象中
console.log('hi')
}
let p1 = new people('张三', 18)
let p2 = new people('李四', 20)
p1.sayhi() // hi
p2.sayhi() // hi
console.log(p1.sayhi === p2.sayhi) // true
公共的属性写到构造函数中
公共的方法写到原型对象中
2.constructor属性
每个原型对象都有constructor属性,constructor属性指向该原型对象的构造函数
3.对象原型
对象都有一个属性_proto_ 指向构造函数的原型对象,所以对象能使用构造函数原型对象的属性和方法。
4.原型继承
利用原型对象实现继承
let Person = {
eyes: 2,
legs: 2
}
function Man() { }
// 通过原型继承Person
Man.prototype =
// 指回原来的构造函数
Man.prototype.constructor = Man
let p1 = new Man()
console.log(p1)
5.原型链
原型对象的继承使不同构造函数的原型对象关联在一起,原型对象的链状结构关系称为原型链。