深谈call方法,了解call方法的原理

作者:jiangwen日期:2016-07-24 22:12:30 点击:165 js中原型深入 call

1.原型深入

回顾:Object为对象类,所有的对象数据类型都是它的实例
同理,Function为函数类,所有的函数数据类型都是它的实例
同时,Function的原型上有call,apply,bind…方法

1.1 Function类和Object类的关系

Object是Function的实例,Function.prototype.__proto__是Object的实例
Function.prototype.__proto__指向Object.prototype

function Fn(){
this.x = 100;
}
console.dir(Fn)

函数具有一些私有属性,如:
length:形参的个数;
name:函数名;
prototype:类的原型,在原型上定义的方法,都是当前Fn类实例的公有方法;
__proto__:把函数当做一个普通对象,指向Function的原型.

Fn.__proto__.__proto__也指向Object
所有的函数都是函数类的一个实例,也作为一个实例的存在,实例就是对象数据类型的

1.2 函数的多面性

一个函数存在了多面性:
1.本身是一个普通函数,执行时形成私有作用域(闭包),形参赋值、预解释、代码执行、栈内存释放;
2.本身是一个类,有自己的实例,也有prototype属性是自己的原型,它的实例都可以指向原型;
3.本身是一个普通对象,作为对象可以有自己的私有属性,也可以通过__proto__找到Function.prototype(函数的三种角色)
但是三者之间没有必然关系

function Fn(){
var num = 500;
this.x = 100;
} //作为函数
Fn.prototype.getX = function(){
console.log(this.x);
}
Fn.aaa = 1000; //作为对象
var f = new Fn; //作为类
console.log(f.num);
console.log(f.aaa);
var res = Fn();
console.log(res);
console.log(Fn.aaa);

Function.prototype是函数数据类型的值,但是相关操作和之前的对象一样
叫做Empty/anonymous(匿名)

console.log(Function.prototype);
//function(){}

Function类的原型为一个空函数

原型链

2.call方法

2.1 call语法

语法:call([thisObj[,arg1[, arg2[,[,.argN]]]]])
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明:call方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

2.2 call原理

举例模仿call原理:

var arr = [12,13,14,15];
Array.prototype.slice = function(context){
//1.将函数中的this变为context
//2.this方法执行
this();
}
//arr.slice arr实例通过原型链查找机制找到位于Array.prototype上的slice方法
//arr.slice(); 让找到的slice方法执行,在执行的过程中对arr进行了截取操作

call()改变this关键字

Function.prototype.call = function(){}
var obj = {name:"Amy"};
function fn(){
console.log(this);
}
fn();
fn.call(obj);

call:首先让原型上的call方法执行,在执行call方法时让fn的this变为第一个参数obj,然后再把fn执行

function f1(){
console.log(1);
}
function f2(){
console.log(2);
}
f1.call(f2); //1
f1.call.call(f2); //call方法的this为f1.call
f1.call.call.call.call(f2);

f1通过原型链找到的是Function.prototype的call方法,然后再让call方法找到Function.prototype
因为本身的值为一个函数,所以同样可以找到Function原型,在第二次找到call的时候让方法执行,方法中的this为f1.call,首先让这个方法中的this变为f2,再让f2执行

f1.call只是起到了查找的作用

2.3 call和apply的区别

apply和call的方法作用是一模一样的,都是用来改变方法的this关键字,并且把方法执行
在严格模式和非严格模式下下apply和call调用null,undefined的情况也是一样的

var obj = {name:"Amy"}
function fn(num1,num2){
console.log(num1+num2);
console.log(this);
}
fn.call(obj,100,200);
fn.call(100,200); //NaN,undefined
fn.apply(obj,[100,200]);

call是一个个传递值的;apply是传递两个值,将函数参数统一放到数组中进行操作,也相当于一个个赋值

function fn(){
console.log(this);
}
//非严格模式下
fn.call(); //this->window
fn.call(null); //this->window
fn.call(undefined); //this->window

"use strict"
;
//严格模式
fn.call(); //this->undefined
fn.call(null); //this->null
fn.call(undefined); //this->undefined

严格模式下自执行函数的this永远是undefined
严格模式下函数执行的”.”前没有对象this是undefined(非严格模式下是window)
非严格模式下没有写执行主体的情况下this都为window
非严格模式下函数执行前的”.”的元素,如果没有则为window.

2.4 bind方法

这个方法在IE6/7/8不兼容;和call、apply相似,都是改变this的

var obj = {name:"Amy"};
function fn(){
console.log(num1+num2,this);
}
fn.bind(obj,1,2);

bind只是改变函数中的this,并且给fn传递了参数,但是此时并没有执行fn,所以不输出任何内容

var temp = fn.bind(obj,1,2);
temp();

执行bind会有一个返回值

bind有预处理思想,事先把this改变为想要的结果,并把需要的值准备好,如果需要再直接执行即可
回顾this的四种情况:
1)自执行函数的this是window
2)给元素的某一行为绑定方法,this为当前元素
3)方法执行前的”.”元素
4)构造函数中this就是当前实例

但是当前四种情况遇到call和apply的时候统统让路

上一篇: Javascript 变态题解析系列四

下一篇: DOM方法详解,前端中的DOM