JavaScript面试笔试题

JavaScript前端面试

系列文章:

HTML及HTTP面试笔试题
CSS面试笔试题

JS一些算法题:

FE-interview-questions,满意点个star。(待更新)

0. 序

本文没有太多基础性的js内容,推荐一本书《JavaScript高级程序设计》,基础不好的同学建议先学习该本书。重点内容:事件,闭包,作用域练,原型,继承。

1.情简述一下javascript的执行环境(执行上下文)以及所涉及到到一些概念?(该文的整体笔记丢失,详细内容建议查看引用链接)

每当控制器转到可执行环境时,就会进入一个执行环境

而执行环境大致分为三类:

  • 全局环境
  • 函数环境
  • eval(个人不了解,开发也不会用到不做讲解)

执行环境是靠栈来存储,每当开始执行js代码的时候,就进入到了全局执行环境,于是乎,就把全局执行环境压到了这个栈(我们暂时称它为执行环境栈)中。

而在全局代码中,会定义很多函数,函数中又会定义很多函数,而每当控制器执行到函数时,则就进入到了这个函数的执行环境中。

http://www.jianshu.com/p/cd3fee40ef59

2.sessionStorage,localStorage,cookie区别

  • 共同点:都是浏览器端的数据存储,同源;
  • 不同点:
  1. cookie在同源的http请求中携带,浏览器与服务器之前回传。cookie有路径的概念;cookie大小不超过4k。
  2. sessionStorage(浏览器关闭窗口前有效)和localStorage(一直有效)达到5M或者更大。
  3. cookie在设置的有效期前有效
  4. session不在不同的浏览器窗口中共享,loacl共享,cookie也共享。
  5. sessionStorage和localStorage支持事件机制

3.localStorage应该如何进行存储?

// 将数据存在loaclStorage中

export function saveToLocal(id, key, value) {
  let seller = window.localStorage.__seller__; 
  if (!seller) {
    seller = {};
    seller[id] = {};
  } else {
    seller = JSON.parse(seller);
    if (!seller[id]) {
      seller[id] = {};
    }
  }
  seller[id][key] = value;
  window.localStorage.__seller__ = JSON.stringify(seller);
};

export function loadFromLocal(id, key, def) {
  let seller = window.localStorage.__seller__;
  if (!seller) {
    return def;
  }
  seller = JSON.parse(seller)[id];
  if (!seller) {
    return def;
  }
  let ret = seller[key];
  return ret || def;
};

4.GET与POST的区别?

  • GET与POST都是HTTP协议中的请求发送方式,实际上他们都是TCP,所能做的事情都是一样的。
  • 不同在于,HTTP规定,发送GET请求时,在HTTP Header的请求行上就声明GET,反之POST就声明POST。
  • HTTP要求,GET把数据放在url上,所以GET常用于发少量的数据用于查询;POST把数据放在body中,数据量相对较大用来存储。
  • GET请求只发一次,POST发两次,header返回后再发送date。

5.同源策略指的是什么?

  • 同源指的是以下三个都相同:
    • 协议相同
    • 域名相同
    • 端口相同
  • 所谓同源策略指的是:浏览器对不同源的脚本或者文本的访问方式进行的限制。比如源a的js不能操作引入的源b的元素属性。
  • 限制主要为:
    • Cookie、LocalStorage 和 IndexDB 无法读取。
    • DOM无法获取
    • AJAX请求不能发送

6.如何才能跨域,跨域方式有哪些?

  • 设置document.domain

Cookie是服务器写入浏览器的一小段信息,只有同源的网页才能共享。但是,两个网页的一级域名相同,只是二级域名不相同,浏览器允许通过设置document.domain共享Cookie。

www.a.com/a.html

document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://www.script.a.com/b.html';
ifr.display = none;
document.body.appendChild(ifr);
ifr.onload = function(){
    var doc = ifr.contentDocument || ifr.contentWindow.document;
    // 这里就能b.html的cookie了
    ifr.cooike = doc.cookie;
};

在 script.a.com/b.html 中

document.cookie = "test1=hello";
document.domain = 'a.com';

这样不仅能访问b的cookie,还可以访问b的dom,但是无法访问到LocalStorage 和 IndexDB,而且主要限制是a,b必须一级域名必须相同

  • window.name

浏览器窗口都有window.name这个属性,这个属性最大的特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页就可以读取它。

在b.com/data.html中有这样的数据

<script>
    window.name = '我是你们想要的数据。';
</script>  

