撸了今年阿里、头条和美团的面试,我有一个重要发现…>>>
Function类型
函数实际上是对象,每个函数实际上都是 Function 类型的实例。而且与其他引用类型一样具有属性和方法。函数名实际上是一个指向内存堆中某个函数对象的指针。不会与函数绑定。函数可以如下面的语法定义:
function sum (num1, num2){
return num1 + num2;
}
也可以像下面一样定义:
var sum = function(num1, num2){
return num1 + num2;
}
还可以使用Function构造函数。Function构造函数可以接收任意数量的参数,最后一个参数始终被看做函数体,前面的参数被看做是新函数的参数。
var sum = new Function("num1","num2","return num1 + num2");
这种方式会导致解析两次代码(第一次是解析常规ECMAScript代码,第二次是解析传入构造函数中的字符串),从而影响性能。
1、函数没有重载
在ECMAScript中没有函数重载。因为函数名是作为指针的概念存在的,重复声明同一个函数名相当于覆盖指针引用,所有同一个函数名同时只能保存一个函数引用。
function fn(num1){
return num1;
}
function fn(num1, num2){
return num1 + num2;
}
console.log(fn(1));//NaN
上面的代码以下面相同:
var fn = function(num1){
return num1;
}
var fn = function(num1,num2){
return num1 + num2;
}
console.log(fn(1));//NaN
2、函数声明与函数表达式的区别
函数声明与函数表达式的语法功能相同,但是其解析的过程却是不同的。解析器会先读取函数声明,并使其在任何执行代码前,就是说解析器会先扫描脚本,然后将声明的函数置于脚本顶部,以便于接下来执行的可以调用函数。这样就可以解释为是声明的函数可以在声明之前调用。
console.log(sum(1,2));//3
function sum(num1,num2){
return num1 + num2;
}
而对于函数表达式,解析器则会当作普通的赋值操作,而不会对其进行特殊的解析。下面代码会抛异常。
console.log(sum(1,2));//unexpected identifier
var sum = function(num1,num2){
return num1 + num2;
}
3、函数内部属性
函数内部有两个特殊的对象:arguments和this。arguments是一个数组对象,包含传入函数的所有参数arguments对象有一个名叫callee的属性,指向拥有这个arguments对象的函数。对比下面的例子:
function factorial(num){
if(num <= 1){
return 1;
} else {
return num * factorial(num - 1);
}
}
function factorial(num){
if(num <= 1){
return 1;
} else {
return num * arguments.callee(num - 1);
}
}
第一个函数中引用了函数名,这回导致函数改名时不可用,而,第二个函数则没有这个问题。
函数内部还有一个特对象this,引用函数数据以执行的环境对象。
window.color = "red";
var o = {color:"blue"};
function sayColor(){
console.log(this.color);
}
sayColor();//"red"
o.sayColor = sayColor;
o.sayColor();//"blue"
还有另外一个属性:caller。保存调用当前函数的引用,如果在全局作用域中调用,值为null。
function outer(){
inner();
}
function inner(){
console.log(arguments.callee.caller);
}
outer();
4、函数属性和方法
ECMAScript中的函数是对象,也有属性和方法。每个函数都有两个属性:length和prototype。其中,length属性表示函数要接收的命名函数的个数。
function sayName(name){
console.log(name);
}
function sum(num1, num2){
return num1 + num2;
}
function sayHi(){
console.log("hi");
}
console.log(sayName.length);//1
console.log(sum.length);//2
console.log(sayHi.length);//0
每个函数包含两个非继承而来的方法:apply()和call()。apply()方法接收两个参数:一个是在其中运行函数的作用越,另一个是参数数组。第二参数可以是Array实例,也可以是arguments对象。
function sum(num1, num2){
return num1 + num2;
}
function callSum1(num1, num2){
return sum.apply(this,arguments);//传入arguments对象
}
function callSum2(num1, num2){
return sum.apply(this, [num1,num2]);//传入数组
}
console.log(callSum1(10,10));//20
console.log(callSum2(10,10));//20
对于call(),第一个参数this没有变化,但是其他参数需要直接传递函数。
function sum(num1, num2){
return num1 + num2;
}
function callSum(num1, num2){
return sum.call(this, num1,num2);//传入数组
}
console.log(callSum(10,10));//20
apply()和call()能够扩充函数运行的作用域。
window.color = "red";
var o = {color : "blue"};
function sayColor(){
console.log(this.color);
}
sayColor();//red
sayColor.call(this);//red
sayColor.call(window);//red
sayColor.call(o);//blue
ECMAScript 5定义了一个方法:bind()。
window.color = "red";
var o = {color : "blue"};
function sayColor(){
console.log(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor();//blue
支持bind()方法的浏览器有IE9+、FF4+、Safari5.1+、Opera 12+和Chrome。
这份 xmind 尤其适合: https://my.oschina.net/u/2663968/blog/3105068
1.近期想跳槽,要面试的Java程序员,查漏补缺,以便尽快弥补短板;
2.想了解“一线互联网公司”最新技术要求,对比找出自身的长处和弱点所在,评估自己在现有市场上的竞争力如何;
3.做了几年Java开发,但还没形成系统的Java知识体系,缺乏清晰的提升方向和学习路径的程序员。
----------------------------头条一面试题
上来先网络问题
说说TCP UDP区别
http状态码301 302区别? 状态码分几大类? https如何使用密钥保证可靠性
面试管可能觉得网络不行,那咱就换个话题吧
说说let const区别 (可惜 唉 const居然说不知道)
call applly bind区别? 请模拟一个bind函数. (答对一半 我也是懵逼 不是有吗 要自己造)
使用正则表达式讲"< %=% >“转换为”{ %}" (又挂了 面试官还是很热心 继续提问 给个简单的)
判断JS为空对象 (这个还行 当时用 JSON.stringify(obj) == ‘{}’) 找出数组中第二大的数.
如arr=[9,2,5,0,6…] (这个还行 当时先排序 在找) creator性能优化讲讲
最好结果呢 不言而喻
1 如何模拟bind函数? 泪崩 可惜太菜 当时没回答商量
var obj = {
name:'zhangsan',
showLog:function(){ ...... }
}
var obj2 = {
name:'LiMing'
};
obj.showLog().bind(obj2);
过了几天才相处办法 ....
function bind2(obj){
let func = bind2.caller.toString(); // func.caller返回调用当前函数的那个函数
obj[func] = arguments.callee; // caller 保存调用当前函数的引用<意思函数指针/地址>
return obj[func];
}