JavaScript基础(函数-对象)

一、JavaScript基础

函数
函数的声明
/**
 * function 函数名(参数列表) {
 *      函数体
 * }
 *
 * 调用方法没有传入实参时,则默认形参为 undefined
 *
 * 合理利用逻辑中断
 *      形参如果不被赋值,就是undefined
 */
function getSum(Start, end) {
    Start = Start || 0 // 调用方法没有传入实参时,默认形参为0
    end = end || 0
    let sum = 0
    for (let i = Start; i <= end; i++) {
        sum += i
    }
    console.log(sum)
}

注意点
  两个相同的函数后面的会覆盖前面的函数

函数的传参

术语1:
  在声明函数的小括号里面写的数值我们称之为形式参数
术语2:
  在调用函数的小括号里面写的数值我们称之为实际参数
形参作用:
  本质上就是在函数内部声明变量

补充
  在Javascript中 实参的个数和形参的个数可以不一致
    ①如果形参过多 会自动填上undefined (了解即可)
    ②如果实参过多 那么多余的实参会被忽略 (函数内部有一个arguments,里面装着所有的实参)

function fnOne(x, y) {
	console.log(arguments)
	// x = 1
	// y = undefined
	// 1 + undefined  =  NaN
	console.log('fnOne', x + y)
}

fnOne(1, 2) // 3

// 1. 实参个数少于形参 函数执行失败 返回的结果:NaN
fnOne(1) // NaN
/* 2. 实参个数大于形参 函数能执行成功
* 实参存入 arguments 数组
* arguments:函数内有效
*      表现形式:伪数组
*          伪数组 比真数组少了 pop()  push() 等方法
*/
fnOne(1, 2, 3) // 返回的结果:3

/***************** 小技巧 *****************/
function fnTwo(x = 0, y = 0) {
	console.log(arguments)
	console.log('fnTwo', x + y)
}
fnTwo() // 0
函数的调用和返回值
/********************* 多个返回值 *********************/
// 求最大值和最小值
function getArrMaxValue(arr) {
 let max = arr[0]
 let min = arr[0]
 for (let i = 1; i < arr.length; i++) {
     max < arr[i] ? max = arr[i] : min > arr[i] ? min = arr[i] : min
 }

 // 返回这个最大值和最小值
 return [max, min]
}

let maxMin = getArrMaxValue([1, 6, 2, 9, 3]) // [9, 1]
let max = maxMin[0]
let min = maxMin[1]
console.log('maxMin', maxMin)
console.log('max', max)
console.log('min', min)
函数表达式

一、匿名函数
  将匿名函数赋值给一个变量,并且通过变量名称进行调用,我们将这个称为函数表达式

let fn02 = function (x, y) {
     console.log(x + y)
 }
 fn02(1, 2)

二、自执行(匿名函数自执行)
  场景介绍: 避免全局变量之间的污染

/***************** 使用函数表达式-立即执行函数 *****************/
// 写法一 (function () {})()
(function () {
	console.log(num)
})();

// 写法二 (function () {}())
(function (x, y) {
	console.log(x + y)
}(1, 2));

// 特殊情况 及时给出名字,也会被立即执行
(function fn(x, y) {
	console.log(x + y)
}(1, 2))
作用域

通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。

全局作用域局部作用域块级作用域
全局有效局部有效{}内有效
作用于所有代码执行的环境(整个script标签内部)或者一个独立的js文件作用于函数内的代码环境,就是局部作用域。因为跟函数有关系,所以也称为函数作用域。函数内部的形参可以当做局部变量块作用域由{}包括,if语句和for语句里面的{}等

有一种特殊情况是全局变量
    局部变量或者块级变量没有 let 声明,直接赋值的,当全局变量看 【强烈不提倡】

全局变量局部变量块级变量
函数外部let的变量函数内部let的变量{}内部的let变量
全局变量在任何区域都可以访问和修改局部变量只能在当前函数内部访问和修改let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访
环境对象

环境对象指的是函数内部特殊的变量this,它代表着当前函数运行时所处的环境
作用:
  弄清楚this的指向,可以让我们代码更简洁
