如何取得对象非原型链上的属性?
应用后hasOwnProperty()
办法来判断属性是否属于原型链的属性:
function iterate(obj){ var res=[]; for(var key in obj){ if(obj.hasOwnProperty(key)) res.push(key+': '+obj[key]); } return res;}
一个 tcp 连贯能发几个 http 申请?
如果是 HTTP 1.0 版本协定,个别状况下,不反对长连贯,因而在每次申请发送结束之后,TCP 连贯即会断开,因而一个 TCP 发送一个 HTTP 申请,然而有一种状况能够将一条 TCP 连贯放弃在沉闷状态,那就是通过 Connection 和 Keep-Alive 首部,在申请头带上 Connection: Keep-Alive,并且能够通过 Keep-Alive 通用首部中指定的,用逗号分隔的选项调节 keep-alive 的行为,如果客户端和服务端都反对,那么其实也能够发送多条,不过此形式也有限度,能够关注《HTTP 权威指南》4.5.5 节对于 Keep-Alive 连贯的限度和规定。
而如果是 HTTP 1.1 版本协定,反对了长连贯,因而只有 TCP 连接不断开,便能够始终发送 HTTP 申请,继续一直,没有下限; 同样,如果是 HTTP 2.0 版本协定,反对多用复用,一个 TCP 连贯是能够并发多个 HTTP 申请的,同样也是反对长连贯,因而只有一直开 TCP 的连贯,HTTP 申请数也是能够没有下限地继续发送
继承
原型链继承
function Animal() { this.colors = ['black', 'white']}Animal.prototype.getColor = function() { return this.colors}function Dog() {}Dog.prototype = new Animal()let dog1 = new Dog()dog1.colors.push('brown')let dog2 = new Dog()console.log(dog2.colors) // ['black', 'white', 'brown']
原型链继承存在的问题:
- 问题1:原型中蕴含的援用类型属性将被所有实例共享;
- 问题2:子类在实例化的时候不能给父类构造函数传参;
借用构造函数实现继承
function Animal(name) { this.name = name this.getName = function() { return this.name }}function Dog(name) { Animal.call(this, name)}Dog.prototype = new Animal()
借用构造函数实现继承解决了原型链继承的 2 个问题:援用类型共享问题以及传参问题。然而因为办法必须定义在构造函数中,所以会导致每次创立子类实例都会创立一遍办法。
组合继承
组合继承联合了原型链和盗用构造函数,将两者的长处集中了起来。根本的思路是应用原型链继承原型上的属性和办法,而通过盗用构造函数继承实例属性。这样既能够把办法定义在原型上以实现重用,又能够让每个实例都有本人的属性。
function Animal(name) { this.name = name this.colors = ['black', 'white']}Animal.prototype.getName = function() { return this.name}function Dog(name, age) { Animal.call(this, name) this.age = age}Dog.prototype = new Animal()Dog.prototype.constructor = Doglet dog1 = new Dog('奶昔', 2)dog1.colors.push('brown')let dog2 = new Dog('哈赤', 1)console.log(dog2) // { name: "哈赤", colors: ["black", "white"], age: 1 }
寄生式组合继承
组合继承曾经绝对欠缺了,但还是存在问题,它的问题就是调用了 2 次父类构造函数,第一次是在 new Animal(),第二次是在 Animal.call() 这里。
所以解决方案就是不间接调用父类构造函数给子类原型赋值,而是通过创立空函数 F 获取父类原型的正本。
寄生式组合继承写法上和组合继承根本相似,区别是如下这里:
- Dog.prototype = new Animal()- Dog.prototype.constructor = Dog+ function F() {}+ F.prototype = Animal.prototype+ let f = new F()+ f.constructor = Dog+ Dog.prototype = f
略微封装下下面增加的代码后:
function object(o) { function F() {} F.prototype = o return new F()}function inheritPrototype(child, parent) { let prototype = object(parent.prototype) prototype.constructor = child child.prototype = prototype}inheritPrototype(Dog, Animal)
如果你厌弃下面的代码太多了,还能够基于组合继承的代码改成最简略的寄生式组合继承:
- Dog.prototype = new Animal()- Dog.prototype.constructor = Dog+ Dog.prototype = Object.create(Animal.prototype)+ Dog.prototype.constructor = Dog
class 实现继承
class Animal { constructor(name) { this.name = name } getName() { return this.name }}class Dog extends Animal { constructor(name, age) { super(name) this.age = age }}
对 rest 参数的了解
扩大运算符被用在函数形参上时,它还能够把一个拆散的参数序列整合成一个数组:
function mutiple(...args) { let result = 1; for (var val of args) { result *= val; } return result;}mutiple(1, 2, 3, 4) // 24
这里,传入 mutiple 的是四个拆散的参数,然而如果在 mutiple 函数里尝试输入 args 的值,会发现它是一个数组:
function mutiple(...args) { console.log(args)}mutiple(1, 2, 3, 4) // [1, 2, 3, 4]
这就是 … rest运算符的又一层威力了,它能够把函数的多个入参收敛进一个数组里。这一点常常用于获取函数的多余参数,或者像下面这样解决函数参数个数不确定的状况。
怎么加事件监听,两种
onclick 和 addEventListener
伪元素和伪类的区别和作用?
- 伪元素:在内容元素的前后插入额定的元素或款式,然而这些元素实际上并不在文档中生成。它们只在内部显示可见,但不会在文档的源代码中找到它们,因而,称为“伪”元素。例如:
p::before {content:"第一章:";}p::after {content:"Hot!";}p::first-line {background:red;}p::first-letter {font-size:30px;}
- 伪类:将非凡的成果增加到特定选择器上。它是已有元素上增加类别的,不会产生新的元素。例如:
a:hover {color: #FF00FF}p:first-child {color: red}
总结: 伪类是通过在元素选择器上加⼊伪类扭转元素状态,⽽伪元素通过对元素的操作进⾏对元素的扭转。
同步和异步的区别
- 同步指的是当一个过程在执行某个申请时,如果这个申请须要期待一段时间能力返回,那么这个过程会始终期待上来,直到音讯返回为止再持续向下执行。
- 异步指的是当一个过程在执行某个申请时,如果这个申请须要期待一段时间能力返回,这个时候过程会持续往下执行,不会阻塞期待音讯的返回,当音讯返回时零碎再告诉过程进行解决。
大数相加
题目形容:实现一个add办法实现两个大数相加
let a = "9007199254740991";let b = "1234567899999999999";function add(a ,b){ //...}
实现代码如下:
function add(a ,b){ //取两个数字的最大长度 let maxLength = Math.max(a.length, b.length); //用0去补齐长度 a = a.padStart(maxLength , 0);//"0009007199254740991" b = b.padStart(maxLength , 0);//"1234567899999999999" //定义加法过程中须要用到的变量 let t = 0; let f = 0; //"进位" let sum = ""; for(let i=maxLength-1 ; i>=0 ; i--){ t = parseInt(a[i]) + parseInt(b[i]) + f; f = Math.floor(t/10); sum = t%10 + sum; } if(f!==0){ sum = '' + f + sum; } return sum;}
对 sticky 定位的了解
sticky 英文字面意思是粘贴,所以能够把它称之为粘性定位。语法:position: sticky; 基于用户的滚动地位来定位。
粘性定位的元素是依赖于用户的滚动,在 position:relative 与 position:fixed 定位之间切换。它的行为就像 position:relative; 而当页面滚动超出指标区域时,它的体现就像 position:fixed;,它会固定在指标地位。元素定位体现为在逾越特定阈值前为绝对定位,之后为固定定位。这个特定阈值指的是 top, right, bottom 或 left 之一,换言之,指定 top, right, bottom 或 left 四个阈值其中之一,才可使粘性定位失效。否则其行为与绝对定位雷同。
对类数组对象的了解,如何转化为数组
一个领有 length 属性和若干索引属性的对象就能够被称为类数组对象,类数组对象和数组相似,然而不能调用数组的办法。常见的类数组对象有 arguments 和 DOM 办法的返回后果,函数参数也能够被看作是类数组对象,因为它含有 length属性值,代表可接管的参数个数。
常见的类数组转换为数组的办法有这样几种:
- 通过 call 调用数组的 slice 办法来实现转换
Array.prototype.slice.call(arrayLike);
- 通过 call 调用数组的 splice 办法来实现转换
Array.prototype.splice.call(arrayLike, 0);
- 通过 apply 调用数组的 concat 办法来实现转换
Array.prototype.concat.apply([], arrayLike);
- 通过 Array.from 办法来实现转换
Array.from(arrayLike);
数组的遍历办法有哪些
办法 | 是否扭转原数组 | 特点 |
---|---|---|
forEach() | 否 | 数组办法,不扭转原数组,没有返回值 |
map() | 否 | 数组办法,不扭转原数组,有返回值,可链式调用 |
filter() | 否 | 数组办法,过滤数组,返回蕴含符合条件的元素的数组,可链式调用 |
for...of | 否 | for...of遍历具备Iterator迭代器的对象的属性,返回的是数组的元素、对象的属性值,不能遍历一般的obj对象,将异步循环变成同步循环 |
every() 和 some() | 否 | 数组办法,some()只有有一个是true,便返回true;而every()只有有一个是false,便返回false. |
find() 和 findIndex() | 否 | 数组办法,find()返回的是第一个符合条件的值;findIndex()返回的是第一个返回条件的值的索引值 |
reduce() 和 reduceRight() | 否 | 数组办法,reduce()对数组正序操作;reduceRight()对数组逆序操作 |
OPTIONS申请办法及应用场景
OPTIONS是除了GET和POST之外的其中一种 HTTP申请办法。
OPTIONS办法是用于申请取得由Request-URI
标识的资源在申请/响应的通信过程中能够应用的性能选项。通过这个办法,客户端能够在采取具体资源申请之前,决定对该资源采取何种必要措施,或者理解服务器的性能。该申请办法的响应不能缓存。
OPTIONS申请办法的主要用途有两个:
- 获取服务器反对的所有HTTP申请办法;
- 用来查看拜访权限。例如:在进行 CORS 跨域资源共享时,对于简单申请,就是应用 OPTIONS 办法发送嗅探申请,以判断是否有对指定资源的拜访权限。
什么是 CSRF 攻打?
(1)概念
CSRF 攻打指的是跨站申请伪造攻打,攻击者诱导用户进入一个第三方网站,而后该网站向被攻打网站发送跨站申请。如果用户在被攻打网站中保留了登录状态,那么攻击者就能够利用这个登录状态,绕过后盾的用户验证,假冒用户向服务器执行一些操作。
CSRF 攻打的实质是利用 cookie 会在同源申请中携带发送给服务器的特点,以此来实现用户的假冒。
(2)攻打类型
常见的 CSRF 攻打有三种:
- GET 类型的 CSRF 攻打,比方在网站中的一个 img 标签里构建一个申请,当用户关上这个网站的时候就会主动发动提交。
- POST 类型的 CSRF 攻打,比方构建一个表单,而后暗藏它,当用户进入页面时,主动提交这个表单。
- 链接类型的 CSRF 攻打,比方在 a 标签的 href 属性里构建一个申请,而后诱导用户去点击。
对Flex布局的了解及其应用场景
Flex是FlexibleBox的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。任何一个容器都能够指定为Flex布局。行内元素也能够应用Flex布局。留神,设为Flex布局当前,子元素的float、clear和vertical-align属性将生效。采纳Flex布局的元素,称为Flex容器(flex container),简称"容器"。它的所有子元素主动成为容器成员,称为Flex我的项目(flex item),简称"我的项目"。容器默认存在两根轴:程度的主轴(main axis)和垂直的穿插轴(cross axis),我的项目默认沿程度主轴排列。
以下6个属性设置在容器上:
- flex-direction属性决定主轴的方向(即我的项目的排列方向)。
- flex-wrap属性定义,如果一条轴线排不下,如何换行。
- flex-flow属性是flex-direction属性和flex-wrap属性的简写模式,默认值为row nowrap。
- justify-content属性定义了我的项目在主轴上的对齐形式。
- align-items属性定义我的项目在穿插轴上如何对齐。
- align-content属性定义了多根轴线的对齐形式。如果我的项目只有一根轴线,该属性不起作用。
以下6个属性设置在我的项目上:
- order属性定义我的项目的排列程序。数值越小,排列越靠前,默认为0。
- flex-grow属性定义我的项目的放大比例,默认为0,即如果存在残余空间,也不放大。
- flex-shrink属性定义了我的项目的放大比例,默认为1,即如果空间有余,该我的项目将放大。
- flex-basis属性定义了在调配多余空间之前,我的项目占据的主轴空间。浏览器依据这个属性,计算主轴是否有多余空间。它的默认值为auto,即我的项目的原本大小。
- flex属性是flex-grow,flex-shrink和flex-basis的简写,默认值为0 1 auto。
- align-self属性容许单个我的项目有与其余我的项目不一样的对齐形式,可笼罩align-items属性。默认值为auto,示意继承父元素的align-items属性,如果没有父元素,则等同于stretch。
简略来说: flex布局是CSS3新增的一种布局形式,能够通过将一个元素的display属性值设置为flex从而使它成为一个flex容器,它的所有子元素都会成为它的我的项目。一个容器默认有两条轴:一个是程度的主轴,一个是与主轴垂直的穿插轴。能够应用flex-direction来指定主轴的方向。能够应用justify-content来指定元素在主轴上的排列形式,应用align-items来指定元素在穿插轴上的排列形式。还能够应用flex-wrap来规定当一行排列不下时的换行形式。对于容器中的我的项目,能够应用order属性来指定我的项目的排列程序,还能够应用flex-grow来指定当排列空间有残余的时候,我的项目的放大比例,还能够应用flex-shrink来指定当排列空间有余时,我的项目的放大比例。
代码输入后果
function SuperType(){ this.property = true;}SuperType.prototype.getSuperValue = function(){ return this.property;};function SubType(){ this.subproperty = false;}SubType.prototype = new SuperType();SubType.prototype.getSubValue = function (){ return this.subproperty;};var instance = new SubType();console.log(instance.getSuperValue());
输入后果:true
实际上,这段代码就是在实现原型链继承,SubType继承了SuperType,实质是重写了SubType的原型对象,代之以一个新类型的实例。SubType的原型被重写了,所以instance.constructor指向的是SuperType。具体如下:
字符串模板
function render(template, data) { const reg = /\{\{(\w+)\}\}/; // 模板字符串正则 if (reg.test(template)) { // 判断模板里是否有模板字符串 const name = reg.exec(template)[1]; // 查找以后模板里第一个模板字符串的字段 template = template.replace(reg, data[name]); // 将第一个模板字符串渲染 return render(template, data); // 递归的渲染并返回渲染后的构造 } return template; // 如果模板没有模板字符串间接返回}
测试:
let template = '我是{{name}},年龄{{age}},性别{{sex}}';let person = { name: '布兰', age: 12}render(template, person); // 我是布兰,年龄12,性别undefined
如果new一个箭头函数的会怎么样
箭头函数是ES6中的提出来的,它没有prototype,也没有本人的this指向,更不能够应用arguments参数,所以不能New一个箭头函数。
new操作符的实现步骤如下:
- 创立一个对象
- 将构造函数的作用域赋给新对象(也就是将对象的__proto__属性指向构造函数的prototype属性)
- 指向构造函数中的代码,构造函数中的this指向该对象(也就是为这个对象增加属性和办法)
- 返回新的对象
所以,下面的第二、三步,箭头函数都是没有方法执行的。
map和Object的区别
Map | Object | |
---|---|---|
意外的键 | Map默认状况不蕴含任何键,只蕴含显式插入的键。 | Object 有一个原型, 原型链上的键名有可能和本人在对象上的设置的键名产生抵触。 |
键的类型 | Map的键能够是任意值,包含函数、对象或任意根本类型。 | Object 的键必须是 String 或是Symbol。 |
键的程序 | Map 中的 key 是有序的。因而,当迭代的时候, Map 对象以插入的程序返回键值。 | Object 的键是无序的 |
Size | Map 的键值对个数能够轻易地通过size 属性获取 | Object 的键值对个数只能手动计算 |
迭代 | Map 是 iterable 的,所以能够间接被迭代。 | 迭代Object须要以某种形式获取它的键而后能力迭代。 |
性能 | 在频繁增删键值对的场景下体现更好。 | 在频繁增加和删除键值对的场景下未作出优化。 |
forEach和map办法有什么区别
这办法都是用来遍历数组的,两者区别如下:
- forEach()办法会针对每一个元素执行提供的函数,对数据的操作会扭转原数组,该办法没有返回值;
- map()办法不会扭转原数组的值,返回一个新数组,新数组中的值为原数组调用函数解决之后的值;
数组去重
ES5 实现:
function unique(arr) { var res = arr.filter(function(item, index, array) { return array.indexOf(item) === index }) return res}
ES6 实现:
var unique = arr => [...new Set(arr)]