现在a.com/index.html想获取这个数据应该怎么办?通过iframe充当中间人

<script>
    function getDate(url){
        var iframe = document.createElement('iframe');
        iframe.style.display='none';
        var state = 0;
        
        iframe.onload = function(){
            if(state == 1){
                var dataPage = iframe.contentWindow;
                var data = dataPage.name;
                console.log(data);
                dataPage.document.write('');
                dataPage.close();
                document.body.remove(iframe);
            }else
            {
                state = 1;
                iframe.contentWindow.location = url;
            }
        };
        
        // 代理源,创建好且设置了document.name
        iframe.src = 'a.com/b.html';
    }
    
    getData('b.com/data.html');
</script>  

些人可能会问为什么不直接把iframe的src设置为目的源(b.com/data.html)来获取数据,而是在设置为目的源之后,还要把src设置为同域名下的其他源(a.com/b.html)才获取数据?

如果直接设置src,那么iframe和本网页(a.com/index.html)会因为同源策略限制不能访问。而把iframe先设置为目的源,再设置为同域名下的其他源,那么同域名下的其他源就和目的源共享了一个窗口,故拥有同样window.name,并且由于是同域名下的源,并且设置了domain,故可以访问目标源的window.name。

state用来干什么

每次设置src,都会刷新,state是标志位,让获取了数据就销毁掉。

  • window.postMessage

上面的方法都是破解,H5提供了官方的API:window.postMessage。允许跨窗口通信,不论这两个窗口是否同源。

// 举例来说,父窗口http://aaa.com向子窗口http://bbb.com发消息,调用postMessage方法就可以了。
var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!', 'http://bbb.com');

postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。

// 子窗口向父窗口发送消息的写法类似。
window.opener.postMessage('Nice to see you', 'http://aaa.com');

// 父窗口和子窗口都可以通过message事件,监听对方的消息。
window.addEventListener('message', function(e) {
  console.log(e.data);
},false);

// event.source:发送消息的窗口
// event.origin: 消息发向的网址
// event.data: 消息内容

下面的例子是,子窗口通过event.source属性引用父窗口,然后发送消息。

window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
  event.source.postMessage('Nice to see you!', '*');
}
  • AJAX

利用jsonp

// 首先,网页动态插入<script>元素,由它向跨源网址发出请求。

function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}

function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};

阮一峰老师:浏览器同源政策及其规避方法

7. AJAX模型是什么?

  • AJAX全称为“AsynchronousJavaScript and XML” 异步的JavaScript和Xml,是一种创建交互式网页应用开发的新技术。
  • 运用AJAX
// 创建xmlHttpRequest对象
function createXmlHttp(){
    var xmlHttp;
    if(window.XMLHttpRequest){
        xmlHttp = new XMLHttpRequest();
    }else{
        xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
    }
    return xmlHttp;
}

var xhr = createXmlHttp();

// 发送请求GET或者POST
// 第三个参数代表是否异步
xhr.open('GET',url+'?date='+ new Date().getTime(),true);

//GET发送的数据在url上 POST发送的数据在send()中
xhr.send();

// 回调函数响应
xhr.onreadystatechange=function(){
    if(xhr.readyState == 4 && xhr.status == 200){
        document.getElementById("myDiv").innerHTML=xhr.responseText;
    }
}
    
// xhr.readyState存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
// 0: 请求未初始化
// 1: 服务器连接已建立
// 2: 请求已接收
// 3: 请求处理中
// 4: 请求已完成,且响应已就绪

// status:状态码

// 如果是同步,直接调用xhr.responseText即可

8.为什么说jsonp不是真正的ajax?

  • 为什么说jsonp是ajax?

因为他们目的一样,都是请求一个url,然后把服务器返回的数据进行处理。故jquery把jsonp封装为ajax的一种形式。

  • 那为什么jsonp不是真正的ajax?

ajax和jsonp其实本质上是不同的东西,ajax的核心通过XmlHttpRequest获取非本页面内容,而jsnop的核心是动态加载script来调用服务器提供的js脚本

ajax 和jsonp 不是一码事 细读详解

9.property 和 attribute有什么区别?

  • property表示DOM的基础属性。
<input id='ipt' value='123' other='1111' />

console.log(document.getElementById('ipt'));

可以发现有attributes,value,id,以及很多我们并没有赋值的属性,但是并没有other属性。value,id这样的就叫做DOM的基础属性。

  • 正如打印出来的结果还有一个叫attributes的属性,类型是NamedNodeMap。这里就可以说attributes是DOM 的property的其中一个。