函数的调用方式不同,this指代的对象也不同
  【谁调用, this 就是谁】是判断this指向的粗略规则

函数进阶
函数的声明方式
// 函数声明方式 function 关键字 (命名函数)
function fn() {}

// 函数表达式 (匿名函数)
let fun = function() {}

// new Function('参数1','参数2'..., '函数体')
let f = new Function('a', 'b', 'console.log(a+b)')
f(1, 2)
// 所有函数都是 Function 的实例(对象)
console.dir(f);
函数的调用方式
// 普通函数
function fn() {
 console.log('人生的巅峰')
}
fn()

// 对象的方法
let o = {
 sayHi: function () {
     console.log('人生的巅峰');
 }
}
o.sayHi()

// 构造函数
function Star() {}
let star = new Star()

// 绑定事件函数
btn.addEventListener('click', function () {})

// 定时器函数
setInterval(function() {}, 1000)

// 立即执行函数
(function () {
 console.log('人生的巅峰')
})();
改变环境变量
/**
 * call() 方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的 this 指向
 * fun.call(thisArg, arg1, arg2, ...)
 * thisArg:在 fun 函数运行时指定的 this 值
 * arg1,arg2:传递的其他参数
 * 返回值就是函数的返回值,因为它就是调用函数
 * 因此当我们想改变 this 指向,同时想调用这个函数的时候,可以使用 call,比如继承
 */

/**
 * apply() 方法调用一个函数。简单理解为调用函数的方式,但是它可以改变函数的 this 指向
 * fun.apply(thisArg, [argsArray])
 * thisArg:在fun函数运行时指定的 this 值
 * argsArray:传递的值,必须包含在数组里面
 * 返回值就是函数的返回值,因为它就是调用函数
 * 因此 apply 主要跟数组有关系,比如使用 Math.max() 求数组的最大值
 */
let arr = [1, 2, 3, 4, 5]
let max = Math.max.apply(Math, arr)
console.log(max);

/**
 * bind() 方法不会调用函数。但是能改变函数内部this 指向
 * fun.bind(thisArg, arg1, arg2, ...)
 * thisArg:在 fun 函数运行时指定的 this 值
 * arg1,arg2:传递的其他参数
 * 返回由指定的 this 值和初始化参数改造的原函数拷贝
 * 因此当我们只是想改变 this 指向,并且不想调用这个函数的时候,可以使用 bind
 */
高阶函数

函数表达式
  把函数当值赋值给变量
回调函数
  把一个函数作为参数传递给另外一个函数

递归函数

利用递归函数求斐波那契数列

// 利用递归函数求斐波那契数列(兔子序列)  1、1、2、3、5、8、13、21...
// 用户输入一个数字 n 就可以求出 这个数字对应的兔子序列值
// 我们只需要知道用户输入的n 的前面两项(n-1 n-2)就可以计算出 n 对应的序列值
function fb(n) {
 if (n === 1 || n === 2) {
     return 1;
 }
 return fb(n - 1) + fb(n - 2);
}
console.log(fb(6)); // 8

利用递归遍历数据

let data = [
 {
     id: 1,
     name: '家电',
     goods: [
         {
             id: 11,
             goodName: '冰箱',
             goods: [
                 {
                     id: 111,
                     goodName: '海尔'
                 },
                 {
                     id: 112,
                     goodName: '美的'
                 }
             ]
         },
         {
             id: 12,
             goodName: '洗衣机'
         }
     ]
 },
 {
     id: 2,
     name: '服饰'
 }
]
function getGoodById(data, id) {
 let obj = {}
 data.forEach(function (value) {
     if (value.id === id) {
         obj = value
     } else if (value.goods && value.goods.length) {
         obj = getGood(value.goods, id)
     }
 })
 return obj
}
console.log(getGoodById(data, 1))
console.log(getGoodById(data, 11))
console.log(getGoodById(data, 111))
对象
声明对象的语法

