(event delegation)
事件代理也称为事件委托,利用了事件冒泡。例如:javascript
<ul class="item-list"> <li class="item">item1</li> <li class="item">item2</li> <li class="item">item3</li> </ul>
当页面li
增多时单独给每一个li
元素添加事件处理程序既繁琐又容易出错,利用事件冒泡,在ul
去监听事件,li
产生事件往上冒泡时去捕获,利用e.target
来判断是否为咱们的目标元素,是的话就能够作相应操做了。html
JavaScript
中this
是如何工做的。做为独立函数的调用java
function func(){ console.log(this); } func(); //Window
全局做用域中声明一个函数,并调用它,此时函数中的this指向全局对象。json
做为对象方法调用跨域
function say(){ console.log(this); } var obj = { name: "f2er", say: say }; obj.say(); //Object {name: "f2er"}
当函数做为一个对象的方法调用时,函数中的this
绑定到了这个对象。数组
使用call或apply来调用函数浏览器
function func(){ console.log(this); } var obj = { name:"f2er" }; func.call(obj); //Object {name: "f2er"} func.apply(obj); //Object {name: "f2er"}
当使用call()
或apply()
函数进行函数调用时,传入参数对象的将被设置为函数体内this
的值,这两个函数都是设置调用函数体内的this
值的,且第一个参数都为this
,区别是第二个参数apply()
是一个参数arguments
(类数组对象),而call()
,传递给他的是一系列参数。安全
new
来调用函数服务器
function F2er(name){ this.name = name; console.log(this); } var f2er = new F2er('f2er'); // F2er {name: "f2er"}
当使用new
来调用一个函数时,会建立一个新的对象,而后绑定到Dog()
调用中的this
。闭包
(prototypal inheritance)
的原理。先上一个例子:
function Super(){ this.superValue = "super"; } Super.prototype.getSuperValue = function (){ return this.superValue; } function Sub(){ this.subValue = "sub"; } var superInstance = new Super(); Sub.prototype = superInstance; Sub.prototype.getSubValue = function (){ return this.subValue; } var instance = new Sub(); console.log(instance.getSuperValue()); // super
每一个函数Sub
都有一个属性prototype
,prototype
指向一个原型对象,原型对象中也有一个指向函数的属性constructor
,经过new
一个函数Sub
能够产生实例instance
,调用这个instance
的某个属性或方法时,instance
会先查找自身是否有这个方法或者属性,没有的话就会去实例的构造函数Sub
的原型prototype
中查找,即Sub.prototype
,若是给原型对象Sub.prototype
赋予另外一个类型的实例superInstance
,则是在superInstance
中查找的,这个superInstance
中也有属性prototype
指向某个原型对象,以此一级级往上最终到Object.prototype
,这样就造成了原型继承。
利用此原理能够本身实现一个inherits函数:
function inherits(subType, superType){ var _prototype = Object.create(superType.prototype); _prototype.constructor = subType; subType.prototype = _prototype; }
(function fn(){..})(),函数被包含在一个括号内,变成为一个表达式,随后跟着一个(),就当即执行这个函数,
这种模式就是当即执行函数表达式(Immediately Invoked Function Expression),简称IIFE。
也有用(function fn(){..}())后面的括号在前面的括号内这种形式表示的,这两种形式在功能上都是一致的。
IIFE的一些做用:
建立做用域,内部保存一些大量临时变量的代码防止命名冲突。
一些库的外层用这种形式包起来防止做用域污染。
运行一些只执行一次的代码。
(function(){ var module = require('module'); module.setup(); module.run(); })();
用闭包保存状态
如下点击页面标签的时候,实际并非弹出每一个具体的i
的,而是elems.length
,由于每一个a
监听器中引用的i
都是同一个做用域的。
var elems = document.getElementsByTagName('a'); for (var i = 0; i < elems.length; i++) { elems[i].addEventListener('click', function (e) { e.preventDefault(); alert('I am link #' + i); }, 'false'); }
如下点击页面标签的时候,每个i
传入一个IIFE
,IIFE
造成单独一个做用域保存了当时的i
值,因此点击a
标签,能够弹出不一样的i
值。
var elems = document.getElementsByTagName('a'); for (var i = 0; i < elems.length; i++) { (function (lockedInIndex) { elems[i].addEventListener('click', function (e) { e.preventDefault(); alert('I am link #' + lockedInIndex); }, 'false'); })(i); }
当某个函数调用时会建立一个执行环境以及做用域链,而后根据arguments
和其它命名参数初始化造成活动对象。在外部函数调用结束后,其执行环境与做用域链被销毁,可是其活动对象保存在了闭包之中,最后在闭包函数调用结束后才销毁。简单的说,闭包就是可以读取其余函数内部变量的函数。在js
中,闭包是指有权访问另外一个函数做用域中的变量的函数。
匿名自执行函数
有的场景下函数只须要执行一次,例如init()
之类的函数,其内部变量无需维护,咱们可使用闭包。 咱们建立了一个匿名的函数,并当即执行它,因为外部没法引用它内部的变量,所以在函数执行完后会马上释放资源,并且不污染全局对象。
封装
模拟面向对象的代码风格进行封装,使私有属性存在成为可能。
常驻内存,会增大内存使用量,易形成内存泄露
JavaScript
宿主对象和原生对象的区别?宿主对象是指DOM
和BOM
。
原生对象是Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、Math
等对象。
function Person(){}、var person = Person()、var person = new Person()
?function Person(){}
声明一个函数Person()
。
var person = Person()
将函数Person()
的结果返回给变量person
,若是没有返回值则person
为undefined
。
var person = new Person()
new
一个Person
的实例对象。
.call
和.apply
的区别是什么?.call
和.apply
的共同点是都是用来改变函数体内this
对象的值。
区别是第二个参数不同。apply()
的第二个参数是一个类数组对象arguments
,参数都是以数组的形式传入,而call()
,传递给他的是一系列参数。例如
Math.max.call(null, 1, 2, 3, 4); //4 Math.max.apply(null, [1, 2, 3, 4]); //4
Function.prototype.bind
Function.prototype.bind
方法会建立一个新函数,当这个新函数被调用时,它的this
值是传递给bind()
的第一个参数, 它的参数是bind()
的其余参数和其本来的参数.
Function.prototype.bind
的实现相似于:
Function.prototype.bind = function (scope) { var fn = this; return function () { return fn.apply(scope, arguments); }; }
Function.prototype.bind
的做用
建立绑定函数
一些函数的参数经常也是函数,给当作参数的函数绑定this
值确保参数函数执行时有正确的this
指向。
Ajax
的工做原理
Ajax
是无需刷新页面就能从服务器取得数据的一种方法。
Ajax
经过XmlHttpRequest
对象来向服务器发异步请求,从服务器得到数据,而后用javascript
来操做DOM
更新页面。
建立XMLHttpRequest
对象。
设置响应HTTP
请求的回调函数。
建立一个HTTP
请求,指定相应的请求方法、url
等。
发送HTTP
请求。
获取服务器端返回的数据。
使用JavaScript
操做DOM
更新页面。
对搜索引擎不友好
要实现Ajax
下的先后退功能成本较大
跨域问题限制
JSONP
的工做原理
JSONP(JSON with Padding)
是一种非官方跨域数据交互协议,它容许在服务器端集成<script>
标签返回至客户端,经过javascript
回调的形式实现跨域访问。
由于同源策略的缘由,咱们不能使用XMLHttpRequest
与外部服务器进行通讯,可是<script>
能够访问外部资源,因此经过JSON
与<script>
相结合的办法,能够绕过同源策略从外部服务器直接取得可执行的JavaScript
函数。
客户端定义一个函数,好比jsonpCallback
,而后建立<script>
,src
为url + ?jsonp=jsonpCallback
这样的形式,以后服务器会生成一个和传递过来jsonpCallback
同样名字的参数,并把须要传递的数据当作参数传入,好比jsonpCallback(json)
,而后返回给客户端,此时客户端就执行了这个服务器端返回的jsonpCallback(json)
回调。
通俗的说,就是客户端定义一个函数而后请求,服务器端返回的javascript
内容就是调用这个函数,须要的数据都当作参数传入这个函数了。
优势 - 兼容性好,简单易用,支持浏览器与服务器双向通讯
缺点 - 只支持GET请求;存在脚本注入以及跨站请求伪造等安全问题
补充一点,JSONP
不使用XMLHttpRequest
对象加载资源,不属于真正意义上的AJAX
。
变量的声明前置就是把变量的声明提高到当前做用域的最前面。
函数的声明前置就是把整个函数提高到当前做用域的最前面(位于前置的变量声明后面)。
//变量的声明前置 console.log(num);//undefined var num = 1; 等价于 //变量的声明前置 var num; console.log(num);//undefined num = 1;
//函数的声明前置 var num = 1; console.log(doubleNum(num));//2 function doubleNum(num){ return num*2; } 等价于 //函数的声明前置 var num; function doubleNum(num){ return num*2; } num = 1; console.log(doubleNum(num));//2
事件冒泡(event bubbling),事件最开始时由触发的那个元素身上发生,而后沿着DOM
树向上传播,直到document
对象。若是想阻止事件起泡,可使用e.stopPropagation()
。
JavaScript
的同源策略同源策略限制了一个源(origin)中加载文本或脚本与来自其它源(origin)中资源的交互方式。同源指的是协议、域名、端口相同,同源策略是一种安全协议。
同源策略保证了用户的信息安全,浏览器打开多个站点时,互相之间不能利用JavaScript
获取对方站点的敏感信息。
JSONP
CORS
修改document.domain来进行跨域
使用window.name来进行跨域
使用window.postMessage来进行跨域
"use strict"
?使用它的好处和坏处分别是什么?在全部语句以前放一个特定语句
"use strict"
,就会为整个script标签开启严格模式。
消除Javascript
语法的一些不严谨之处,减小一些怪异行为;
消除代码运行的一些不安全之处,保证代码运行的安全;
提升编译器效率,增长运行速度;
为将来新版本的Javascript
作好铺垫。
严格模式改变了语义。依赖这些改变可能会致使没有实现严格模式的浏览器中出现问题或者错误。