js面试题

this指向:

https://www.cnblogs.com/rinack/p/5698018.html

冒泡:

1.event.stopPropagation(); 

   事件处理过程中,阻止了事件冒泡,但不会阻击默认行为(它就执行了超链接的跳转)

2.return false;

   事件处理过程中,阻止了事件冒泡,也阻止了默认行为(比如刚才它就没有执行超链接的跳转)

还有一种有冒泡有关的:

3.event.preventDefault(); 

   如果把它放在头部A标签的click事件中,点击“点击我”。

   会发现它依次弹出:我是最里层---->我是中间层---->我是最外层,但最后却没有跳转到百度

   它的作用是:事件处理过程中,不阻击事件冒泡,但阻击默认行为(它只执行所有弹框,却没有执行超链接跳转)

创建对象:

1.new 对象
    var person = new Object();
    person.name = "lisi";
    person.age = 21;
    person.family = ["lida","lier","wangwu"];
    person.say = function(){
        alert(this.name);
    }
2.直接创建
    var person ={
        name: "lisi",
        age: 21,
        family: ["lida","lier","wangwu"],
        say: function(){
            alert(this.name);
        }
    };
3.工厂模式
function createPerson(name,age,family) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.family = family;
    o.say = function(){
        alert(this.name);
    }
    return o;
}

var person1 =  createPerson("lisi",21,["lida","lier","wangwu"]);   //instanceof无法判断它是谁的实例,只能判断他是对象,构造函数都可以判断出
var person2 =  createPerson("wangwu",18,["lida","lier","lisi"]);
console.log(person1 instanceof Object);                           //true

4.构造函数
function Person(name,age,family) {
    this.name = name;
    this.age = age;
    this.family = family;
    this.say = function(){
        alert(this.name);
    }
}
var person1 = new Person("lisi",21,["lida","lier","wangwu"]);
var person2 = new Person("lisi",21,["lida","lier","lisi"]);
console.log(person1 instanceof Object); //true
console.log(person1 instanceof Person); //true
console.log(person2 instanceof Object); //true
console.log(person2 instanceof Person); //true
console.log(person1.constructor);      //constructor 属性返回对创建此对象的数组、函数的引用
5.原型模式
function Person() {
}

Person.prototype.name = "lisi";
Person.prototype.age = 21;
Person.prototype.family = ["lida","lier","wangwu"];
Person.prototype.say = function(){
    alert(this.name);
};
console.log(Person.prototype);   //Object{name: 'lisi', age: 21, family: Array[3]}

var person1 = new Person();        //创建一个实例person1
console.log(person1.name);        //lisi

var person2 = new Person();        //创建实例person2
person2.name = "wangwu";
person2.family = ["lida","lier","lisi"];
console.log(person2);            //Person {name: "wangwu", family: Array[3]}
// console.log(person2.prototype.name);         //报错
console.log(person2.age);              //21
6.混合模式
function Person(name,age,family){
    this.name = name;
    this.age = age;
    this.family = family;
}

Person.prototype = {
    constructor: Person,  //每个函数都有prototype属性,指向该函数原型对象,原型对象都有constructor属性,这是一个指向prototype属性所在函数的指针
    say: function(){
        alert(this.name);
    }
}

var person1 = new Person("lisi",21,["lida","lier","wangwu"]);
console.log(person1);
var person2 = new Person("wangwu",21,["lida","lier","lisi"]);
console.log(person2);

事件穿透:

阻止:fastclick

实现:https://www.deanhan.cn/js-through.html

是不是数组:

arr instanceof Array

arr.length

arr.constructor === Array

Object.prototype.toString.call(arr) === '[object Array]'

深拷贝浅拷贝:

浅拷贝:直接复制

深拷贝:JSON.parse() JSON.stringify()  

           或者:

function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
} 

 闭包:

使用闭包的注意点