点击开这个你会发现有

0: id
1: value
2: other
length: 3
__proto__: NamedNodeMap

这个属性包含了显示定义在标签上的属性。

console.log(ipt.attributes.other); // other="1111";

并且

console.log(typeof ipt.attributes.other); // object

返回的是一个对象。

  • property能够从attribute中得到同步,attribute不会同步property上的值;
in1.value = 'new value of prop';
console.log(in1.value);             // 'new value of prop'
console.log(in1.attributes.value);  // 'value="1"'

in1.attributes.value.value = 'new value of attr';
console.log(in1.value);             // 'new value of attr'
console.log(in1.attributes.value);  // 'new value of attr'

10. 关于==的强制类型转换

image
  1. 重点:

    1. Number与String比较,String转Number。
    2. Number与Object比较,Object转String。
    3. 当比较中出现Boolean,无论另一个数据是什么类型,都先把Boolean转为Number。
    4. undefined与null,undefined与undefined,
      null与null都返回true。
    5. Object 与 Object只有引用相同返回true。
  2. 数据类型转化为Boolean的规则:

    1. String的 “” 转换为Boolean为false其他都为true
    2. Number的0和NaN转换为Boolean为false其他都为true
    3. Object的null转换为Boolean为false其他都为true
    4. Undefined转换为false 不能转换为true
[] == ![] //true

// 1.由于!的优先级比较高,先执行![],[]是空数组,数组是对象,由2.3(需要了解的知识文字序号),则[]转换为boolean结果为true,![]结果就为false,表达式变为判断 []==false
// 2.根据1.3,将false转为Number,结果为0,表达式变为判断 [] == 0
// 3.根据1.2,将[]变为String,结果为"",表达式变为判断 "" == 0
// 4.根据1.1,将""变为Number,结果为0,表达式变为判断 0 == 0
返回结果 true

console.log(1 == true); // 文字1.3,Number(true) = 1  ->  1 == 1 true
console.log(2 == true); // 文字1.3,Number(true) = 2  ->  2 == 1 false
console.log(0 == false);//文字 1.3,Number(false)= 0  ->  0 == 0 true
console.log(NaN == NaN);// 图片1.c.i/1.c.ii false
console.log({} == {});// 图片1.f {}是对象,比较引用指向的空间,因为是两个不同的空对象,地址也不一样 false
console.log([] == []);// 同理
console.log(null == 0);// 文字1.2 null是对象,String(null) == "null"  -> "null" == 0 ,文字1.1 Number("null") == NaN -> NaN == 0 false
console.log(undefined == 0);// 这里将执行String(undefined),之后执行步骤同上

总结:
undefined == null,结果是true。且它俩与所有其他值比较的结果都是false。

String == Boolean,需要两个操作数同时转为Number。

String/Boolean == Number,需要String/Boolean转为Number。

Object == Primitive,需要Object转为Primitive(具体通过valueOf和toString方法)。

11.支持正则表达式的方法:

  • RegExp 对象方法
// 1. complie() 用于编译正则表达式或改变正则表达式
let str = 'woman1manm';
let patt = /(wo)?man/g;
let str2 = str.replace(patt,'2222'); // 222212222m
let patt2 = /2222/g;
patt.compile(patt2); // 改变了正则表达式
let str3 = str2.replace(patt,'woman'); // 返回 woman1womanmm

// 2. exec() 未匹配到返回一个null,匹配到则返回一个数组arr
// arr[0]表示匹配到的这个字符串,arr[1]...arr[n]表示依次匹配到的圆括号的值,如果有的话
// 并且arr有两个属性,index表示第一次匹配到的字符串下标,input表示需要匹配的字符串本身
let str = '22222womanmmmmmmmanmmmmman';
let patt = /(wo)?(man)/g;
let what = patt.exec(str); 
console.log(what);

// 返回 :
// [ 'woman',
//   'wo',
//   'man',
//   index: 5,
//   input: '22222womanmmmmmmmanmmmmman' ]

// 因为patt是全局搜索,所以exec还可以继续搜索,并且这个时候patt还有一个属性lastIndex表示 匹配文本的最后一个字符的下一个位置

console.log(patt.lastIndex) // 10
what = patt.exec(str);
console.log(what);

// 返回 :
// [ 'man',
//   'undefined',
//   'man',
//   index: 16,
//   input: '22222womanmmmmmmmanmmmmman' ]
//当patt再也匹配不到时,lastIndex会被重置为0

//3. test(str) 检索字符串是否有这个模式,有返回true否则false
  • String对象方法
