关于前端的碎碎念5-web前端常见面试问题总结(3)

举报
花溪 发表于 2020/08/25 08:26:55 2020/08/25
【摘要】 1.new操作符是干什么的? 2.call() 和 apply() 有什么区别? 3.谈谈模块化开发?

1.new操作符过程的理解?

考察对new关键的深刻认识,是否对前端知识有专研,如果没有专研的人,肯定说创建了一个对象,恭喜你面试官知道你是小菜鸟来的,这次面试基本上没有太大的希望了。一定要对new过程的4个步骤非常清楚,这样才能深深地抓住面试官的心!

先看代码

var myFn=function(){  
};  
var func=new myFn ();

new共经过了4个阶段

  • 1、创建一个空对象

var obj=new Object();
  • 2、设置原型链

obj.__proto__= myFn.prototype;
  • 3、让myFn中的this指向obj,并执行myFn的函数体。

var result =myFn.call(obj);

  • 4、判断Func的返回值类型:

如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象。

if (typeof(result) == "object"){  
    func=result;  
}  
else{  
    func=obj;;  
}

2.call() 和 apply() 有什么区别?

属于比较一般性的问题,稍有接触基本都可以掌握,先说清楚他们的相同点,方法的作用的,关键在于把它们的差异讲清楚。

相同点:两个方法产生的作用是完全一样的,都用来改变当前函数调用的对象。

不同点:调用的参数不同,比较精辟的总结:

foo.call(this,arg1,arg2,arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3)

具体的使用

1.call的使用

语法

call([thisObj[,arg1[, arg2[, [,.argN]]]]])

参数

thisObj  可选项。将被用作当前对象的对象。

arg1,arg2, , argN  可选项。将被传递方法参数序列。

说明

call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

<!doctype html>
<html>
 <head>
  <meta charset="UTF-8">
  <meta name="Generator" content="EditPlus®">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>Document</title>  
<script>
	 function Obj()  
	{  
	   this.value="对象!";  
	}  
	var value="global 变量";  
	function myFn(a,b){  
	   alert(this.value);  
	}  
	window.myFn();   //global 变量  
	myFn.call(window,1,2);  //global 变量  
	myFn.call(document.getElementById('myText'));  //global 变量  
	myFn.call(new Obj());   //对象!  
</script>
 </head>
 <body>

<div  id="myText">  

</div>  

 </body>
</html>

2.apply()

apply与call的功能几乎一样,第一个参数意义都一样,只是第二个参数有点不同apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,call从第二个参数开始,依次传值给调用函数的参数 

3.代码比较

<!doctype html>
<html>
 <head>
  <meta charset="UTF-8">
  <meta name="Generator" content="EditPlus®">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>Document</title>  
<script>
function print(a, b, c, d){  
  alert(a + b + c + d);  
}  
function example(a, b , c , d)
{  
 //用call方式借用print,参数显式打散传递  
 print.call(this, a, b, c, d);  
 //用apply方式借用print, 参数作为一个数组传递,  
 //这里直接用JavaScript方法内本身有的arguments数组  
 print.apply(this, arguments);  
 //或者封装成数组  
 print.apply(this, [a, b, c, d]);  
}  
//下面将显示”华为前端”  
example("华" , "为" , "前", "端");  
</script>
 </head>
 <body>

<div  id="myText">  

</div>  

 </body>
</html>

image.png

3.谈谈模块化开发?

主要看你是否有做过比较复杂、庞大的项目,是否具备一定的编程思想。随着前端技术的发展,前端编写的代码量也越来越大,就需要对代码有很好的管理。目前比较好的开发语言就是OOP(面向对象编程)编程语言,例如Java语言、C#语言。从JavaScript新的版本来看,要求JavaScript具有封装、继承、多态这样的优点需求越来越明显。考察编程思想。

什么是模块化

所谓的模块化开发就是封装细节,提供使用接口,彼此之间互不影响,每个模块都是实现某一特定的功能。模块化开发的基础就是函数 

使用函数封装 

function myFn1(){  
 //...  
}  
function myFn2(){  
 //...  
}

上面的函数myFn1 ()和myFn2 (),组成一个模块。使用的时候,直接调用就行了。这种做法的缺点很明显:"污染"了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。

使用对象封装  ---为了解决上面的缺点,可以把模块写成一个对象,所有的模块成员都放到这个对象里面。

var obj = {  
    age : 0,  
    myFn1 : function (){  
        //...  
    },  
    myFn2 : function (){  
        //...  
    }  
};

上面的函数myFn1 ()和myFn2 (),都封装在obj对象里。使用的时候,就是调用这个对象的属性。

 obj.myFn1();

这样做也是有问题的,变量可以被外面随意改变而导致不安全。比如,年龄被修成负数。

obj.age = -10;

如何保证对象的属性不被访问了? 

立即执行函数写法 

使用"立即执行函数"(Immediately-Invoked FunctionExpression,IIFE),可以达到不暴露私有成员的目的。这个也是闭包处理的一种方式。

var obj= (function(){  
    var _age= 0;  
    var myFn1= function(){  
      //...  
    };  
    var myFn2= function(){  
      //...  
    };  
    return {  
      m1 : myFn1,  
      m2 : myFn2  
    };  
})();

使用上面的写法,外部代码无法读取内部的age变量。

console.info(obj.age);//undefined

<script>
    var obj= (function(){  
        var _age= 0;  
        var myFn1= function(a,b){  
          return a+b;
        };  
        var myFn2= function(a,b){  
          return a-b
        };  
        return {  
          m1 : myFn1(4,5),  
          m2 : myFn2(6,_age)  
        };  
    })();  
    console.log(obj.m1);//9
    console.log(obj.m2)//6
    console.log(obj.age);//undefined
</script>

image.png

放大模式

如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用"放大模式"(augmentation)。在原有的基础上扩展更多的方法。

var obj =(function (mod){  
    mod.myFn3= function () {  
      //...  
    };  
    return mod;//方便方法连续调用  
})(obj);

上面的代码为obj模块添加了一个新方法myFn3 (),然后返回新的obj模块,方便方法连续调用。如何防止obj为null或underfined的情况了?

宽放大模式(Loose augmentation)

在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上面的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用"宽放大模式"。

var obj =( function (mod){  
  //...  
  return mod;  
})(window.obj|| {});//确保对象不为空

与"放大模式"相比,"宽放大模式"就是"立即执行函数"的参数可以是空对象,解决了非空问题。

输入全局变量

独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互。为了在模块内部调用全局变量,必须显式地将其他变量输入模块。

(function(window, undefined ) {  
    ……  
})(window );

这是jQuery框架的源码,将window对象作为参数传入,这样做除了保证模块的独立性,还使得模块之间的依赖关系变得明显。目前,通行的JavaScript模块规范共有两种:CommonJS和AMD。CommonJS可以跟进华为前端课程3阶段node模块化。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。