页面中使用多个js,导致js冲突,怎么解决。一般js冲突是不是就是id一名字一样导致,还有其他原因导致么?
大部分是因为变量名,函数名重名冲突。
如果js都是自己写的,那尽量封装好每一个功能块。
如果都是网上下的模板,那你得找到冲突源,改写代码了。
】传统浏览器端JavaScript在使用的时候存在的命名冲突和什么两大问题?
程序采用了异步事件驱动编程(Event-driven programming)模型,维基百科对它的解释是:
简页言之,在 web 前端编程里面 JavaScript 通过浏览器提供的事件模型 API 和用户交互,接收用户的输入
由于用户的行为是不确定的,也就是说不知道用户什么时候发生点击、滚动这些动作。这种场景是传统的同步编程模型没法解决的,因为你不可能等用户操作完了才执行后面的代码
比如我们在 Python 里面调用接收用户输入的方法 raw_input() 后终端就会一直等待用户的输入,直到输入完成才会执行后面的代码逻辑。但是在下面这段 NodeJS 代码中,接收用户输入的方法 process.stdin.read 是在一个事件中调用的。后面的代码不会被阻塞(blocked)
55a635844547e8d0bfaabfd4bb75401d.png
事件驱动程序模型基本的实现原理基本上都是使用 事件循环(Event Loop),这部分内容涉及浏览器事件模型、回调原理,有兴趣的去看链接里面的视频学习下
需要说明的是在客户端 JavaScript 中像 setTimeout, XMLHTTPRequest 这类 API 并不是JavaScript 语言本身就有的。而是 JavaScript 的宿主环境(在客户端 JavaScript 中就是浏览器),同样像 DOM、BOM、Event API 都是浏览器提供的
事件绑定的方法
DOM 元素行内绑定
直接在 DOM 元素上通过设置 on + eventType 来绑定事件处理程序
这种绑定方法是最原始的,有两个缺点:
1 事件处理程序和 HTML 结构混杂在一起
早期在结构、样式、表现分离的时代很忌讳这一点。现在看来在很多 MVX 框架中将事件绑定和 DOM 结构放在一起处理,这样似乎更方便维护(不用来回切换 HTML,JavaScript 文件),而且也符合可预见(predictable)性的规则
2 命名空间冲突
因为 onclick 中的 JavaScript 代码片段执行环境是全局作用域。然而在 JavaScript 语言中并没有相关的命名空间特性。所以就很容易造成命名空间的冲突,非要用这种方法绑定事件的话只能用对象来做一些封装
JavaScript函数重名怎么办?
,因为脚本在页面里本身就是顺序执行下来的,包括函数的定义,但然如果只是定义 function foo(){}
这种形式,我们是跟踪不到函数初始化的。可是如果是定义类的方式,我们就可以明显地跟踪到函数的初始化顺序。比如:
function foo() {}
function foo.prototype.fn1() {}
function foo.prototype.fn2() {}
我们就可以明显地看到先执行function foo.prototype.fn1(){}再执行function
foo.prototype.fn2(){}。
回到我们刚才说的JavaScript脚本函数重名问题上来,比如我们定义两个函数 funAlert():
function funAlert()
{
alert(‘A’);
}
function funAlert()
{
alert(‘B’);
}
调用 funAlert(),那么将显示一个MegBox,内容为’B’。
为什么初始化函数会有这样的效果?这里只用把上面两个函数的定义改一下,就会一目了然了,我们把定义改为:
var fnAlert = new Function(“alert(‘A’)”);
var fnAlert = new Function(“alert(‘B’)”);
window.fnAlert();
其函数也就是定义在对象上的一个函数指针,我们象这个指针赋什么函数引用,它就执行什么效果,而JavaScript中的脚本函数重名就和普通赋值语句一样,等同于:
var i = 0;
var i = 1;
// 稍微注意以下JavaScript里的var,用var定义变量和我们平时用的高级语言定义变量是不同的,它只起到一个提示的作用,提醒说我在这里定义变量了,而没有什么变量作用域的概念,只要不离开定义它的对象的域(比如页面刷新),出现过的变量会就一直存在。所以var写不写都行。举个例子:
if ( true )
{
t = 100;
}
alert(t);
将显示100,而
if ( true )
{
var t = 100;
}
alert(t);
也是显示100。
所以JavaScript的脚本函数名重不重复只是一个运算的问题,和我们高级语言里的语法约束完全不是一回事,当然也更不是overload的范畴。
脚本函数名重名有什么用呢?最直观就是可以用来实现伪重载,比如我们不少免费的主页空间常常会给你强加弹出窗口广告,我们就可以在页面第一行写上:
script language=”javascript”
var _open = window.open;
window.open = function() {}
/script
这样就可以屏蔽掉不是加在页面第一行上的弹出窗口广告(加在第一行不能拦截,因为window.open还没有被’重载’open就先执行了)。
Web前端工程师应该知道的JavaScript的10个难点!
今天小编要跟大家分享的文章是关于Web前端工程师应该知道的JavaScript的10个难点。相信很多正在学习Web前端知识的小伙伴对于JavaScript存在很多疑问,为了帮助大家更好的学习Web前端知识,成为一名优秀的web前端工程师,今天小编为大家分享了这篇Web前端应该知道的JavaScript难点的问题,下面我们一起看一看吧!
1、立即执行函数
立即执行函数,即ImmediatelyInvokedFunctionExpression
(IIFE),正如它的名字,就是创建函数的同时立即执行。它没有绑定任何事件,也无需等待任何异步操作:
1.(function(){
2.
3.//代码
4.
5.//…
6.
7.})();
function(){}是一个匿名函数,包围它的一对括号将其转换为一个表达式,紧跟其后的一对括号调用了这个函数。立即执行函数也可以理解为立即调用一个匿名函数。立即执行函数最常见的应用场景就是:将var变量的作用域限制于你们函数内,这样可以避免命名冲突。
2、闭包
对于闭包(closure),当外部函数返回之后,内部函数依然可以访问外部函数的变量。
1.(function(){
2.
3.//代码
4.
5.//…
6.
7.})();
代码中,外部函数f1只执行了一次,变量N设为0,并将内部函数f2赋值给了变量result。由于外部函数f1已经执行完毕,其内部变量N应该在内存中被清除,然而事实并不是这样:我们每次调用result的时候,发现变量N一直在内存中,并且在累加。为什么呢?这就是闭包的神奇之处了!
3、使用闭包定义私有变量
通常,JavaScript开发者使用下划线作为私有变量的前缀。但是实际上,这些变量依然可以被访问和修改,并非真正的私有变量。这时,使用闭包可以定义真正的私有变量:
1.functionProduct(){
2.
3.varname;
4.
5.this.setName=function(value){
6.name=value;
7.};
8.
9.this.getName=function(){
10.returnname;
11.};
12.}
13.
14.varp=newProduct();
15.p.setName(“Fundebug”);
16.
17.console.log(p.name);//输出undefined
18.console.log(p.getName());//输出Fundebug
代码中,对象p的的name属性为私有属性,使用p.name不能直接访问。
4、prototype
每个JavaScript构造函数都有一个prototype属性,用于设置所有实例对象需要共享的属性和方法。prototype属性不能列举。JavaScript仅支持通过prototype属性进行继承属性和方法。
1.functionRectangle(x,y)
2.{
3.this._length=x;
4.this._breadth=y;
5.}
6.
7.Rectangle.prototype.getDimensions=function()
8.{
9.return{
10.length:this._length,
11.breadth:this._breadth
12.};
13.};
14.
15.varx=newRectangle(3,4);
16.vary=newRectangle(4,3);
17.
18.console.log(x.getDimensions());//{length:3,breadth:4}
19.console.log(y.getDimensions());//{length:4,breadth:3}
代码中,x和y都是构造函数Rectangle创建的对象实例,它们通过prototype继承了getDimensions方法。
5、模块化
JavaScript并非模块化编程语言,至少ES6落地之前都不是。然而对于一个复杂的Web应用,模块化编程是一个最基本的要求。这时,可以使用立即执行函数来实现模块化,正如很多JS库比如jQuery以及我们Fundebug都是这样实现的。
1.varmodule=(function(){
2.varN=5;
3.
4.functionprint(x){
5.console.log(“Theresultis:”+x);
6.}
7.
8.functionadd(a){
9.varx=a+N;
10.print(x);
11.}
12.
13.return{
14.description:”Thisisdescription”,
15.add:add
16.};
17.})();
18.
19.
20.console.log(module.description);//输出”thisisdescription”
21.
22.module.add(5);//输出“Theresultis:10”
所谓模块化,就是根据需要控制模块内属性与方法的可访问性,即私有或者公开。在代码中,module为一个独立的模块,N为其私有属性,print为其私有方法,decription为其公有属性,add为其共有方法。
6、变量提升
JavaScript会将所有变量和函数声明移动到它的作用域的最前面,这就是所谓的变量提升(Hoisting)。也就是说,无论你在什么地方声明变量和函数,解释器都会将它们移动到作用域的最前面。因此我们可以先使用变量和函数,而后声明它们。但是,仅仅是变量声明被提升了,而变量赋值不会被提升。如果你不明白这一点,有时则会出错:
1.console.log(y);//输出undefined
2.
3.y=2;//初始化y
上面的代码等价于下面的代码:
1.vary;//声明y
2.
3.console.log(y);//输出undefined
4.
5.y=2;//初始化y
为了避免BUG,开发者应该在每个作用域开始时声明变量和函数。
7、柯里化
柯里化,即Currying,可以是函数变得更加灵活。我们可以一次性传入多个参数调用它;也可以只传入一部分参数来调用它,让它返回一个函数去处理剩下的参数。
1.varadd=function(x){
2.returnfunction(y){
3.returnx+y;
4.};
5.};
6.
7.console.log(add(1)(1));//输出2
8.
9.varadd1=add(1);
10.console.log(add1(1));//输出2
11.
12.varadd10=add(10);
13.console.log(add10(1));//输出11
代码中,我们可以一次性传入2个1作为参数add(1)(1),也可以传入1个参数之后获取add1与add10函数,这样使用起来非常灵活。
8、apply,call与bind方法
JavaScript开发者有必要理解apply、call与bind方法的不同点。它们的共同点是第一个参数都是this,即函数运行时依赖的上下文。
三者之中,call方法是最简单的,它等价于指定this值调用函数:
1.varuser={
2.name:”RahulMhatre”,
3.whatIsYourName:function(){
4.console.log(this.name);
5.}
6.};
7.
8.user.whatIsYourName();//输出”RahulMhatre”,
9.
10.varuser2={
11.name:”NehaSampat”
12.};
13.
14.user.whatIsYourName.call(user2);//输出”NehaSampat”
·apply方法与call方法类似。两者唯一的不同点在于,apply方法使用数组指定参数,而call方法每个参数单独需要指定:
·apply(thisArg,[argsArray])
1.varuser={
2.greet:”Hello!”,
3.greetUser:function(userName){
4.console.log(this.greet+””+userName);
5.}
6.};
7.
8.vargreet1={
9.greet:”Hola”
10.};
11.
12.user.greetUser.call(greet1,”Rahul”);//输出”HolaRahul”
13.user.greetUser.apply(greet1,[“Rahul”]);//输出”HolaRahul”
使用bind方法,可以为函数绑定this值,然后作为一个新的函数返回:
1.varuser={
2.greet:”Hello!”,
3.greetUser:function(userName){
4.console.log(this.greet+””+userName);
5.}
6.};
7.
8.vargreetHola=user.greetUser.bind({greet:”Hola”});
9.vargreetBonjour=user.greetUser.bind({greet:”Bonjour”});
10.
11.greetHola(“Rahul”)//输出”HolaRahul”
12.greetBonjour(“Rahul”)//输出”BonjourRahul”
9、memoization
Memoization用于优化比较耗时的计算,通过将计算结果缓存到内存中,这样对于同样的输入值,下次只需要中内存中读取结果。
1.functionmemoizeFunction(func)
2.{
3.varcache={};
4.returnfunction()
5.{
6.varkey=arguments[0];
7.if(cache[key])
8.{
9.returncache[key];
10.}
11.else
12.{
13.varval=func.apply(this,arguments);
14.cache[key]=val;
15.returnval;
16.}
17.};
18.}
19.
20.
21.varfibonacci=memoizeFunction(function(n)
22.{
23.return(n===0||n===1)?n:fibonacci(n-1)+fibonacci(n-2);
24.});
25.
26.console.log(fibonacci(100));//输出354224848179262000000
27.console.log(fibonacci(100));//输出354224848179262000000
代码中,第2次计算fibonacci(100)则只需要在内存中直接读取结果。
10、函数重载
所谓函数重载(method
overloading),就是函数名称一样,但是输入输出不一样。或者说,允许某个函数有各种不同输入,根据不同的输入,返回不同的结果。凭直觉,函数重载可以通过if…else或者switch实现,这就不去管它了。jQuery之父John
Resig提出了一个非常巧(bian)妙(tai)的方法,利用了闭包。
从效果上来说,people对象的find方法允许3种不同的输入:
0个参数时,返回所有人名;1个参数时,根据firstName查找人名并返回;2个参数时,根据完整的名称查找人名并返回。
难点在于,people.find只能绑定一个函数,那它为何可以处理3种不同的输入呢?它不可能同时绑定3个函数find0,find1与find2啊!这里的关键在于old属性。
由addMethod函数的调用顺序可知,people.find最终绑定的是find2函数。然而,在绑定find2时,old为find1;同理,绑定find1时,old为find0。3个函数find0,find1与find2就这样通过闭包链接起来了。
根据addMethod的逻辑,当f.length与arguments.length不匹配时,就会去调用old,直到匹配为止。
1.functionaddMethod(object,name,f)
2.{
3.varold=object[name];
4.object[name]=function()
5.{
6.//f.length为函数定义时的参数个数
7.//arguments.length为函数调用时的参数个数
8.if(f.length===arguments.length)
9.{
10.returnf.apply(this,arguments);
11.}
12.elseif(typeofold===”function”)
13.{
14.returnold.apply(this,arguments);
15.}
16.};
17.}
18.
19.
20.//不传参数时,返回所有name
21.functionfind0()
22.{
23.returnthis.names;
24.}
25.
26.
27.//传一个参数时,返回firstName匹配的name
28.functionfind1(firstName)
29.{
30.varresult=[];
31.for(vari=0;i
32.{
33.if(this.names[i].indexOf(firstName)===0)
34.{
35.result.push(this.names[i]);
36.}
37.}
38.returnresult;
39.}
40.
41.
42.//传两个参数时,返回firstName和lastName都匹配的name
43.functionfind2(firstName,lastName)
44.{
45.varresult=[];
46.for(vari=0;i
47.{
48.if(this.names[i]===(firstName+””+lastName))
49.{
50.result.push(this.names[i]);
51.}
52.}
53.returnresult;
54.}
55.
56.
57.varpeople={
58.names:[“DeanEdwards”,”AlexRussell”,”DeanTom”]
59.};
60.
61.
62.addMethod(people,”find”,find0);
63.addMethod(people,”find”,find1);
64.addMethod(people,”find”,find2);
65.
66.
67.console.log(people.find());//输出[“DeanEdwards”,”AlexRussell”,”DeanTom”]
68.console.log(people.find(“Dean”));//输出[“DeanEdwards”,”DeanTom”]
69.console.log(people.find(“Dean”,”Edwards”));//输出[“DeanEdwards”]
以上就是小编今天为大家分享的关于Web前端工程师应该知道的JavaScript的10个难点。希望本篇文章能够对正在从事Web前端学习的小伙伴们有所帮助。想要了解更多web前端相关知识记得关注北大青鸟Web培训官网最后祝愿小伙伴们工作顺利!
原文链接:#/a/1190000010371988