共计 8595 个字符,预计需要花费 22 分钟才能阅读完成。
如何取得对象非原型链上的属性?
应用后 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 = Dog
let 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)]