apply、call、bind三者的区别在于:
实现bind的步骤,我们可以分解成为三部分:
// 方式一:只在bind中传递函数参数
fn.bind(obj,1,2)()// 方式二:在bind中传递函数参数,也在返回函数中传递参数
fn.bind(obj,1)(2)
整体实现代码如下:
Function.prototype.myBind = function (context) {// 判断调用对象是否为函数if (typeof this !== "function") {throw new TypeError("Error");}// 获取参数const args = [...arguments].slice(1),fn = this;return function Fn() {// 根据调用方式,传入不同绑定值return fn.apply(this instanceof Fn ? new fn(...arguments) : context, args.concat(...arguments)); }
}
AJAX 全称(Async Javascript and XML)
即异步的 JavaScript 和 XML,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页
Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面
流程图如下
下面举个例子:领导想找小李汇报一下工作,就委托秘书去叫小李,自己就接着做其他事情,直到秘书告诉他小李已经到了,最后小李跟领导汇报工作
Ajax请求数据流程与“领导想找小李汇报一下工作”类似,上述秘书就相当于XMLHttpRequest对象,领导相当于浏览器,响应数据相当于小李.浏览器可以发送HTTP请求后,接着做其他事情,等收到XHR返回来的数据再进行操作
实现 Ajax 异步交互需要服务器逻辑进行配合,需要完成以下步骤:
继承(inheritance)是面向对象软件技术当中的一个概念。如果一个类别B“继承自”另一个类别A,就把这个B称为“A的子类”,而把A称为“B的父类别”也可以称“A是B的超类”。继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码。在子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。虽然JavaScript并不是真正的面向对象语言,但它天生的灵活性,使应用场景更加丰富。
JavaScripy常见的继承方式:
继承这个概念在面向对象编程思想里面十分重要,也是面试必考的考点之一。javascript的继承主要是依托其原型与原型链的概念来实现的。
ECMAscript将原型链作为实现继承的主要方法。
ES6提供了Class关键字来实现类的定义,Class 可以通过extends关键字实现继承,让子类继承父类的属性和方法。
ES5的四种常用的实现方式:原型链继承、构造函数继承、组合式继承、寄生式组合继承。
原型
JavaScript 常被描述为一种基于原型的语言——每个对象拥有一个原型对象
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。准确地说,这些属性和方法定义在Object的构造器函数(constructor functions)之上的prototype属性上,而非实例对象本身
下面举个例子:
函数可以有属性。 每个函数都有一个特殊的属性叫作原型prototype
function doSomething(){}
console.log( doSomething.prototype );
控制台输出
{constructor: ƒ doSomething(),__proto__: {constructor: ƒ Object(),hasOwnProperty: ƒ hasOwnProperty(),isPrototypeOf: ƒ isPrototypeOf(),propertyIsEnumerable: ƒ propertyIsEnumerable(),toLocaleString: ƒ toLocaleString(),toString: ƒ toString(),valueOf: ƒ valueOf()}
}
上面这个对象,就是大家常说的原型对象。可以看到,原型对象有一个自有属性constructor,这个属性指向该函数,如下图关系展示:
原型链
原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。在对象实例和它的构造器之间建立一个链接(它是__proto__属性,是从构造函数的prototype属性派生的),之后通过上溯原型链,在构造器中找到这些属性和方法
下面举个例子:
function Person(name) {this.name = name;this.age = 18;this.sayName = function() {console.log(this.name);}
}
// 第二步 创建实例
var person = new Person('person')
根据代码,我们可以得到下图
下面分析一下:
总结
下面首先要看几个概念:
__proto__作为不同对象之间的桥梁,用来指向创建它的构造函数的原型对象的
每个对象的__proto__都是指向它的构造函数的原型对象prototype的
1person1.__proto__ === Person.prototype
构造函数是一个函数对象,是通过 Function 构造器产生的
1Person.__proto__ === Function.prototype
原型对象本身是一个普通对象,而普通对象的构造函数都是Object
1Person.prototype.__proto__ === Object.prototype
刚刚上面说了,所有的构造器都是函数对象,函数对象都是 Function 构造产生的
1Object.__proto__ === Function.prototype
Object 的原型对象也有__proto__属性指向null,null是原型链的顶端
1Object.prototype.__proto__ === null
下面作出总结:
先看看在那些场景会导致重复请求:
1.手速快,不小心双击操作按钮。
2.很小心的点击了一次按钮,因为请求响应比较慢,页面没有任何提示,怀疑上次点击没生效,再次点击操作按钮。
3.很小心的点击了一次按钮,因为请求响应比较慢,页面没有任何提示,刷新页面,再次点击操作按钮。
前端方案
我们可以对症下药:
1.控制按钮,在短时间内被多次点击,第一次以后的点击无效。
2.控制按钮,在点击按钮触发的请求响应之前,再次点击无效。
3.配置特殊的URL,然后控制这些URL请求的最小时间间隔。如果再次请求跟前一次请求间隔很小,弹窗二次提示,是否继续操作。
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
会继续执行。
虽然Promise是开发过程中使用非常频繁的一个技术点,但是它的一些细节可能很多人都没有去关注过。我们都知道.then, .catch, .finally都可以链式调用,其本质上是因为返回了一个新的Promise实例。
catch的语法形式如下:
1p.catch(onRejected);
.catch只会处理rejected的情况,并且也会返回一个新的Promise实例。
.catch(onRejected)与then(undefined, onRejected)在表现上是一致的。
事实上,catch(onRejected)从内部调用了then(undefined, onRejected)。
CORS、Nginx代理跨域、Node中间件代理跨域、WebSocket、postMessage、JSONP
具体描述请点击此链接
懒加载是一种网页性能优化的方式,它能极大的提升用户体验。就比如说图片,图片一直是影响网页性能的主要元凶,现在一张图片超过几兆已经是很经常的事了。如果每次进入页面就请求所有的图片资源,那么可能等图片加载出来用户也早就走了。所以,我们需要懒加载,进入页面的时候,只请求可视区域的图片资源。
总结出来就两个点:
全部加载的话会影响用户体验
浪费用户的流量,有些用户并不想全部看完,全部加载会耗费大量流量。
html 实现:实现方式是给 img 标签加上 loading=“lazy”
js 实现:原理通过js监听页面的滚动也能实现。