1、我们把冒号左边的内容称之为属性, 右边称之为值, 成对出现, 故称之为键值对
2、当右边的值为函数的时候, 我们将这个属性称之为方法
3、对象本质是一种无序的数据集合, 对比数组来说它里面装的都是不同类型的数据, 并且有对应的属性提示数据的含义
4、对象访问属性的方式
  ①对象.属性名
  ②对象[‘属性名’]

/**
 * 对象有属性和方法组成
 * let 对象名= {
 *      属性名:属性值,
 *		方法名:函数
 * }
 */
let phone = {
	name: '小米10青春版',
	num: '100012816024',
	weight: '0.55kg',
	address: '中国大陆',
	sayHey: function () {
	console.log("Hello js!")
	}
}
// 输出对象
console.dir('phone', phone)
// 1.访问对象里面的属性 对象.属性名
console.log('phone.name', phone.name)
// 2.访问对象里面的属性 对象[属性名]
console.log('phone.name', phone['name'])
// 3.访问对象里面的方法 对象.方法名()
phone.sayHey()
使用对象

操作数据的增删改查语法:
  查询对象:
    对象.属性
    对象.[‘属性’]
    对象.方法()
  重新赋值:
    对象.属性 = 值
    对象.方法 = function(){}
  对象添加新的数据:
    对象名.新属性名 = 新值
  删除对象中属性:
    delete 对象名.属性名

let obj = {
	username: '小明',
	age: 18
}
// 修改属性值
obj.age = 21
// 新增属性
obj.sex = '男'
// 删除属性
delete obj.sex
遍历对象

引入[]语法操作对象属性
  对比点语法的相同点和不同点
    都可以访问对象的属性 对象名.属性名 === 对象名[‘属性名’]
    []语法里面的值如果不添加引号 默认会当成变量解析
    没有必要的时候直接使用点语法, 在需要解析变量的时候使用 [] 语法
遍历对象
  对象没有length属性,所以无法确定长度
  对象里面是无序的键值对, 没有规律

let phone = {
	name: '小米10青春版',
	num: '100012816024',
	weight: '0.55kg',
	address: '中国大陆'
}
// 遍历对象的属性值
for (let phoneKey in phone) {
	// phoneKey 变量名
	console.log(phoneKey, phone[phoneKey]) // 不能使用phone.phoneKey
}
内置对象
console.log(Math.random()) // 随机数
console.log(Math.ceil(1.66)) // 2 向上取整
console.log(Math.floor(1.66)) // 1 向下取整

console.log(Math.round(1.33)) // 1 就近取整 四舍五入
console.log(Math.round(1.5)) // 2
console.log(Math.round(-1.5)) // -1 特殊(.5往大取整)
console.log(Math.round(1.66)) // 2

console.log(Math.max(1.66, 1.56, 2.999)) // 找最大数

Math.floor(Math.random() * (10 + 1)) // 生成0-10的随机数
Math.floor(Math.random() * (5 + 1)) + 5 // 生成5-10的随机数
Math.floor(Math.random() * (M + N + 1)) + N // 生成N-M之间的随机数
操作对象(进阶&积累)

①封装对象自身所有的属性

let obj = {id: 1, pName: '小米', price: 1999, num: 2000}

let arrKeys = Object.keys(obj); /** 返回一个由属性名组成的数组 */
let arrValues = Object.values(obj) /** 返回一个由属性值组成的数组 */
console.log(arrKeys) // ['id', 'pName', 'price', 'num']
console.log(arrValues) // [1, '小米', 1999, 2000]

②浅拷贝

Object.assign(objNew,objOld)

③定义新属性或修改原有的属性

let obj = {id: 1, pName: '小米', price: 1999}
Object.defineProperty(obj, 'num', {
/* 设置属性的值  默认为undefined 
value: 1000,
/** 值是否可以重写。true | false  默认为false */
writable: false,
/** 目标属性是否可以被枚举。true | false 默认为 false */
enumerable: false,
/** 目标属性是否可以被删除或是否可以再次修改特性 true | false  默认为false */
configurable: false
});
console.log(Object.keys(obj)); // ['id', 'pName', 'price']

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值