昨天和js大神谈js,他说要是他出题的话,就问apply和call的区别。。。
现在整理一下,首先说apply和call的不同之处其实就是 方法传递的参数不同,(还有一个是性能方面的差别,apply的性能要差很多。)
call( fun, arg1 , arg2 ,arg3...... ), 而apply只接受 两个参数 apply( fun , [ arg1 , arg2 ,arg3....])(以数组形式存储)
两者的作用呢,都是变化上下文,所谓的上下文是指 对象的空间:
var a = { o : 100, m : function (){ console.log(this.o); var o = 200; } }
则变量o和函数m的上下文就是对象 a。
注 :在JavaScript中,代码将总是有着某种形式的上下文(代码在其内部工作的 对象)
上下文是通过变量this(号称魔法变量)工作。变量this总是引用代 码当前所在的那个对象。记住全局对象实际上是window对象的属性。这意味着即使是在全局上下文里,this 变量仍然引用一个对象。
下面来举一些有点磨人的例子:
(1)全局变量k
var k = 200; var obj = { f : function() { console.log( k ); k = 100; } } obj.f(); // 200 ,k为一个全局的变量,k的上下文是window
(2 ) this.k,此处的this指代的对象是 obj,而在执行console.log(this.k)的时候,下一句k还没有定义,但是由于声明提前,所以k已经声明,所以不会报错,
而是undefined(相当于在内存开了一个0字节的内存,也就是只是声明了一个变量,而没有给它赋值,则默认值)
var k = 200; var obj = { f : function() { console.log( this.k ); k = 100; } } obj.f(); // undefined
(3) 自执行的函数,是一个自我封闭的区域,其中的this没有上下文,没有上下文默认为全局的window是其上下文。
var k = 200; var o = { k : 100, m : (function() { console.log(k); //200 console.log(this.k); // 200 } )() } o.m;
其他一些问题:(好难)
1.考的是函数中参数arguments的类型,arguments是参数的集合,是一个对象不是数组
(function(){ return typeof arguments; })()
结果是: object
2.命名函数表达式的函数名只对函数体内可见
var f = function g(){ return 23; }; typeof g();
//根据标准,命名函数表达式的函数名只对函数体内可见
//因此报错
//Uncaught ReferenceError: g is not defined
//at <anonymous>:3:3
//at Object.InjectedScript._evaluateOn (<anonymous>:905:140)
//at Object.InjectedScript._evaluateAndWrap (<anonymous>:838:34)
//at Object.InjectedScript.evaluate (<anonymous>:694:21)
3.参数是不可删除的
(function(x){ delete x; return x; })(1);
结果是:1
4.未赋值的变量默认为undefined
var y = 1, x = y = typeof x; x;
结果是:undefined
//声明两个变量x与y,y最初赋为1,x没有赋值,默认赋给window的一个属性undefined,
//因此typeof undefined为"undefined",最后x= y= "undefined"
5.函数名被优先级更高的参数名覆盖了,内存覆盖了
(function f(f){ return typeof f(); })(function(){ return 1; });
//结果就是: typeof 1; 最终结果是: number
//函数名被优先级更高的参数名覆盖了
6.自执行函数的上下文,这个解释了自执行函数的上写文是window了
var foo = { bar: function() { return this.baz; }, baz: 1 }; (function(){ return typeof arguments[0](); })(foo.bar);
结果是: undefined
//我们把下面那个自动执行函数分解一下
//var a = function(){
// return typeof arguments[0]();
//};
//a(foo.bar)
//执行完arguments[0](),即得到this.baz
//由于this变量在此绑定失效,它指向window,window有bax变量吗?
//没有,返回"undefined"
7.还是this指代的当前对象的变化
var foo = { bar: function(){ return this.baz; }, baz: 1 } typeof (f = foo.bar)();
结果是: undefined
解释是:这个函数可以等价于:
// window.f;
// f = foo.bar;
// f();
//此时this指向的对象是window了,所以最后结果是undefined;
8.内存中后赋值的会覆盖掉先赋值的(包括变量赋值和函数赋值哟)
var f = (function f(){ return "1"; }, function g(){ return 2; })(); typeof f;
结果是 typeof 2 => number
解释是: var a = ( 1,2,3 )
a ; => 3
函数赋值亦是这样,f先是赋值为f(),然后赋值为g().
所以最后执行的是g函数
9.这题好难。。。。理解
var x = 1; if (function f(){}) { x += typeof f; }
x ;
结果是: 1undefined
//函数声明只能裸露于全局作用域下或位于函数体中
//从句法上讲,它们不能出现在快中,例如不能出现在if,while,或for语句中,因为块只能包含语句。
因此if()中的f函数不能当做函数声明,当成表达式使用
//可能是预编译阶段做了如下处理:
//if ( xxx = function(){} )
//根据第2条,命名函数表达式的函数名只对函数体内可见,所以是找不到f的。
10.typeof undefined = "undefined" //string型的
var x = [typeof x, typeof y][1]; typeof typeof x;
结果是: string
x数组其实是: [ "undefined" , "undefined" ]
11.这题其实简单,就是要看清楚{有几层
(function(foo){ return typeof foo.bar; })({ foo: { bar: 1 } });
结果是: undefined
看到这样复杂的可以这样解释:
var a = {foo:{bar:1}}
(function( foo ) {
return typeof foo.bar
})(a);
a中的属性只有foo
12.声明提升
(function f(){ function f(){ return 1; } return f(); function f(){ return 2; } })();
结果: 2
13.这题就不是很明白,应该是instanceof对象是否是特定类的一个实例
function f(){ return f; } new f() instanceof f;
结果是:false
解释是: 由于函数f会返回自身,这个new就形同虚设
如果f的形式为function f(){ return this;}或function f(){}就不一样
14.函数的length就是指它形参的长度,with就是一个读写器,题意就是取出函数的length属性
with (function(x, undefined){}) length;
结果是:2