javascript函数调用的几种方式总结(上下文模式call,apply方法借用)

 浆糊之家   2018-04-14 10:45   216 views 热度值

函数有下列调用模式

函数调用模式 方法调用模式 构造器模式 上下文模式

1. 函数调用 模式

要调用,就肯定要先定义,函数的定义方式:

声明式: function fuc() {} 表达式式: var func = function() {}; Function: new Function( ‘参数’,…,’函数体’ );

单独独立调用的,就是函数调用模式,即 函数名( 参数 ),不能加任何其他的东西, 对象 o.fuc() 就不是了。

在函数调用模式中, this 表示全局对象 window

任何自调用函数都是函数模式。


2. 方法调用 模式 method

所谓方法调用,就是用对象的方法调用。方法是什么,方法本身就是函数,但是,方法不是单独独立的,而是要通过一个对象引导来调用。

就是说方法对象一定要有宿主对象

对象.方法(参数)

this表示引导方法的对象,就是指宿主对象

对比-函数调用模式:

方法调用模式是不是独立的,需要宿主,而函数调用模式是独立的 方法调用模式方式:obj.fuc(); 函数调用模式方式: fuc(); 方法调用模式中,this指宿主。而函数调用模式中 this 指 全局对象window

美团的一道面试题

解析:

fn() 前面没有引导对象,是函数调用模式, this是全局对象,输出 10

arguments[ 0 ](),arguments是一个伪数组对象, 这里调用相当于通过数组的索引来调用.

这里引导对象即宿主就是 arguments对象。

所以,执行时,this 就是指 arguments,由于传了两个参数,所以 输出为 arguments.length 就是 2


3. 构造器模式(构造函数模式, 构造方法模式)

constructor

特点: 使用 new 关键字引导

执行步骤:var p = new Person();

new 是一个运算符, 专门用来申请创建对象, 创建出来的对象传递给构造函数的 this。然后利用构造函数对其初始化。

执行完 new 进入构造函数时, p 对象的原型 就指向了 构造函数 Person

而 构造时,this 指的的是 p 对象,是通过对象动态添加属性来构造的

小贴士:如果调用构造函数的时候, 构造函数没有参数, 圆括号是可以省略的。

↑ 不传参,可以简写,不影响构造

返回值

不写 return 语句, 那么 构造函数 默认返回 this

在构造函数 return 基本类型( return num, return 1223 ). 则忽略返回类型.

在构造函数 return 引用类型, 那么构造函数返回该引用类型数据, 而忽略 this

↑ 忽略了 123,返回 this 对象, 指向构建的实例

 

↑ 忽略了 this,返回 { ‘peter’: ‘nihao’ } 对象

构造函数结合性

如果构造函数没有参数, 可以省略 圆括号

var p = new Person;

如果希望创建对象并直接调用其方法

( new Person () ).sayHello()

-> 可以省略调整结核性的圆括号 new Person().sayHello()

-> 如果想要省略构造函数的圆括号, 就必须添加结核性的圆括号 (new Person).sayHello()

面试题

一道面试题,大家可以自己尝试先做一下,再看下面的答案和解析

请问顺序执行下面代码,会怎样 alert

 

预解析,简化后的代码,以及答案

 

全部解析过程 ↓

 

4. 上下文调用模式

就是 环境调用模式 => 在不同环境下的不同调用模式

简单说就是统一一种格式, 可以实现 函数模式与方法模式

-> 语法(区分)

call 形式, 函数名.call( … ) apply 形式, 函数名.apply( … )

这两种形式功能完全一样, 唯一不同的是参数的形式. 先学习 apply, 再来看 call 形式

apply方法的调用形式

存在上下文调用的目的就是为了实现方法借用,且不会污染对象。

如果需要让函数以函数的形式调用, 可以使用

foo.apply( null ); // 上下文为 window

如果希望他是方法调用模式, 注意需要提供一个宿主对象

foo.apply( obj ); // 上下文 为 传的 obj 对象

 

带有参数的函数如何实现上下文调用?

使用 apply 进行调用, 如果函数是带有参数的. apply 的第一个参数要么是 null 要么是对象

如果是 null 就是函数调用

如果是 对象就是 方法调用, 该对象就是宿主对象, 后面紧跟一个数组参数, 将函数所有的参数依次放在数组中.

 

方法借用的案例

需求, 获得 p 与 p 标签, 并添加边框 border: 1px solid red

一般做法:

利用方法借用优化,元素获取

