内置对象:数组对象方法
1.连接数组arr.concat(数组)
//声明数组
let arr = [10,20,30]
//(1) arr.concat(数组) : 把两个数组连接成一个数组
//应用场景: 一般用于长列表(下一页),不断往后面拼接数组
let newArr = arr.concat([40,50])
console.log(newArr)//[10,20,30,40,50]
2.翻转数组arr.reverse()
let arr = [10,20,30]
//(2) arr.reverse() : 翻转数组
//应用场景: 价格从低到高 切换成 从高到低, 只需要翻转数组即可
arr.reverse()
console.log( arr )//[30,20,10]
3.拼接arr.join(‘分隔符’)
//(3) arr.join('分隔符') : 把数组每一个元素拼接成字符串
let arr1 = [80,90,55,60]
//应用场景 : 有些歌曲是多个人合唱,服务器会给我们一个数组。 这个时候就需要将数组元素通过join拼接起来然后再页面显示
let str = arr1.join('&')
console.log( str )//80&90&55&60
4.排序arr.sort(function(a,b){return a-b // return a-b //从小到大 //return b-a //从大到小})
//(4) arr.sort( function(a,b){return a-b} ) : 排序
let arr = [10,30,2]
arr.sort( function(a,b){
// return a-b //从小到大
return b-a //从大到小
} )
console.log(arr)//[30,10,2]
字符串对象
** 1. 字符串类似于数组,也有长度和下标**
let str='我要去曦度看武'
//1. 字符串类似于数组,也有长度和下标
console.log( str.length )//7
console.log( str[5] )//看
2. str.indexOf(‘字符串’) 获取 ‘字符串’ 在str中的首字母下标 如果字符串存在则返回首字母下标, 如果字符串不存在则返回固定值 -1 应用场景: 一般用户判断 str中是否有某个字符串 如果没有则返回-1,不是-1说明有
let str='我要去曦度武'
let index1=str.indexOf('度武')//4
let index1=str.indexOf('去武')//-1
3. str.split(‘分隔符’) 用分隔符切割字符串,得到切割之后的数组 应用场景 : 一般用户解析 网址
let url = 'http://www.baidu.com?name=张三&age=20'
console.log( url.split('|') )//['http://www.baidu.com?name=张三&age=20']
console.log( url.split('?') )//['http://www.baidu.com', 'name=张三&age=20']
console.log( url.split('=') )//['http://www.baidu.com?name', '张三&age', '20']
**4. str.substr(起始下标,截取长度) 截取字符串 应用场景 : 一般后台返回的数据 不会和前端完全匹配。 有时候需要自己截取一部分 例如: 商品价格后台返回 :价格58元 但是前端只需要显示58元,就需要截取 **
let str='我要去曦度看武剑仙降临'
console.log( str.substr(2,5) )//从2下标开始,往后截取5个字 //曦度看武剑仙
5.大小写转换 (中文没有大小写) 应用场景: 字母验证码不区分大小写 (一般无论你输入什么,都会转成大写或小写保持格式统一)
console.log('dsSFJSGDJHsdfs'.toLocaleLowerCase() )//小写 dssfjsgdjhsdfs
console.log('dsSFJSGDJHsdfs'.toLocaleUpperCase() )//大写 DSSFJSGDJHSDFS
原型对象:
一.构造函数
1.工厂函数(了解) : 用于创建对象的函数
2.构造函数 : 使用new调用一个函数
构造函数作用与工厂函数一致,都是用来创建对象的。但是代码更加简洁。
3.构造函数new工作原理
(1)创建空对象
(2)this指向这个对象
(3)对象赋值
(4)返回这个对象
4.构造函数new在使用时需要注意的地方
4.1 构造函数首字母一般大写, 为了提醒调用者不要忘记new关键字
4.2 如果在构造函数内部 手动return
return 值类型 : 无效,还是返回new创建的对象
return 引用类型 : 有效,会覆盖new创建的对象
function Person(name,age,sex){
//(1)创建空对象 {}
//(2)this指向这个对象 this = {}
//(3)对象赋值
this.name = name
this.age = age
this.sex = sex
//(4)返回这个对象 return this
}
let p1 = new Person('嘿嘿嘿',23,'男')
console.log(p1)//{name:'嘿嘿嘿',age:23,sex:'男'}
二.原型函数
(1)构造函数内部方法: 浪费内存资源 2.使用全局函数解决内存浪费3.使用对象 : 解决内存浪费 + 变量污染
// function Person(name,age){
// this.name = name
// this.age = age
// this.eat = function(){
// console.log('eat');
// }
// }
// let p1 = new Person('张三',18)
// let p2 = new Person('李四',20)
// console.log( p1,p2)
/* 思考: p1和p2都有eat方法,而是函数体相同。但是他们是同一个函数吗?
不是同一个: 因为每一次调用构造函数, 内部都会执行一次function,就会在堆中开辟一个新的空间。虽然代码是一样的,但是地址不同。 就会导致每调用一次构造函数,多出一个函数堆空间。导致内存资源浪费
*/
// console.log( p1.eat == p2.eat )//false
/* 2.使用全局函数解决内存浪费
导致新的问题: 全局变量污染
*/
// let eat = function() {
// console.log("吃东西")
// }
// let learn = function() {
// console.log("学习")
// }
// function Person(name, age) {
// this.name = name
// this.age = age
// this.eat = eat
// this.learn = learn
// }
// let p1 = new Person("张三", 18)
// let p2 = new Person("李四", 20)
// console.log(p1, p2)
/* 思考题:p1的eat和p2是不是同一个
答案:是的 因为构造函数内部并没有重新function创建一个函数,而是拷贝eat的地址赋值。 无论你调用构造函数多少次,都是拷贝eat的地址
*/
// console.log( p1.eat == p2.eat )//true
/* 3.使用对象 : 解决内存浪费 + 变量污染 */
let obj = {
eat: function() {
console.log("吃东西")
},
learn: function() {
console.log("学习")
}
}
function Person(name, age) {
this.name = name
this.age = age
this.eat = obj.eat
this.learn = obj.learn
}
let p1 = new Person("张三", 18)
let p2 = new Person("李四", 20)
console.log(p1, p2)
三.原型对象
** 原型继承 :把父对象 作为子对象构造函数的原型
1.原型对象是什么? : 任何函数在声明的时候,系统会自动帮你创建一个对象,称之为原型对象
2.原型对象作用? : 解决 内存浪费 + 变量污染
3.原型对象相关三个属性 : 描述 构造函数、原型对象、实例对象三者关系
(1)prototype : 属于构造函数, 指向原型对象
(2)proto : 属于实例对象,指向原型对象, proto : 属于实例对象的,指向原型对象
注意: 这个属性不是web标准,很多浏览器不会显示的。 这个属性在开发中不能使用,只能用于学习研究
(3) constructor : 属于原型对象,指向构造函数
**
/*
1.原型对象是什么? : 任何函数在声明的时候,系统会自动帮你创建一个对象,称之为原型对象
2.原型对象作用? : 解决 内存浪费 + 变量污染
3.原型对象相关三个属性
*/
//构造函数
function Person(name, age) {
this.name = name
this.age = age
}
//原型对象
console.log(Person.prototype)
Person.prototype = {
eat: function() {
console.log("吃东西")
},
learn: function() {
console.log("学习")
}
}
//实例对象 : 用new调用构造函数,返回的那个对象(new创建的那个对象)
let p1 = new Person('张三',20)
console.log( p1 )
let p2 = new Person('李四',22)
console.log( p1.eat == p2.eat )//true
四.获取对象所有的属性值
(1)以前 for-in 循环
//1 以前的写法: for-in 循环
for(let key in person ){
console.log( person[key] )
}
(2)现在:
//2.静态方法 Object.values(对象名)
//返回值是一个数组,会存储对象每一个属性值
let arr = Object.values(person)
console.log(arr)
面向对象的三大特征
面向对象三大特征: 封装 、 继承 、 多态
1.封装 : 把代码放入对象的方法中
2.继承 : 一个对象 拥有 另一个对象 所有的成员
3.多态 : 一个对象 在不同情况下的不同状态
js语言基本不涉及多态
2.1原型继承 :把父对象 作为子对象构造函数的原型
<script>
/*
1.继承 : 一个对象 拥有 另一个对象 所有的 成员
2.原型继承 :把父对象 作为子对象构造函数的原型
*/
//父对象
let father = {
house:{
address : '深圳湾一号',
price: 20000000
},
car:{
brand : '劳斯莱斯幻影',
price:15000000
}
}
//子对象
//构造函数
function Son(name,age){
this.name = name
this.age = age
}
//原型继承: 把父对象 作为子对象构造函数的原型
Son.prototype = father
//可选 : 原型继承之后,由于父对象覆盖原来的 子对象构造函数原型, 就会导致constructor消失.
//解决办法: 手动添加。(对开发几乎没有影响,也可以不加)
Son.prototype.constructor = Son
//实例对象
let s1 = new Son('ikun',30)
let s2 = new Son('班长',20)
console.log(s1,s2)
</script>
原型链
<script>
/*
1.原型链 : 每一个对象都有自己的原型, 而原型也是对象,也会有自己的原型,此次类推形成链式结构。称之为原型链。(原型链的终点是null)
2.对象访问原型链规则 : 就近原则
* 对象先访问自己的,自己没有就找原型的,原型没有就找原型的原型,一直到原型链终点null.如果还找不到。 属性则获取undefined, 方法则会报错 xxx is not function
*/
//1.构造函数
function Person(name,age){
this.name = name
this.age = age
// this.type = '学生'//如果自己有type,优先访问自己的
}
//2.原型对象 : 存储具有共同特征的数据
Person.prototype.type = '哺乳动物'
Person.prototype.country = '中国'
Person.prototype.eat = function(){
console.log(this.name + '吃东西')
}
//3.实例对象
let p1 = new Person('班长',20)
let p2 = new Person('ikun',20)
console.log(p1)
/* 小测试 */
console.log( p1.name )//班长 p1自己有name属性
console.log( p1.age )//20 p1自己有age
console.log( p1.type )//哺乳动物 p1自己没有type,但是p1的原型有
console.log( p1.girlFrined )//undefined p1自己没有girlFrined, p1的原型也没有girlFrined
p1.eat()// 吃东西
// p1.learn()//报错 undefined is not a function
/* 思考: p1自己没有toString, p1的原型也没有toString, 但是为什么不报错呢?
原因: p1的原型的原型有toString
*/
p1.toString()
/* 如何查看实例对象原型 : 两行 */
//查看p1的原型
console.log( p1.__proto__.constructor )//Person
console.log( Person.prototype === p1.__proto__ )//true
//查看p1的原型的原型
console.log( p1.__proto__.__proto__.constructor )//Object
console.log( Object.prototype === p1.__proto__.__proto__ )//true
//查看p1的原型的原型的原型
console.log( p1.__proto__.__proto__.__proto__ )//null
</script>
内置对象
<script>
// 数组对象
//实例化对象
let arr = [10,20,30]//new Array(10,20,30)
console.log( arr )
//1.1 查看arr的原型
console.log( arr.__proto__.constructor )//Array
console.log( arr.__proto__ === Array.prototype )//true
//1.2 查看arr的原型的原型
console.log( arr.__proto__.__proto__.constructor )//Object
console.log( arr.__proto__.__proto__ === Object.prototype )//true
// 字符串对象
let str = new String('abc')
console.log( str )
//2.1 查看str的原型
console.log( str.__proto__.constructor )//String
console.log( str.__proto__ === String.prototype )//true
//2.2 查看arr的原型的原型
console.log( str.__proto__.__proto__.constructor )//Object
console.log( str.__proto__.__proto__ === Object.prototype )//true
// 日期对象
let date = new Date()
/* js有几个特殊的对象 无法使用 log来打印的,需要用dir来打印: function date dom对象 */
console.dir( date )
//3.1 查看date的原型
console.log( date.__proto__.constructor )//Date
console.log( date.__proto__ === Date.prototype )//true
//3.2 查看date的原型的原型
console.log( date.__proto__.__proto__.constructor )//Object
console.log( date.__proto__.__proto__ === Object.prototype )//true
</script>
instanceof(关键字)
<script>
/*
1. instanceof(关键字): 运算符。 用于检测 构造函数的prototype在不在实例对象的原型链中
说人话: 亲子鉴定,鉴定两个对象之间有没有血缘关系
2. 实例对象 instanceof 构造函数
检测 右边构造函数的prototype 在不在 左边实例对象的原型链中
3. 应用 : 某些函数为了限制你的数据类型,在内部需要用instanceof进行判断是否是正确的数据类型
*/
let arr = [10,20,30]
// arr-> Array.prototype -> Object.prototype -> null
console.log( arr instanceof Array )//true
console.log( arr instanceof Object )//true
console.log( arr instanceof String )//false
//封装一个函数,要求这个函数必须要传数组类型、 传其他类型不可以
function fn(arr){
if( arr instanceof Array){
console.log( arr.reverse() )
}else{
console.log('数据类型错误')
}
}
fn( [10,20,30] )
fn( 'abc' )
</script>
面向对象封装消息提示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>面向对象封装消息提示</title>
<style>
.modal {
width: 300px;
min-height: 100px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
border-radius: 4px;
position: fixed;
z-index: 999;
left: 50%;
top: 50%;
transform: translate3d(-50%, -50%, 0);
background-color: #fff;
}
.modal .header {
line-height: 40px;
padding: 0 10px;
position: relative;
font-size: 20px;
}
.modal .header i {
font-style: normal;
color: #999;
position: absolute;
right: 15px;
top: -2px;
cursor: pointer;
}
.modal .body {
text-align: center;
padding: 10px;
}
.modal .footer {
display: flex;
justify-content: flex-end;
padding: 10px;
}
.modal .footer a {
padding: 3px 8px;
background: #ccc;
text-decoration: none;
color: #fff;
border-radius: 2px;
margin-right: 10px;
font-size: 14px;
}
.modal .footer a.submit {
background-color: #369;
}
</style>
</head>
<body>
<button id="btn1">消息提示1</button>
<button id="btn2">消息提示2</button>
<button id="btn3">消息提示3</button>
<button id="btn4">消息提示4</button>
<!-- <div class="modal">
<div class="header">提示消息 <i>x</i></div>
<div class="body">消息内容</div>
<div class="footer">
<a href="javascript:;" class="cancel">取消</a>
<a href="javascript:;" class="submit">确认</a>
</div>
</div> -->
<script>
//1. 模态框构造函数
function Modal(title,message){
this.title = title
this.message = message
this.modalBox = `<div class="modal">
<div class="header">${
this.title} <i>x</i></div>
<div class="body">${
this.message}</div>
</div>`
}
//2. 模态框原型
Modal.prototype.open = function(){
//(1)创建空标签
let div = document.createElement('div')
//(2)设置标签内容
div.innerHTML = this.modalBox
//(3)添加到页面
document.body.appendChild(div)
//给删除按钮注册点击事件
div.querySelector('.header i').onclick = function(){
document.body.removeChild(div)
}
}
//1.确认框构造函数
function Confirm(title,message){
this.title = title
this.message = message
this.modalBox = ` <div class="modal">
<div class="header">${
this.title} <i>x</i></div>
<div class="body">${
this.message}</div>
<div class="footer">
<a href="javascript:;" class="cancel">取消</a>
<a href="javascript:;" class="submit">确认</a>
</div>
</div>`
}
/* 为什么要继承: confirm确认框和 modal模态框 功能是一样的, 也要显示到页面,也要点击xx移除
1.继承 : 一个对象 继承 另一个对象 所有的成员
2.原型继承 : 把父对象 作为 子对象构造函数的原型
*/
Confirm.prototype = Modal.prototype
//继续给Confirm的原型添加自己的方法
Confirm.prototype.addEvent = function( confirm ){
let modal = document.querySelector('.modal')
modal.querySelector('.submit').onclick = function(){
//调用函数
confirm()
//移除模态框
modal.parentNode.removeChild(modal)
}
modal.querySelector('.cancel').onclick = function(){
//移除模态框
modal.parentNode.removeChild(modal)
}
}
//弹窗1
document.querySelector('#btn1').onclick = function(){
//创建模态框
let m = new Modal('友情提示','删除成功')
m.open()
console.log( m )
}
//弹窗2
document.querySelector('#btn2').onclick = function(){
//创建模态框
let mm = new Modal('提示消息','您没有权限操作')
mm.open()
}
//弹窗3
document.querySelector('#btn3').onclick = function(){
//创建确认框
let c = new Confirm('友情提示','您确定要删除吗?')
console.log(c)
c.open()
//添加确认功能
c.addEvent( function(){
alert('删除成功')} )
}
//弹窗4
document.querySelector('#btn4').onclick = function(){
//创建确认框
let c = new Confirm('友情提示','您确定要下单吗?')
c.open()
//添加确认功能
c.addEvent(function(){
alert('下单成功')
})
}
</script>
</body>
</html>
arguments关键字:
<script>
/*
1. arguments关键字: 获取函数所有的 实参
是一个伪数组 : 有数组三要素(元素、下标、长度),但是不能使用数组的方法
2. 应用 : 一般用户参数数量不限的函数.
例如: arr.push() Math.max() 这些函数实参数量不限,底层原理就是使用arguments来接收所有的实参
*/
function fn(a,b){
console.log(a)
console.log(b)
console.log(a+b)
console.log(arguments)
}
fn()
fn(10)
fn(10,20)
fn(10,20,30)
fn(10,20,30,40)
</script>
剩余的
<script>
/*
1. arguments关键字: 获取函数所有的 实参
是一个伪数组 : 有数组三要素(元素、下标、长度),但是不能使用数组的方法
2. 应用 : 一般用户参数数量不限的函数.
例如: arr.push() Math.max() 这些函数实参数量不限,底层原理就是使用arguments来接收所有的实参
3. 剩余参数(rest参数) : 获取函数剩余的所有实参
语法: function 函数名(形参1,...形参2){
}
特点: (1)只能作为最后一个参数 (2)是真数组
4. 一般情况下,rest参数可以替代arguments
*/
function fn(...b){
console.log(b)//10
console.log(arguments)
}
fn(10)
fn(10,20)
fn(10,20,30)
fn(10,20,30,40)
</script>
函数默认参数
<script>
/*
1. arguments关键字: 获取函数所有的 实参
是一个伪数组 : 有数组三要素(元素、下标、长度),但是不能使用数组的方法
2. 应用 : 一般用户参数数量不限的函数.
例如: arr.push() Math.max() 这些函数实参数量不限,底层原理就是使用arguments来接收所有的实参
3. 剩余参数(rest参数) : 获取函数剩余的所有实参
语法: function 函数名(形参1,...形参2){
}
特点: (1)只能作为最后一个参数 (2)是真数组
4. 一般情况下,rest参数可以替代arguments
5. 函数默认参数
function 函数名(形参=默认值){
}
*/
function fn(a=10,b=20){
//以前: 逻辑或短路
// 找真 : 左边是真就返回左边式子的值,否则返回右边式子的值
// a = a || 10
// b = b || 20
console.log( a + b )
}
fn(5)
</script>
环境对象 this
<script>
/*
环境对象 this : 谁'调用'我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建实例对象
* 小技巧: 没点没new是window, 有new是实例,有点是点左边的对象
*/
function fn(){
console.log( this )
}
//普通函数 : window
fn()
//构造函数 : new创建实例对象
new fn()
let obj = {
name:'张三',
eat:fn
}
//对象方法 : obj对象
obj.eat()
</script>
<script>
/*
环境对象 this : 谁'调用'我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建实例对象
* 小技巧: 没点没new是window, 有new是实例,有点是点左边的对象
*/
//作用域链
let obj = {
name: "张三",
eat: function() {
//1级链
console.log(this) //1.obj
function fn() {
//2级链
console.log(this) //2.window
}
fn()
}
}
let eat = obj.eat
obj.eat()
</script>
函数上下文调用
call()调用函数
<script>
/*
1.环境对象 this : 谁'调用'我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建实例对象
*** 默认情况下,函数内部的this不能主动修改. 如果需要修改,则需要使用上下文方式
2.上下文调用 : 修改函数内部的this
2.1 函数名.call(修改后的this,形参1,形参2…………)
2.2 函数名.apply()
2.3 函数名.bind()
3. 面试必问: call 和 apply 和 bind三者区别
*/
function fn(a,b){
console.log( a + b )
console.log( this )
}
// 函数名.call(修改后的this)
fn.call({
name:'张三'},10,20)
</script>
<script>
/* 伪数组 : 有数组三要素(下标,元素,长度),但是没有数组的方法
伪数组本质是对象
*/
let weiArr = {
0:88,
1:20,
2:50,
3:60,
length:4
}
console.log( weiArr )
//如果希望伪数组也可以调用数组的方法(排序、拼接),就需要把伪数组转成真数组
/*
1. slice可以查询数组,默认情况下不传参这个方法会得到数组本身
2. 但是伪数组由于原型不是Array,所以无法调用slice
3. slice方法存储在哪里? : Array.prototype
*/
weiArr = Array.prototype.slice.call(weiArr)
console.log(weiArr)
// weiArr.slice()
//实际开发中,ES6新增语法用于伪数组转真数组 : Array.from(伪数组)
let arr = Array.from(weiArr)
console.log( arr )
</script>
<script>
/*
1. typeof 数据 : 有两种数据类型无法检测
null和数组无法检测,结果都是 'object'
2. 解决方案:万能数据类型检测
Object.prototype.toString.call(数据)
*/
//值类型
let str = 'abc'
let num = 123
let bol = true
let und = undefined
let nul = null
//引用类型
let arr = [10,20,30]
let fn = function(){
}
let obj = {
name:'张三'}
console.log( typeof str )//'string'
console.log( typeof num )//'number'
console.log( typeof bol )//'boolean'
console.log( typeof und )//'undefined'
console.log( typeof nul )//'object'
console.log( typeof arr )//'object'
console.log( typeof fn )//'function'
console.log( typeof obj )//'object'
/* Object.prototype.toString() 返回固定格式字符串 '[object 数据类型]' */
console.log( Object.prototype.toString.call( str ) )//[object String]
console.log( Object.prototype.toString.call( num ) )//[object Number]
console.log( Object.prototype.toString.call( bol ) )//[object Boolean]
console.log( Object.prototype.toString.call( und ) )//[object Undefined]
console.log( Object.prototype.toString.call( nul ) )//[object Null]
console.log( Object.prototype.toString.call( arr ) )//[object Array]
console.log( Object.prototype.toString.call( fn ) )//[object Function]
console.log( Object.prototype.toString.call( obj ) )//[object Object]
</script>
apply(修改后的this, 数组或伪数组 )
<script>
/*
1.环境对象 this : 谁'调用'我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建实例对象
2.上下文调用 : 修改函数内部的this
2.1 函数名.call(修改后的this,形参1,形参2…………)
2.2 函数名.apply(修改后的this, 数组或伪数组 )
2.3 函数名.bind()
3. 面试必问: call 和 apply 和 bind三者区别
*/
function fn(a,b){
console.log( a + b )
console.log( this )
}
// 函数名.call(修改后的this,形参1,形参2…………)
fn.call({
name:'张三'},10,20)
// 函数名.apply(修改后的this, 数组或伪数组 )
// apply会自动帮你遍历数组,然后按照顺序逐一传参
fn.apply({
name:'李四'}, [30,40] )
</script>
<script>
//伪数组 本质是 : 对象
let obj = {
0:20,
1:66,
2:88,
3:90,
length:4
}
//伪数组转真数组
let arr = []
// arr.push( obj[0],obj[1],obj[2],obj[3])
//借助 apply自动遍历数组/伪数组 逐一传参特点
//这里不需要修改this,只是借助apply传参的特点. this指向原来是谁,还是设置谁
arr.push.apply( arr,obj )
console.log(arr)
//伪数组转真数组 : Array.from( 伪数组 )
console.log( Array.from(obj) )
</script>
<script>
//求数组最大值
let arr = [20,50,66,100,30]
//1.js基础 : 擂台思想
let max = arr[0]
for(let i = 1;i<arr.length;i++){
if( arr[i] > max ){
max = arr[i]
}
}
console.log(max)
//2. Math.max()
// let max1 = Math.max(arr[0],arr[1],arr[2],arr[3],arr[4])
//这里使用apply只是借助传参特点,this指向不用修改。还是原来的this
let max1 = Math.max.apply(Math,arr)
console.log( max1 )
//ES6求最大值 ...作用和apply类似,也会自动遍历数组,然后逐一传参
let max2 = Math.max(...arr)
console.log(max2)
</script>
bind(修改后的this)
<script>
/*
1.环境对象 this : 谁'调用'我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建实例对象
2.上下文调用 : 修改函数内部的this
2.1 函数名.call(修改后的this,形参1,形参2…………)
2.2 函数名.apply(修改后的this, 数组或伪数组 )
2.3 函数名.bind(修改后的this)
* 不会立即执行函数,而是得到一个修改this之后的新函数。
* bind一般用于修改: 定时器函数、事件处理函数
3. 面试必问: call 和 apply 和 bind三者区别
*/
function fn(a,b){
console.log( a + b )
console.log( this )
}
// 函数名.call(修改后的this,形参1,形参2…………)
fn.call({
name:'张三'},10,20)
// 函数名.apply(修改后的this, 数组或伪数组 )
// apply会自动帮你遍历数组,然后按照顺序逐一传参
fn.apply({
name:'李四'}, [30,40] )
//函数名.bind(修改后的this)
// bind不会立即执行函数,而是返回一个修改this之后的新函数
let newFn = fn.bind({
name:'王五'})
newFn(100,200)
newFn(10,20)
</script>
<script>
/*
定时器中的this : 默认指向window
*/
setTimeout(function() {
console.log(this)
}.bind({
name: "1111" }),2000)
// let obj = {
// name: "张三",
// hobby: ["学习", "干饭", "睡觉"],
// sayHi: function() {
// setTimeout(function() {
// console.log(this)
// }, 1000)
// }
// }
// obj.sayHi()
</script>
**
1.环境对象 this : 谁’调用’我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建实例对象
2.上下文调用 : 修改函数内部的this
2.1 函数名.call(修改后的this,形参1,形参2…………)
2.2 函数名.apply(修改后的this, 数组或伪数组 )
2.3 函数名.bind(修改后的this)
* 不会立即执行函数,而是得到一个修改this之后的新函数。
* bind一般用于修改: 定时器函数、事件处理函数
3.面试必问: call 和 apply 和 bind 三者区别
相同点 : 作用一致,修改函数this指向
不同点 :
传参方式不同 : call是按照顺序传参, apply是数组/伪数组传参
执行机制不同 : call和apply会立即执行函数,而bind不会立即执行而是得到修改this的新函数
**
1.闭包closure是什么 : a. 闭包 是一个 访问其他函数内部变量 的 函数 b. 闭包 = 函数 + 上下文引用 2.闭包作用 : 解决变量污染 * 一般用于回调函数
3.在浏览器中调试闭包 :
*/
document.querySelector('.btn').onclick = function(){
//1.获取用户搜索的内容
let txt = document.querySelector('input').value
//2.网络请求 : 不是立即就能出结果的,网络请求需要时间的。
//使用定时器来模拟请求
setTimeout(function(){
alert(`${
txt}的搜索结果如下:123条`)
},1000)
}
递归函数: 一个函数 在内部 调用自己,递归作用和循环类似的,也需要有结束条件
//双函数递归 : 两个函数互相调用
function fn1(){
console.log('哈哈')
fn2()
}
function fn2(){
console.log('呵呵')
fn1()
}
1.递归函数: 一个函数 在内部 调用自己 * 递归作用和循环类似的,也需要有结束条件 2.递归应用: 浅拷贝与深拷贝 : 方式一(推荐) : JSON方式实现 * let newObj = JSON.parse( JSON.stringify( obj ) ) 方式二(递归) : 了解 遍历dom树
//浅拷贝: 拷贝地址
// 修改拷贝后的数据,原数据也会修改
//深拷贝 : 拷贝数据
//(1)先把js对象 -> JSON字符串 (JSON会自动帮你深拷贝)
// let jsonStr = JSON.stringify( obj )
//(2)再把 JSON字符串 -> js对象
// let newObj = JSON.parse( jsonStr )