// 1. search(patt),搜索字符串是否含有这个匹配,如果有就返回其实位置下标,没有就返回-1。

// 2. match(patt), 在字符串内检索指定的模式,返回存放匹配结果的数组,该数组内容依赖于regexp是否具有g。
// 如果没有g,则返回的结果与exec相同。既,str.match(patt) 和 patt.exec(str)的返回结果相同。如果有g,是全局匹配,则会返回所有匹配结果。

let str = '22222womanmmmmmmmanmmmmman';
let patt = /(wo)?(man)/g;
let result = str.match(patt);
console.log(result); // [ 'woman', 'man', 'man' ]

// 3. replace(patt,str) ,返回一个新的字符串,如果有g将所有匹配值换成目标字符串,没有则替换第一个。
// $1、$2、...、$99代表圆括号所匹配的值
var name = "Doe, John";
console.log(name.replace(/(\w+)\s*, \s*(\w+)/, "$2 $1")); // John Doe

12.常用的正则表达式:

  • 匹配一个邮箱:
/^([a-zA-Z0-9])+([a-zA-Z0-9_-\.])*@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/ 

开始必须是数组英文字母开头,然后是可以是任意数字字母下划线或者点,然后@,之后是邮箱名,域名。

  • 匹配ip地址:
/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/
  • 匹配电话号码
/^[1][34578][0-9]{9}$/
  • 检查输入字符串是否是带小数的数字格式,可以是负数
/^-?(\d+)[\.]?(\d+)$/

13. es6中的let,const和var有什么区别?

  • let的作用域是外层块,不是外层函数,而var是外层函数。
if(true){
    let a =0;
    var b =0;
}
console.log(a) // 报错,未定义
console.log(b) // 就是0
  • let没有声明提升,但是有暂时性死区。
console.log(a); // 结果是报错,不是undefined
let a = 0; 


if(true){
    var c = 0; // 报错,因为c已经定义在此区域了。
    let c = 0;
}
  • 重新声明会报错
  • const与let一样,不同在于const引用的地址不能改变,值也不能改变。声明必须赋值。

14.var f = function g(){ return 23; }; typeof g()结果是什么?为什么?

  • typeof f :function,因为f本来就是一个函数。
  • typeof f():number,因为f()先执行,返回了一个数字,23.
  • typeof g:undefined,因为typeof一个未声明的变量,都默认返回undefined。
  • typeof g():报错,g未定义。因为function是函数表达式的形式,并且赋值给了f,所以这个函数就算f,而g只是一个匿名,只能在函数f中使用,在全局访问不到。

15.最完美的数组去重:

function normalize(arr) {
    // 判断传入的是否是数组
    if (arr && Object.prototype.toString.call(arr) !== '[object Array]') {
        return;
    }

    // 当作为对象属性时,会发生强制类型转换,为了区别类型,创建不同对象来去重。
    // 例如: 1,'1' 都会被转化为 obj['1'],导致去重出错, 故区别类型。
    const objectSet = {};

    // Object.create(null), 以防和原型上的函数名冲突。
    // 例如: obj[toString], 本来是没有重复的,但是obj[toString]会查找到
    // 原型上的toString方法,“temp in map”会为true,故利用Object.create(null)
    // 使原型为空
    objectSet.number = Object.create(null);
    objectSet.string = Object.create(null);
    objectSet.array = Object.create(null);
    objectSet.boolean = Object.create(null);
    objectSet.object = Object.create(null);
    objectSet.undefined = Object.create(null);

    let len = arr.length, temp, type, map;

    for (let i = len - 1; i >= 0; i--) {
        temp = arr[i];
        // 取相应的去重对象。
        if(Object.prototype.toString.call(temp) === '[object Array]'){
            map = objectSet.array;
        }else{
            type = typeof temp;
            map = objectSet[type];
        }
        if (temp in map) {
            arr.splice(i, 1);
        } else {
            map[temp] = true;
        }
    }
    return arr;
}

const arr = [1, '1', 1, 'toString', ['toString'], 1, '', 2, '', null, 'null', 2, 2, null, 3, 3];
console.log(normalize(arr));

16. 把字符串转化为大小写:

toUpperCase(): 转大写
toLowerCase(): 转小写

17. 为什么js是阻塞加载的?

当引用了js的时候,浏览器发送一个js请求,就会一直等待请求的返回,因为浏览器需要一个稳定的dom结构,而js中很有可能直接改变了dom结构,为了防止渲染好的树又被js代码修改,所以就会阻塞其他的下载和呈现。