接下来考虑下面的优化,两个for循环,只要将数组合并了,就可以只用一个 for 循环

数组合并

 

所以同理,利用 apply 方法借用,将两个伪数组合并成同一个数组

 

将两者综合, 使用forEach,最终 6 行就解决了

 

call 调用

在使用 apply 调用的时候, 函数参数, 必须以数组的形式存在. 但是有些时候数组封装比较复杂

所以引入 call 调用, call 调用与 apply 完全相同, 唯一不同是 参数不需要使用数组

 

函数调用: 函数名.call( null, 参数1,参数2,参数3… );

方法调用: 函数名.call( obj, 参数1,参数2, 参数3… );

不传参时,apply 和 call 完全一样

借用构造方法实现继承

补充知识 1. 函数的 bind 方法 ( ES5 )

bind 就是 绑定

还是上面那个案例 获得 p 与 p 标签, 并添加边框 border: 1px solid red

我们 让 t 包含函数体(上面的方式),同时包含 对象,就可以更精简

 

bind : 就是让函数绑定对象的一种用法

函数本身就是可以调用, 但是其如果想要作为方法调用, 就必须传入宿主对象, 并且使用 call 或 apply 形式

但是 bind 使得我的函数可以与某一个对象绑定起来, 那么在调用函数的时候, 就好像是该对象在调用方法,就可以直接传参,而不需要传宿主对象。

语法: 函数.bind( 对象 )

返回一个函数 foo,那么调用 返回的函数 foo, 就好像 绑定的对象在调用 该方法一样

 

补充知识 2. Object.prototype 的成员

Object.prototype 的成员

constructor hasOwnProperty 判断该属性是否为自己提供 propertyIsEnumerable 判断属性是否可以枚举 isPrototypeOf 判断是否为原型对象 toString, toLocaleString, valueOf

 

用途:一般把一个对象拷贝到另一个对象时,可以进行判断,更加严谨,以防把原型中的属性也拷贝过去了…


补充知识 3. 包装类型

字符串 string 是基本类型, 理论上讲不应该包含方法

那么 charAt, substr, slice, …等等方法,理论上都不应该有,但确是有的

所以引入包装对象的概念,在 js 中为了更好的使用数据, 为三个基本类型提供了对应的对象类型

Number String Boolean

在 开发中常常会使用基本数据类型, 但是基本数据类型没有方法, 因此 js 引擎会在需要的时候自动的将基本类型转换成对象类型, 就是包装对象

“abc”.charAt( 1 )

“abc” -> s = new String( “abc” )

s.charAt( 1 ) 返回结果以后 s 就被销毁

当基本类型.方法 的时候. 解释器首先将基本类型转换成对应的对象类型, 然后调用方法.

方法执行结束后, 这个对象就被立刻回收

在 apply 和 call 调用的时候, 也会有转换发生. 上下文调用的第一个参数必须是对象. 如果传递的是数字就会自动转换成对应的包装类型


补充知识 4. getter 和 setter 的语法糖 ( ES5 )

语法糖: 为了方便开发而给出的语法结构

本身实现:

希望获得数据  以对象的形式
o.get_num();            => o.num 形式
希望设置数据  以对象的形式
o.set_num( 456 );       => o.num = 456 形式
所以 getter 和 setter 诞生 了

 

为什么不直接用 对象呢 var o = { num : 123 } ,也可以读写呀?

因为语法糖还可以 限制其赋值的范围,使用起来特别爽

补充知识 5. ES5 中引入的部分数组方法

forEach map filter some every indexOf

lastIndexOf

forEach, 数组遍历调用,遍历arr,参数三个 arr[index] 某项, index 索引, arr 整个数组

 

map 映射

语法: 数组.map( fn )

返回一个数组, 数组的每一个元素就是 map 函数中的 fn 的返回值

就是对每一项都进行操作,并返回

 

filter 就是筛选, 函数执行结果是 false 就弃掉, true 就收着

语法: 数组.filter( function ( v, i ) { return true/false })

some 判断数组中至少有一个数据复合要求 就返回 true, 否则返回 false

 

every 必须满足所有元素都复合要求才会返回 true

 

indexOf 在数组中查找元素, 如果含有该元素, 返回元素的需要( 索引 ), 否则返回 -1

 

lastIndexOf 从右往左找

 

 发表评论


表情

  1. ΝΤΕΤΕΚΤΙΒ
    ΝΤΕΤΕΚΤΙΒ 【活跃】 @回复

    WOW just what I was looking for. Came here by searching for javascript函数调用