一、this用法,相关原理
- 默认绑定
- this指向全局对象
- 隐式绑定
- this指向的是被调用方法的上一级对象,而不是最外层对象
- this是在运行时被确定,而不是在定义时被确定
- 在方法的参数中传入函数时也需要特别注意,传入函数的this也指向其方法被调用的上一级对象
- 显示绑定
- 使用bind() call() apply()方法改变this的指向
- new绑定
- 使用new构造一个对象,在构造函数中的this 根据 函数返回的数据来看
- 如果构造函数返回的是一个对象, 那么this指向就是那个返回的对象
- 如果构造函数返回的是不是一个对象,那么this还是指向函数实例,即新创建的对象
箭头函数中
原型
- js的每个函数都带有一个prototype的属性,这个属性指向一个对象,即原型对象
- 对于构造函数来说,可以通过new实例化一个对象,每一个实例化对象都有一个隐含的属性proto,这个属性也指向构造函数的原型对象。
- 原型对象就是一个公共的区域,可以被每一个实例化的对象所共用,而不会产生全局变量的污染。
- 原型的作用就是给实例化的对象提供共享的方法和属性。
- 原型链
- 当一个对象调用某个方法或者属性的时候,先在自身查找,如果找到就调用,如果没有找到就顺着proto到原型对象中查找,如果还没有就继续取原型的原型中查找,这样形成一条链叫做原型链。
- 原型链的终点是object原型,如果还没有找到就返回undefined。
综上
- 所有的实例化对象对的proto指向其构造函数的prototype
- 所有普通的对象和构造函数的prototype的proto都指向object.prototype
所有函数(包括构造函数)都是function的实例,所以proto指向function.prototype。
三、闭包
1.函数跨作用域访问变量就会形成闭包,闭包是一种作用域的体现
2.优点;变量私有化,避免全局污染
3.缺点:形成闭包的变量常驻内存,延迟或者永远不被js回收机制回收,造成比较大的内存开销,甚至容易造成内存泄露
4.应用场景:闭包随处可见,一个Ajax请求的成功回调,一个事件绑定的回调函数,一个setTimeout的延时回调,或者一个函数内部返回另一个匿名函数,这些都是闭包。简而言之,无论使用何种方式对函数类型的值进行传递,当函数在别处被调用时都有闭包的身影
5.解释:由于在js中,变量到的作用域属于函数作用域,在函数执行后作用域会被清除、内存也会随之被回收,但是由于闭包是建立在一个函数内部的子函数,由于其可访问上级作用域的原因,即使上级函数执行完,作用域也不会随之销毁,这时的子函数—-也就是闭包,便拥有了访问上级作用域中的变量权限,即使上级函数执行完后,作用域内的值也不会被销毁。四、作用域与变量声明提升
作用域:每一个变量、函数都有其作用的范围,超出范围不得使用,这个就是作用域
全局变量:在全局范围内声明的变量,如var a=1,只有赋值没有声明的值,如a=1
局部变量:写入函数的变量,叫做局部变量,作用范围仅限函数内部
变量提升:在预编译阶段,编译器会把所有定义的变量全部提升到最顶部(如;使用var声明的变量和函数声明式声明的函数会自动提升到最顶部)五、同步异步/回调/promise/async、await
1. promise原理
Promise 必须为以下三种状态之一:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。一旦Promise 被 resolve 或 reject,不能再迁移至其他任何状态(即状态 immutable)。
基本过程:初始化promise状态(pending)
- 立即执行promise中传入的fn函数,将promise内部resolve、reject函数作为参数传递给fn,按事件机制时机处理
- 执行then(…)注册回调处理数组(then方法可被同一个promise调用多次)
- promise里的关键是要保证,then方法传入的参数onfulfilled和onRejected,必须在then方法被调用的那一轮事件循环之后的新执行栈中执行
真正的链式Promise是指在当前promise达到fulfilled状态后,即开始进行下一个promise.
六、模块化commonjs,amd
七、call apply bind区别
(1)call
1、对象的继承。如下面这个例子:
function superClass () {
this.a = 1;
this.print = function () {
console.log(this.a);
}
}
function subClass () {
superClass.call(this);
this.print();
}
subClass();
// 1
subClass 通过 call 方法,继承了 superClass 的 print 方法和 a 变量。此外,subClass 还可以扩展自己的其他方法。
2、借用方法。还记得刚才的类数组么?如果它想使用 Array 原型链上的方法,可以这样:
let domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
这样,domNodes 就可以应用 Array 下的所有方法了。
call 和 apply 的主要作用,是改变对象的执行上下文,并且是立即执行的。它们在参数上的写法略有区别。
bind 也能改变对象的执行上下文,它与 call 和 apply 不同的是,返回值是一个函数,并且需要稍后再调用一下,才会执行。
(2)apply 的一些妙用
1、Math.max。用它来获取数组中最大的一项。
let max = Math.max.apply(null, array);
同理,要获取数组中最小的一项,可以这样:
let min = Math.min.apply(null, array);
2、实现两个数组合并。在 ES6 的扩展运算符出现之前,我们可以用 Array.prototype.push来实现。
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
Array.prototype.push.apply(arr1, arr2);
console.log(arr1); // [1, 2, 3, 4, 5, 6]
(3)bind的使用
bind 方法 与 apply 和 call 比较类似,也能改变函数体内的 this 指向。不同的是,bind 方法的返回值是函数,并且需要稍后调用,才会执行。而 apply 和 call 则是立即调用。
来看下面这个例子:
function add (a, b) {
return a + b;
}
function sub (a, b) {
return a - b;
}
add.bind(sub, 5, 3); // 这时,并不会返回 8
add.bind(sub, 5, 3)(); // 调用后,返回 8
如果 bind 的第一个参数是 null 或者 undefined,this 就指向全局对象 window。
八、new操作符在创建实例的时候经历了哪几个阶段
new创建了一个对象,共经历了4个阶段
- 创建了一个空对象
- 设置原型链
- 让实例化对象中的this指向对象,并执行函数体
- 判断实例化对象的返回值类型
九、父元素和子元素分别有点击事件的情况下
如果点击父元素只会触发父元素事件,不会影响到子元素;
如果点击子元素,会因为冒泡触发父元素的点击事件,可阻止默认冒泡事件。
- 取消事件冒泡方法: ``` e.stopPropagation(); //非IE浏览器 window.event.cancelBubble = true; //IE浏览器
//VUE只需将click改成click.stop
Test
- 阻止默认事件方法:
e.preventDefault(); //非IE浏览器 window.event.returnValue = false; //IE浏览器
//VUE只需将click改成click.prevent
Test
```十、从输入url到页面展示发生了什么?
- 浏览器通过DNS查找该域名的IP地址
- 浏览器根据解析得到IP地址,向web服务器发送一个HTTP请求
- 服务器收到请求并进行处理
- 服务器返回一个响应
- 浏览器对该响应进行解码,解析html为dom、解析css为css-tree、dom+css生成render-tree绘图
- 页面显示完成后,浏览器发送异步请求
- 整个过程结束之后,浏览器关闭TCP连接。