(1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

(2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

 Ajax 请求过程:

    (1)创建`XMLHttpRequest`对象,也就是创建一个异步调用对象.

    (2)创建一个新的`HTTP`请求,并指定该`HTTP`请求的方法、`URL`及验证信息.

    (3)设置响应`HTTP`请求状态变化的函数.

    (4)发送`HTTP`请求.

    (5)获取异步调用返回的数据.

    (6)使用JavaScript和DOM实现局部刷新.

跨域:(https://segmentfault.com/a/1190000015597029

跨域原因:同源策略 

解决办法 1.jsonp  2.ifream 3.cors(请求头) 4.代理   

typeof返回值:

string || number|| undefined || boolean || function|| object

js的原始数据类型有哪些?

string , boolean , number , null , undefined

箭头函数和普通函数有什么区别?

1.箭头函数没有绑定this指针,普通函数的this指向调用函数的对象(匿名函数的this都指向全局window对象);
2.箭头函数没有构造器

数组去重:

1.创建新数组 原数组遍历放入如果有重复则不放入

function uniq(array){
    var temp = []; //一个新的临时数组
    for(var i = 0; i < array.length; i++){
        if(temp.indexOf(array[i]) == -1){
            temp.push(array[i]);
        }
    }
    return temp;
}

2.对象键值法去重

function uniq(array){
    var temp = {}, r = [], len = array.length, val, type;
    for (var i = 0; i < len; i++) {
        val = array[i];
        type = typeof val;
        if (!temp[val]) {
            temp[val] = [type];
            r.push(val);
        } else if (temp[val].indexOf(type) < 0) {
            temp[val].push(type);
            r.push(val);
        }
    }
    return r;
}

3. 排序后相邻去除法


function uniq(array){
    array.sort();
    var temp=[array[0]];
    for(var i = 1; i < array.length; i++){
        if( array[i] !== temp[temp.length-1]){
            temp.push(array[i]);
        }
    }
    return temp;
}

4.数组下标法

function uniq(array){
    var temp = [];
    for(var i = 0; i < array.length; i++) {
        //如果当前数组的第i项在当前数组中第一次出现的位置是i,才存入数组;否则代表是重复的
        if(array.indexOf(array[i]) == i){
            temp.push(array[i])
        }
    }
    return temp;
}

5

function uniq(array){
    var temp = [];
    var index = [];
    var l = array.length;
    for(var i = 0; i < l; i++) {
        for(var j = i + 1; j < l; j++){
            if (array[i] === array[j]){
                i++;
                j = i;
            }
        }
        temp.push(array[i]);
        index.push(i);
    }
    console.log(index);
    return temp;
}

6.new set()

var items = new Set([1, 2, 4, 4, 5]);
var array = Array.from(items);
console.log(array)  // (4) [1, 2, 4, 5]

检测一个对象是否有prop属性,没有就抛出异常,有的话返回true,并删掉该属性:

var o = {
      age:10,
      prop:"prop"
    }
    function hasProperty(pro,obj){
      if(obj.hasOwnProperty(pro)){
        delete obj.prop;
      }else{
        throw new Error("没有该属性");
      }
    }
    hasProperty("prop",o)
    console.log(o)

attr()和prop()的区别?

attr是自己定义属性 prop 是修改元素固有属性(checked、disabled ...)

touch和click有何区别?

touch有延迟等待双击事件

Vue的双向绑定原理是什么?

defineProperty

webpack原理是什么?

合并脚本 (require)

get 和 post区别:

(1)post更安全(不会作为url的一部分,不会被缓存、保存在服务器日志、以及浏览器浏览记录中) 
(2)post发送的数据更大(get有url长度限制) 
(3)post能发送更多的数据类型(get只能发送ASCII字符) 
(4)post比get慢 
(5)post用于修改和写入数据,get一般用于搜索排序和筛选之类的操作(淘宝,支付宝的搜索查询都是get提交),目的是资源的获取,读取数据 

但是在服务器端 get请求更安全,不会修改数据

为什么get比post更快

1.post请求包含更多的请求头 
因为post需要在请求的body部分包含数据,所以会多了几个数据描述部分的首部字段(如:content-type),这其实是微乎其微的。

2.最重要的一条,post在真正接收数据之前会先将请求头发送给服务器进行确认,然后才真正发送数据 
post请求的过程: 
(1)浏览器请求tcp连接(第一次握手) 
(2)服务器答应进行tcp连接(第二次握手) 
(3)浏览器确认,并发送post请求头(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送) 
(4)服务器返回100 Continue响应 
(5)浏览器发送数据 
(6)服务器返回200 OK响应 
get请求的过程: 
(1)浏览器请求tcp连接(第一次握手) 
(2)服务器答应进行tcp连接(第二次握手) 
(3)浏览器确认,并发送get请求头和数据(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送) 
(4)服务器返回200 OK响应 

也就是说,目测get的总耗是post的2/3左右,这个口说无凭,网上已经有网友进行过测试。

3.get会将数据缓存起来,而post不会 
可以做个简短的测试,使用ajax采用get方式请求静态数据(比如html页面,图片)的时候,如果两次传输的数据相同,第二次以后消耗的时间将会在10ms以内(chrome测试),而post每次消耗的时间都差不多。经测试,chrome和firefox下如果检测到get请求的是静态资源,则会缓存,如果是数据,则不会缓存,但是IE什么都会缓存起来,当然,应该没有人用post去获取静态数据吧,反正我是没见过。

4.post不能进行管道化传输 
http权威指南中是这样说的:http的一次会话需要先建立tcp连接(大部分是tcp,但是其他安全协议也是可以的),然后才能通信,如果 每次连接都只进行一次http会话,那这个连接过程占的比例太大了!于是出现了持久连接:在http/1.0+中是connection首部中添加keep-alive值,在http/1.1中是在connection首部中添加persistent值,当然两者不仅仅是命名上的差别,http/1.1中,持久连接是默认的,除非显示在connection中添加close,否则持久连接不会关闭,而http/1.0+中则恰好相反,除非显示在connection首部中添加keep-alive,否则在接收数据包后连接就断开了。 
出现了持久连接还不够,在http/1.1中,还有一种称为管道通信的方式进行速度优化:把需要发送到服务器上的所有请求放到输出队列中,在第一个请求发送出去后,不等到收到服务器的应答,第二个请求紧接着就发送出去,但是这样的方式有一个问题:不安全,如果一个管道中有10个连接,在发送出9个后,突然服务器告诉你,连接关闭了,此时客户端即使收到了前9个请求的答复,也会将这9个请求的内容清空,也就是说,白忙活了……此时,客户端的这9个请求需要重新发送。这对于幂等请求还好(比如get,多发送几次都没关系,每次都是相同的结果),如果是post这样的非幂等请求(比如支付的时候,多发送几次就惨了),肯定是行不通的。 
所以,post请求不能通过管道的方式进行通信!很有可能,post请求需要重新建立连接,这个过程不跟完全没优化的时候一样了么?所以,在可以使用get请求通信的时候,不要使用post请求,这样用户体验会更好,当然,如果有安全性要求的话,post会更好。管道化传输在浏览器端的实现还需考证,貌似默认情况下大部分浏览器(除了opera)是不进行管道化传输的,除非手动开启!

get 传参长度原因是由于浏览器本身原因

完整的HTTP请求过程

https://blog.youkuaiyun.com/u014600626/article/details/78720763

1.域名解析(DNS解析)

2.发起TCP的3次握手

3.建立TCP连接后发起http请求

4.服务器端响应http请求,浏览器得到html代码

5.浏览器解析html代码,并请求html代码中的资源

6.浏览器对页面进行渲染呈现给用户

手写promise

function Pwromise(exector) {
				// 这里我们将value 成功时候的值 reason失败时候的值放入属性中
				let self = this;
				// 这里我们加入一个状态标识
				this.status = 'pending';
				this.value = undefined;
				this.reason = undefined;
				// 成功执行
				function resolve(value) {
					// 判断是否处于pending状态
					if(self.status === 'pending') {
						self.value = value;
						// 这里我们执行之后需要更改状态
						self.status = 'resolved';
					}
				}
				// 失败执行
				function reject(reason) {
					// 判断是否处于pending状态
					if(self.status === 'pending') {
						self.reason = reason;
						// 这里我们执行之后需要更改状态
						self.status = 'rejected';
					}
				}
				// 这里对异常进行处理
				try {
					exector(resolve, reject);
				} catch(e) {
					reject(e)
				}
			}
			Pwromise.prototype.then = function(resolve, reject) {
				// 获取下this
				let self = this;
				if(this.status === 'resolved') {
					resolve(self.value);
				}

				if(this.status === 'rejected') {
					reject(self.reason);
				}
			}
			function test() {
				return new Pwromise((resolve, reject) => {
					reject("haha");
				}).then(data => {
					console.log(data)
				}, err => {
					console.log(err + '666');
				})
			}
			test()

手写订阅者模式(简单版)

function Public() {
				//存放订阅者信息
				this.subscribers = [];
				//添加订阅者
				this.addSubscriber = function(subscriber) {
					//保证一个订阅者只能订阅一次
					let isExist = this.subscribers.some(function(item) {
						return item == subscriber;
					})
					if(!isExist) {
						this.subscribers.push(subscriber);
					}
					return this;
				}
				//发布消息
				this.deliver = function(data) {
					this.subscribers.forEach(function(fn) {
						fn(data)
					})
					return this;
				}
			}
			let a = function(data) {
				console.log(`订阅者a收到订阅信息:${data}`)
			}
			let publisher = new Public();
			publisher.addSubscriber(a);
			publisher.deliver('这是公众号推送的第1条新信息!'); 
			console.log(publisher)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值