18. 数组长度问题:

  • 为什么结果不是3?
 var arr = [];
arr[0]  = 'a';
arr[1]  = 'b';
arr.foo = 'c';
console.log(arr.length); //2 

length返回的是array数组索引长度。

var arr = [];
arr[9] = 1;
console.log(arr.length); // 10;
console.log(arr[8]); // undefines;

19. ToPrimitive()是什么?

简单来说,就是将对象(object)转化为原始类型(undefined, null, boolean ,string, number)的方法,在计算一些强制类型转换时,都需要将对象转化为原始类型再进行计算。

ToPrimitive(obj)等价于,obj.valueOf(),如果为原始值则返回结果,否则,计算obj.toString(),如果是原始值返回,否则抛出异常。

注:此处有个例外,即Date类型的对象,它会先调用toString()方法,后调用valueOf()方法。

  • 不同对象的valueOf,toString结果不同
// Array
console.log([,2,'ss'].valueOf());  // 返回数组本身[,2,'ss'] ,仍然不是原始类型
console.log([,2,'ss'].toString()); // 返回每个元素中间以逗号隔开的字符串:,2,ss

// Object
console.log({a:11,b:'uu'}.valueOf()); // 返回对象本身{ a: 11, b: 'uu' }
console.log({a:11,b:'uu'}.toString()); // 返回字符串 [object Object]

console.log(function(){return 1}.valueOf()); // 返回[Function]代表函数本身
console.log(function(){return 1}.toString()); // 返回函数定义的字符串 :function (){return 1}

20. '+new Array(017)' 的结果?

  • 017是8进制,为15 -> + new Array(15);
  • +为强制类型转Number -> Number(new Array(15));
  • new Array(15) -> ToPrimitive([,,,,,,,,,,,,]);
  • ToPrimitive([,,,,,,,,,,,,]) -> [,,,,,,,,,,].valueOf() 结果为 [,,,,,,,,,,]
  • [,,,,,,,,,,].toString() -> ',,,,,,,,,'
  • Number(,,,,,,,,,) 为NaN

21. 不能用变量提升的思路取思考

var foo = {n: 1};
var bar = function(foo){
    console.log(foo.n)
    var foo = {n:2};
}
bar(foo);

这里有正常的传参和执行。

22. innerHTML, outerHTML, innerText, outerText的区别?

<div id="div1"><span>abcd</span></div>

//写
//div.innerHTML = "<p>大米</p>";    //div保留
//div.outerHTML = "<p>大米</p>";    //div也被取代了
//div.innerText = "米老鼠";
//console.log(div);           //div中包裹米老鼠
div.outerText = '<p>www</p>'  //将原来单元素直接变成了纯文本,包括外围<div>

23. Array方法的返回结果?

  • 返回本身:reverse(),sort(),
  • 返回一个副本:concat(),slice(),map(),filter
  • 返回其他:
    • 改变数组:
      • pop:返回arr最后一个元素
      • push:返回新的长度
      • shift:返回arr第一个元素
      • unshift:返回新的长度
      • splice:返回被删除的项目
    • 不改变:
      • join:返回字符串
      • some/every:boolean
      • findIndex:下标

24. 常用排序时间复杂度?

image

25. AMD 和 CMD 的区别有哪些?

  • AMD规范:github.com/amdjs/amdjs-api/wiki/AMD,是RequireJS在推广过程中对模块化定义的规范化产出。
  • CMD规范:github.com/seajs/seajs/issues/242CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
  • 区别
    1. 对于模块的依赖,AMD是提前执行,CMD是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
    2. CMD 推崇依赖就近,AMD 推崇依赖前置。
    3. AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。
// CMD
define(function (require, exports, module) {
    var a = require('./a')
    a.doSomething()   // 此处略去 100 行   
    var b = require('./b') // 依赖可以就近书写   
    b.doSomething()
    // ... 
})
// AMD 默认推荐的是
define(['./a', './b'], function (a, b) {
    // 依赖必须一开始就写好  
    a.doSomething()    // 此处略去 100 行   
    b.doSomething()   // ...
})
  • 世界上,有两种比较流行的 JavaScript 模块化体系,一个是 Node 实现的 CommonJS,另外一个是 AMD。很多类库都同时支持 AMD 和 CommonJS,但是不支持 CMD。或许国内有很多 CMD 模块,但并没有在世界上流行起来。

