文章目录

  • 一、函数的定义方式
  • 二、六大触发函数的方式
    • 2.1 普通函数
    • 2.2 对象的方法
    • 2.3 构造函数
    • 2.4 绑定事件的函数
    • 2.5 定时器函数
    • 2.6 立即执行函数
  • 三、函数内 this 的指向
    • 3.1 改变函数内部 this 的指向
    • 3.2 call() 方法
    • 3.3 apply() 方法
    • 3.4 bind() 方法 不需要立即调用的同时改变 this
    • 3.5 call apply bind 总结
  • 四、递归
    • 4.1 递归求阶乘
    • 4.2 斐波那契数列
    • 4.3 递归遍历数据
  • 五、浅拷贝 和 深拷贝
    • 5.1 浅拷贝
      • 5.1.1 for 循环实现
      • 5.1.2 Object.assign实现:
    • 5.2 深拷贝
  • 六、立即执行函数

一、函数的定义方式

// 1. 自定义函数(命名函数)
function fn(){}// 2.函数表达式 (匿名函数)
let fun = function (){}// 3. 利用 new Function("参数1","参数2","参数3")
// let f = new Function("console.log(123)")
// f() // 123let f = new Function("a", "b", "console.log(a+b)")
f(1, 2) // 3

注意:

  • Function 里边的参数都必须是字符串格式
  • 第三种方式执行效率低,也不方便书写,因此较少使用
  • 所有函数都是 Funtion的实例(对象)
    • console.log(f instanceof Object); // true

函数的内容原理:

二、六大触发函数的方式

2.1 普通函数

调用方式:fn() or fn.call()
this 指向 window

function fn() {console.log("人生的巅峰")
}
fn()
fn.call()

2.2 对象的方法

调用方式:obj.sayHi()
this 指向当当前对象 obj

let obj = {sayHi: function () {console.log("人生的巅峰")}
}
obj.sayHi()

2.3 构造函数

调用方式:new 构造函数的时候调用
this指向 实例对象

function Star(){}new Star()

2.4 绑定事件的函数

调用方式:事件触发时调用
this 指向 事件对象

btn.onclick = function (){ //点击按钮即可调用函数console.log("人生的巅峰")
}

2.5 定时器函数

调用方式:定时器时间到达时调用
this 指向 window 因为完整写法是 window.setInterval

setInterval(() => {console.log('...');
}, 1000);

2.6 立即执行函数

调用方式:立即调用
this 指向 window

(function (){console.log("立即执行函数");
})()

三、函数内 this 的指向

这些this的指向,是当我们调用函数的时候确定的。调用方式的不同決定了this的指向不同
一般指向我们的调用者。

调用方式 this指向
普通函数调用 window
构造函数调用 实例对象,原型对象里面的方法也指向实例对象
对象方法调用 该方法所属对象
事件绑定方法 绑定事件对象
定时器函数 window
立即执行函数 window

3.1 改变函数内部 this 的指向

Javascript为我们专门提供了一些函数方法来帮我们更优雅的处理函数内部this的指向问题,常用的有 bind()、call()、appy() 三种方法。

3.2 call() 方法

call(obj,arg1,arg2,ar3,...)

call() 方法的主要作用有两个:

  • 一是可以调用该函数,类似于 你有一个函数 function demo(){...} , 你 平时或许是 demo()这样调用它的,你也可以 demo.call(),它们的本质上没有什么区别
  • 二是你可以改变函数内 this的指向,具体请看下面示例:
let obj = {name: "andy"
}function fn(a, b) {console.log(this)console.log(a + b);
}
fn(2, 3) // window 5
fn.call(obj, 2, 3) //{name: "andy"}  5

call() 方法在实际开发中主要用于继承使用。
call() 实现继承实例:

// 手写继承
function Father(name,age){this.uname  = namethis.uage = age
}
Father.prototype.sing = function (){console.log("我会唱歌")
}function Son(name,age){Father.call(this,name,age)
}Son.prototype = new Father()
Son.prototype.dance = function (){console.log("我会跳舞");
}
Son.prototype.constructor = Sonlet objFather = new Father("父亲",30)
let objSon = new Son("儿子",18)console.log(objFather);
console.log(objSon);

3.3 apply() 方法

apply(obj,[array])
apply() 方法与 call() 方法很相似,主要区别在于 参数
apply: 的第二个参数 是接受一个数组作为参数,而 call() 方法是一串参数列表

apply:最多只能有两个参数——新this对象和一个数组argArray。如果给该方法传递多个参数,则把参数都写进这个数组里面,当然,即使只有一个参数,也要写进数组里。如果argArray不是一个有效的数组或arguments对象,那么将导致一个TypeError。

call:它可以接受多个参数,第一个参数与apply一样,后面则是一串参数列表。这个方法主要用在js对象各方法相互调用的时候,使当前this实例指针保持一致,或者在特殊情况下需要改变this指针。

apply 的主要应用示例:

let arr = [1,66,3,99,4]
let maxNum = Math.max.apply(null,arr)
let minNum = Math.min.apply(null,arr)console.log('maxNum: ', maxNum); // 99
console.log('minNum: ', minNum); // 1

3.4 bind() 方法 不需要立即调用的同时改变 this

bind方法 不会调用函数 。但是能改变函数内部this指向

fun.bind(thisarg, argl, arg2, ...)

  • thisarg:在fun函数运行时指定的this值
  • arg1,arg2:传递的其他参数
  • 返回的是原函数 修改this 之后产生的新函数

示例:

let obj = {name:"andy"
}function fn(){console.log(this)
}
let newFn = fn.bind(obj) // 不会调用,没有结果输出
newFn() // {name: "andy"}

应用场景:
如果有的函数我们不需要立即调用但是又想改变这个函数内部的this指向此时用bind()方法

bind() 方法应用:

let btn = document.querySelector("#btn")// bind() 应用案例
btn.onclick = function () {this.disabled = truelet that = thissetTimeout(function () {// 直接写不起作用,因为 this 指定的是 window ,绑定 bing(this)之后才起作用this.disabled = false // 方案二:// that.disabled = false }.bind(this), 3000); // 因为 this是在定时器外边而又在 btn的事件处理程序里边,所以 this 指向的是 btn// }.bind(btn), 3000);  //效果相同,但是耦合过高
}

此外还有一种奇怪的用法:
这里实现的需求是, 在不改变函数内部this的同时,传入一个 this,
当然,你可以在全局定义一个 that,然后直接在函数内部使用,这里使用 bind 只是另外一种解决方案。

3.5 call apply bind 总结

相同点:

  • 都可以改变 函数内部的 this

不同点:

  1. call()apply() 会调用函数,而 bind() 不会调用函数
  2. call()bind() 传入的参数都是一串参数列表,而 apply传递的参数必须是数组形式

主要应用场景:

  • call() 主要处理继承
  • apply() 主要处理 数组相关的
  • bind() 不调用函数改变this指向。比如改变定时器内部的this指向

四、递归

4.1 递归求阶乘

一个数的阶乘:n!=1×2×3×…(n-1)×n

// 1.递归求阶乘
function fn(n){if(n == 1){return 1;}return n * fn(n-1)
}
console.log(fn(5)); // 120

4.2 斐波那契数列

0、1、1、2、3、5、8、13、21、34
F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)

function fb(n) {if (n === 1 || n === 2) {return 1}return fb(n - 1) + fb(n - 2)
}
console.log(fb(6));function f(n, a1 = 1, a2 = 1) {if (n <= 1) {return a1};return f(n - 1, a2, a1 + a2);
}
console.log(f(6)); // 可以计算到1450位,不溢出

4.3 递归遍历数据

<script>var data = [{id: 1,name: '家电',goods: [{id: 11,gname: '冰箱',goods: [{id: 111,gname: '海尔'}, {id: 112,gname: '美的'}, ]}, {id: 12,gname: '洗衣机'}]}, {id: 2,name: '服饰'}];// 我们想要做输入id号,就可以返回的数据对象// 1. 利用 forEach 去遍历里面的每一个对象function getID(json, id) {var o = {};json.forEach(function(item) {// console.log(item); // 2个数组元素if (item.id == id) {// console.log(item);o = item;// 2. 我们想要得里层的数据 11 12 可以利用递归函数// 里面应该有goods这个数组并且数组的长度不为 0 } else if (item.goods && item.goods.length > 0) {//这里需要接收 内部 return 的 oo = getID(item.goods, id);}});return o;}console.log(getID(data, 1));console.log(getID(data, 2));console.log(getID(data, 11));console.log(getID(data, 12));console.log(getID(data, 111));
</script>

五、浅拷贝 和 深拷贝

  • 浅拷贝只是拷贝一层,更深层次 对象级别 的 只拷贝引用 。
  • 深拷贝拷贝多层,每一级别的数据都会拷贝

5.1 浅拷贝

5.1.1 for 循环实现

let obj = {id: 1,name: "andy",msg: {age: 18}
}let newObj = {}for (key in obj) {newObj[key] = obj[key]
}
// newObj 修改 obj的也会改,因为这是浅拷贝对于对象级别的拷贝是,拷贝指针
newObj.msg.age = 50console.log(obj);
console.log(newObj);

5.1.2 Object.assign实现:

Object.assign返回目标对象。
语法:
Object.assign(target, ...sources)
target 目标对象。
sources 源对象。

let obj = {id: 1,name: "andy",msg: {age: 18}
}
const copy = Object.assign({},obj)
copy.msg.age = 50console.log(obj);
console.log(copy);

5.2 深拷贝

注意:判断时要先把数组写在上面,因为 数组也属于对象,如果写在下边会错把数组当对象。

let obj = {id: 1,name: "andy",msg: {age: 18},color:['white','black']
}
let objTwo = {}
function deepCopy(newObj, oldObj) {for(var k in oldObj){// 判断我们的属性值属于哪种数据类型// 1.获取我们的属性值 oldObj[k]var item = oldObj[k]// 2.判断值是否是 数组,对象if(item instanceof Array){newObj[k] = []deepCopy(newObj[k],item)}else if(item instanceof Object){newObj[k] = {}deepCopy(newObj[k],item)}else{newObj[k] = item}}
}
deepCopy(objTwo,obj)
console.log(objTwo);

六、立即执行函数

// 写法一:
(function (a, b) {num = a + bconsole.log(num);  // 5
})(3, 2);// 写法二:
(function (a, b) {console.log(a + b); // 30
}(10, 20));

函数进阶 call apply bind 的区别相关推荐

  1. 创建对象的方式以及call,apply,bind的区别

    创建对象的方式有四种 1.直接量 var obj={ 属性名:属性 方法名:function(){} } 2.通过构造函数创建对象,这样能够批量创建多个具有相同属性的子对象(顺便介绍call,appl ...

  2. JS函数方法Call Apply Bind运用

    JS 函数非继承的call和apply方法 同:call & apply 主要是用于扩展this指向,降低this作用域与函数之间的耦合度: 区别:传参差异 function.call(thi ...

  3. 前端学习(1115):call apply bind的区别

  4. call,apply,bind的区别

    1 转载于:https://www.cnblogs.com/YangJonathan/p/11223641.html

  5. JS高级—call(),apply(),bind()

    文章目录 call() 介绍 语法 特点 返回值 使用(主要应用) apply() 介绍 语法 特点 返回值 使用 bind() 介绍 语法 特点 返回值 使用 call(),apply(),bind ...

  6. javascript函数进阶详细内容 函数闭包 箭头函数 call bind apply用法 偏函数 回调函数

    JS函数进阶 这次的内容我会给大家详细介绍函数方面的内容 1.箭头函数:ES6新增的定义函数的方式,箭头函数是用来简化函数定义语法的. - 箭头函数的语法: ()=>{} ()里面写形式参数,{ ...

  7. javascript中apply、call和bind的区别

    在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢. 在说区别之前还是先总结一下三者的相似之处: 1.都是用来改变函数的this对象的指向的. 2.第一个参数都是this要指 ...

  8. call(),apply()和bind()的区别和应用以及扩展

    首先三个方法的作用: 1:都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域. 2:都是改变this的指向方向 区别: call()和apply()接受参数的方 ...

  9. call apply bind 的作用和区别

    1.call apply bind 的作用和区别 作用: 都可以改变函数内部的this指向. 区别点: 1.call和apply会调用函数,并且改变函数内部this指向. 2.call和apply传递 ...

  10. call apply 和 bind的区别

    apply 和call 在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向. Ja ...

最新文章

  1. GitHub开源的超逼真俄罗斯方块游戏
  2. [Object-C语言随笔之二] 《NSLog》常用的打印调试语句与自动排版
  3. linux 从grub 进入rescue,在grub的rescue模式修复linux引导
  4. 小工匠聊架构-超高并发秒杀系统设计 01_总体原则和架构演进
  5. 【Python】raise ValueError(Too many dimensions: %d %d. % (ndim, ndmax))问题
  6. kafka Linux 下启动服务 测试,Linux下安装部署Kafka分布式集群与测试
  7. c语言 iostream,C语言 我应该在哪里使用iostream类?
  8. switch如何更新大气层,和进入hekate界面
  9. 安徽省计算机二级水平考试试卷,2010安徽省全国计算机等级考试二级笔试试卷VB试题及答案...
  10. go语言中的try、catch、throw实现
  11. 转发页面,并且传参数,@click@dblclick冲突问题
  12. jmonkeyEngineSDK安装部署及IDEA集成JME3开发
  13. JavaScript学习之旅-导言篇
  14. 服务器文件变更监控,监控文件夹变化并ftp到服务器
  15. ios10苹果手机页面定位不准问题
  16. 【数据处理】Python,matplotlib 如何画柱状图?如何画各种类型的柱状图?柱子宽度设置;设置X轴刻度用label显示;设置柱子距离x轴的高度;设置柱体颜色;设置柱体描边;并列、多条柱状图
  17. Java swing 单机版五子棋
  18. 无锡设计培训——室设行业现状与发展前景
  19. Linux固态硬盘 设置写入缓存,固态硬盘性能的背后:浅论写入缓存设置
  20. 基于Javaweb高校毕业生实习管理系统 .rar(论文+项目源码)

热门文章

  1. 金蝶KIS迷你版、标准版年结注意事项!!
  2. 谈谈对springboot的理解
  3. element中navMenu结合路由使用
  4. 你一定会用到的SolidWorks快捷键汇总大全
  5. 算法教给我的人生道理-贪婪算法
  6. 教给大家:怎样给电脑分盘。
  7. SCC算法求强连通分量简单讲解证明及实现
  8. UVa 12307 Smallest Enclosing Rectangle(旋转卡壳+最小覆盖矩形)
  9. mysql单数据库多硬盘配置_MySQL 使用mysqld_multi部署单机多实例详细过程
  10. CLM陆面过程模式实践技术应用