26.keydown、keypress、keyup的区别

  • keypress主要用来捕获数字(shift+数字的符号)、字母(区分大小写)、小键盘等除了F1-12、SHIFT、Alt、Ctrl、Insert、Home、PgUp、Delete、End、PgDn、ScrollLock、Pause、NumLock、{菜单键}、{开始键}和方向键外的ANSI字符。keypress事件不能对系统功能键(例如:删除,后退等,还有中文输入法)进行正常的响应。
  • keypress只能响应单个字符
  • keydown和keyup可以响应除prscrn的所有按键,可以捕捉组合键。
  • keydown和keyup不可以判断字符大小写,keypress可以。(keyCode)
  • keypress事件的which值无法区分主键盘上的数字键和附键盘数字键的,而keydown、keyup的which值对主附键盘的数字键敏感。

27. 原生实现点击按钮切换弹框的隐藏,且点击弹框以外的地方使弹框隐藏:

<!DOCTYPE html>
<html lang="en">

<head>
    <style>
        html {
            height: 100%;
        }
        
        body {
            height: 100%;
        }
        
        .div {
            height: 300px;
            width: 300px;
            background-color: rosybrown;
            transition: opacity 0.4s ease;
        }
    </style>
</head>

<body>
    <button class="btn1">toggle</button>
    <div class="div" style="opacity: 1;">
        <button class="btn2">console1</button>
        <button class="btn3">console2</button>
    </div>
    <br />
    <div class="div"></div>
    <script>
        var toggle = document.getElementsByTagName('button')[0];
        var console1 = document.getElementsByTagName('button')[1];
        var console2 = document.getElementsByTagName('button')[2];
        var div = document.getElementsByClassName('div')[0];
        var isShow = true;

        toggle.onclick = function () {
            if (isShow) {
                div.style.opacity = '0';
                isShow = false;
            } else {
                div.style.opacity = '1';
                isShow = true;
            }
        }

        div.addEventListener('click', function (e) {
            e.stopPropagation();
        }, false);

        console1.addEventListener('click', function (e) {
            console.log(1);
            // e.stopPropagation();
        }, false);

        console2.onclick = function (e) {
            console.log(2);
            // e.stopPropagation();
        }

        document.body.addEventListener('click', function (e) {
            var target = e.target;
            // 点击toggle事件也会冒泡到body上,本身toggle的效果就没了,所以事件在toggle时直接退出不执行
            if(target === toggle){
                return;
            }
            div.style.opacity = '0';
            isShow = false;
        }, false);
    </script>
</body>

</html>

思路:切换隐藏很简单,主要是点击周围的地方隐藏弹框。那么就在body上绑定一个事件,点击页面任何一个地方都隐藏,然后再去除弹框区域就行了。如何去除,就在弹框上绑定一个click事件,此事件发生后停止冒泡,那么点击弹框上任何内容的时候,事件都会冒泡到弹框上,然后弹框再停止冒泡,那么事件就不会走到body上,也就不会在弹框区域触发隐藏弹框事件。

28. js单例模式:

var Universe;

(function () {

    var instance;

    Universe = function Universe() {

        if (instance) {
            return instance;
        }

        instance = this;

        // 其它内容
        this.start_time = 0;
        this.bang = "Big";
    };
} ());

//测试代码
var a = new Universe();
var b = new Universe();
alert(a === b); // true
a.bang = "123";
alert(b.bang); // 123
var single = (function(){
    var unique;
    function getInstance(){
        if( unique === undefined ){
            unique = new Construct();
        }
        return unique;
    }
    function Construct(){
        // ... 生成单例的构造函数的代码
    }
    return {
        getInstance : getInstance
    }
})();

js实现单例模式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容

  • 前端开发面试知识点大纲: HTML&CSS: 对Web标准的理解、浏览器内核差异、兼容性、hack、CSS基本功:...
    秀才JaneBook阅读 2,324评论 0 25
  • 本文旨在加深对前端知识点的理解,资料来源于网络,由本人(博客:http://segmentfault.com/u/...
    还是那个西瓜阅读 1,323评论 0 1
  • 本文旨在加深对前端知识点的理解,资料来源于网络,由本人(博客:http://segmentfault.com/u/...
    AuthorJim阅读 437评论 0 0
  • 1.几种基本数据类型?复杂数据类型?值类型和引用数据类型?堆栈数据结构? 基本数据类型:Undefined、Nul...
    极乐君阅读 5,492评论 0 106
  • 在线阅读 http://interview.poetries.top[http://interview.poetr...
    程序员poetry阅读 114,222评论 24 450