【面筋烧烤手册】20200228
1、实现五点布局
<div class="box">
<div class="column">
<span class="pip"></span>
<span class="pip"></span>
</div>
<div class="column">
<span class="pip"></span>
</div>
<div class="column">
<span class="pip"></span>
<span class="pip"></span>
</div>
</div>
/* 重点内容 */
.box{
display: flex;
flex-direction: column;
}
.box .column {
display: flex;
justify-content: space-between;
}
.box .column:nth-of-type(2) {
justify-content: center;
}
body {
display: flex;
align-items: center;
justify-content: center;
vertical-align: center;
flex-wrap: wrap;
align-content: center;
font-family: 'Open Sans', sans-serif;
background: linear-gradient(top, #222, #333);
}
.box {
margin: 16px;
padding: 4px;
background-color: #e7e7e7;
width: 104px;
height: 104px;
object-fit: contain;
box-shadow:
inset 0 5px white,
inset 0 -5px #bbb,
inset 5px 0 #d7d7d7,
inset -5px 0 #d7d7d7;
border-radius: 10%;
}
.pip {
display: block;
width: 24px;
height: 24px;
border-radius: 50%;
margin: 4px;
background-color: #333;
box-shadow: inset 0 3px #111, inset 0 -3px #555;
}
- 或者换成row弹性,每个元素
flex-wrap: wrap; align-content: space-between;
,中间的元素align-content: center;
/* 重点内容 */
.box {
display: flex;
flex-direction: row;
}
.box .column {
display: flex;
flex-wrap: wrap;
align-content: space-between;
}
.box .column:nth-of-type(2) {
align-content: center;
}
body {
display: flex;
align-items: center;
justify-content: center;
align-content: center;
background: linear-gradient(top, #222, #333);
}
2、typeof和instanceof区别
typeof
typeof运算符返回一个用来表示表达式的数据类型的字符串。
typeof一般返回以下几个字符串:
“number”, “string”,“boolean”,“object”,“function”,“undefined”
对于Array,Null等特殊对象使用typeof一律返回object,这正是typeof的局限性。
我们可以使用typeof来判断一个变量是否存在,if(typeof a!= “undefined”), 而不要去使用if(a),因为a不存在(未声明)会报错。
instanceof
instanceof用来检测某个对象是不是另一个对象的实例。
官方的话:该运算发用来测试一个对象在其原型链中是否存在一个构造函数prototype属性
var a = new Array();
console.log(a instanceof Array); // 会返回 true
console.log(a instanceof Object); // 也会返回 true
因为Array是object 的子类
function Foo(){}
Foo.prototype = new Aoo(); // 原型继承
var foo = new Foo();
console.log(foo instanceof Foo) //true
console.log(foo instanceof Aoo) //true
instanceof不仅可以判断一层继承关系,也可以判断多层继承关系
var a = new Array();
if(a instanceof Object) // 返回true
if(window instanceof Object) // 返回false
typeof(window) //会得到object
需要注意的是,如果表达式 obj instanceof Foo 返回true,则并不意味着该表达式会永远返回ture,因为Foo.prototype属性的值有可能会改变,改变之后的值很有可能不存在于obj的原型链上,这时原表达式的值就会成为false
var a = new Array();
if(a instanceof Object) // 返回true
if(window instanceof Object) // 返回false
typeof(window) //会得到object
需要注意的是,如果表达式 obj instanceof Foo 返回true,则并不意味着该表达式会永远返回ture,因为Foo.prototype属性的值有可能会改变,改变之后的值很有可能不存在于obj的原型链上,这时原表达式的值就会成为false
3、状态码 特别是3xx
1XX 已被接受等待处理
2XX 成功
200 请求成功
204 请求成功⽆资源(OPTIONS的返回状态码)
206 partial content 范围请求 部分
3XX 重定向
301 永久性重定向 已被分配新URL(⾸部会有提示)
302 临时分配新URL 要改POST为GET
303 存在另⼀个资源
304 请访问协商缓存
307 临时重定向 不改POST
301 302 303 POST改成GET
4XX 客户端错误
400 报⽂语法错误
401 HTTP请求没通过认证
403 forbidden 被服务器拒绝
404 ⽆资源
405 禁⽌使⽤此⽅法,设置请求头OPTIONS看⽀持什么⽅法
var Access-Control-Allow-Method = xhr.getResponseHeader('Access-Control-Allow-Method')
var Access-Control-Allow-Origin = xhr.getResponseHeader('Access-Control-Allow-Origin')
5XX 服务器错误
500 执⾏请求出错
502 服务器⾃身正常 但就是访问有问题
503 暂时停机(可能超负载)⽆法处理请求
4、 组件中怎么对css进行处理的
1.提供选项
2.函数传参式
3.
4.
5、http和https
HTTPS和HTTP的主要区别
1、https协议需要到CA申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl/tls加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL/TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
5、https在握手时多个步骤,并且后面还有认证环节,比http时间花得多
7、浏览器缓存
8、跨域方法
9、JS判断为数组的方式
1.instanceof
手写instanceof
function myInstanceof(letf, right){
let proto = Object.getPrototypeOf(left),
prototype = right.prototype;
while(true){
if(!proto) return false;
if(proto === prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}
2.Object.prototype.toString.call
Object.prototype.toString.call(variable).indexOf('Array') !== -1;
//或者
Object.prototype.toString.call(variable).slice(8, -1) === 'Array';
调用toString时会将this对象的[[class]]属性值拿到,而这个属性值就是该对象的真实类型。
又因为call能够显示的修改this指针的对象,所以用call将Object内部的this对象指向我们要检测的变量自身。
从而再通过toString拿到变量的[[class]]值。
3.原型prototype + isPrototypeOf()方法
Array.prototype.isPrototypeOf(variable)
isPrototypeOf() 函数 : 用于指示对象是否存在于一个对象的原型链中。如果存在返回true,反之返回false。该方法属Object对象,由于所有的对象都继承了Object的对象实例,因此几乎所有的实例对象都可以使用该方法。
原型复习
4.variable.constructor.toString()
variable.constructor.toString().indexOf("Array") !== -1
- 但是有个问题就是 constructor如果被改了,就会不对
5.Array.isArray(variable)
10、JS将类数组转换成数组的方法
1.slice()
最经典的方法,使用Array的slice方法,此方法如果不传参数的话会返回原数组的一个拷贝,因此可以用此方法转换类数组到数组;
// 创建一个类数组对象
var alo = {0:"a", 1:"b",2:"c", length:3};
// 转化
var arr = Array.prototype.slice.call(alo);
console.log(
Array.isArray(alo) // false
)
console.log(
Array.isArray(arr) // true
)
console.log(alo); // { '0': 'a', '1': 'b', '2': 'c', length: 3 }
console.log(arr); // [ 'a', 'b', 'c' ]
2. Array.from()
ES6的方法,只要有length属性的对象,都可以应用此方法转换成数组。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
3. 扩展运算符
ES6中的扩展运算符…也能将某些数据结构转换成数组,这种数据结构必须有便利器接口。
扩展运算符背后调用的是遍历器接口(Symbol.iterator),如果一个对象没有部署这个接口,就无法转换。
var args = [...arguments];
4. $.makeArray()
jQuery的此方法可以将类数组对象转化为真正的数组
var arr = $.makeArray(arguments);
11、AMD与CMD和COMMONJS
commonjs
//定义一个module.js文件
var A = function() {
console.log('我是定义的模块');
}
//导出这个模块
//1.第一种返回方式 module.exports = A;
//2.第二种返回方式 module.exports.test = A
//3.第三种返回方式 exports.test = A;
exports.test = A;
//再写一个test.js文件,去调用刚才定义好的模块,这两个文件在同一个目录下
var module = require("./module"); //加载这个模块
//调用这个模块,不同的返回方式用不同的方式调用
//1.第一种调用方式 module();
//2.第二种调用方式 module.test();
//3.第三种调用方式 module.test();
module.test();
//接下来我们去执行这个文件,前提是你本地要安装node.js,不多说了,自己百度安装。
//首先打开cmd, cd到这两个文件所在的目录下,执行: node test.js
node test.js
//输出结果:我是定义的模块
AMD
//编写一个module1.js文件
//定义独立的模块
define({
methodA: function() {
console.log('我是module1的methodA');
},
methodB: function() {
console.log('我是module1的methodB');
}
});
//编写一个module2.js文件
//另一种定义独立模块的方式
define(function () {
return {
methodA: function() {
console.log('我是module2的methodA');
},
methodB: function() {
console.log('我是module2的methodB');
}
};
});
//编写一个module3.js文件
//定义非独立的模块(这个模块依赖其他模块)
define(['module1', 'module2'], function(m1, m2) {
return {
methodC: function() {
m1.methodA();
m2.methodB();
}
};
});
//再定义一个main.js,去加载这些个模块
require(['module3'], function(m3){
m3.methodC();
});
//我们在一个html文件中去通过RequireJS加载这个main.js
//等号右边的main指的main.js
<script data-main="main" src="require.js"></script>
//浏览器控制台输出结果
我是module1的methodA
我是module2的methodB
AMD和CMD的区别:
1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible(尽可能的懒加载,也称为延迟加载,即在需要的时候才加载)。
2. CMD 推崇依赖就近,AMD 推崇依赖前置。
虽然 AMD 也支持 CMD 的写法,同时还支持将 require 作为依赖项传递,但 RequireJS 的作者默认是最喜欢上面的写法,也是官方文档里默认的模块定义写法。看代码:
// CMD
define(function(require, exports, module) {
var a = require('./a');
a.doSomething();
// 此处略去 100 行
var b = require('./b'); // 依赖可以就近书写
b.doSomething();
// ...
})
// AMD 默认推荐的是
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
a.doSomething();
// 此处略去 100 行
b.doSomething();
//...
})
12、【手撕】手写深拷贝
/*
深度克隆
1). 大众乞丐版
问题1: 函数属性会丢失
问题2: 循环引用会出错
2). 面试基础版本
解决问题1: 函数属性还没丢失
3). 面试加强版本
解决问题2: 循环引用正常
4). 面试加强版本2(优化遍历性能)
数组: while | for | forEach() 优于 for-in | keys()&forEach()
对象: for-in 与 keys()&forEach() 差不多
*/
/*
1). 大众乞丐版
问题1: 函数属性会丢失
问题2: 循环引用会出错
*/
export function deepClone1(target) {
return JSON.parse(JSON.stringify(target))
}
/*
获取数据的类型字符串名
*/
function getType(data) {
return Object.prototype.toString.call(data).slice(8, -1)
}
/*
2). 面试基础版本
解决问题1: 函数属性还没丢失
*/
export function deepClone2(target) {
const type = getType(target)
if (type==='Object' || type==='Array') {
const cloneTarget = type === 'Array' ? [] : {}
for (const key in target) {
if (target.hasOwnProperty(key)) {
cloneTarget[key] = deepClone2(target[key])
}
}
return cloneTarget
} else {
return target
}
}
/*
3). 面试加强版本
解决问题2: 循环引用正常
*/
export function deepClone3(target, map = new Map()) {
const type = getType(target)
if (type==='Object' || type==='Array') {
let cloneTarget = map.get(target)
if (cloneTarget) {
return cloneTarget
}
cloneTarget = type==='Array' ? [] : {}
map.set(target, cloneTarget)
for (const key in target) {
if (target.hasOwnProperty(key)) {
cloneTarget[key] = deepClone3(target[key], map)
}
}
return cloneTarget
} else {
return target
}
}
/*
4). 面试加强版本2(优化遍历性能)
数组: while | for | forEach() 优于 for-in | keys()&forEach()
对象: for-in 与 keys()&forEach() 差不多
*/
export function deepClone4(target, map = new Map()) {
const type = getType(target)
if (type==='Object' || type==='Array') {
let cloneTarget = map.get(target)
if (cloneTarget) {
return cloneTarget
}
if (type==='Array') {
cloneTarget = []
map.set(target, cloneTarget)
target.forEach((item, index) => {
cloneTarget[index] = deepClone4(item, map)
})
} else {
cloneTarget = {}
map.set(target, cloneTarget)
Object.keys(target).forEach(key => {
cloneTarget[key] = deepClone4(target[key], map)
})
}
return cloneTarget
} else {
return target
}
}
13、【手撕】具有最大和的连续子数组
给定一个整数数组 nums ,给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最
少包含一个元素),返回其最大和。
示例 1: 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
- c语言实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int maxSubArray(int* nums, int numsSize) {
int sum = 0;
int max = nums[0];
for (int i = 0; i<numsSize; i++)
{
if (sum>0)
{
sum += nums[i];//只有sum大于0 加上一个数才有可能继续增大
}
if (sum <= 0)
{
sum = nums[i];//sum小于0 就让它等于第i位
}
if (sum>max)
{
max = sum;
}
}
return max;
}
int main()
{
int num[] = { -2, 1, -3, 4, -1, 2, 1, -5, 4 };
int len = sizeof(num) / sizeof(int);
int a = maxSubArray(num, len);
printf("%d\n", a);
system("pause");
return 0;
}
// 给定一个整数数组 nums ,给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最
// 少包含一个元素),返回其最大和。
// 示例 1: 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
function subArrayWithMaxSum(arr) {
let sum = 0,
max = arr[0];
arr.forEach(i => {
(sum > 0) && (sum += i);
(sum <= 0) && (sum = i);
(sum > max) && (max = sum);
console.log(" i:" + i + " sum:" + sum + " max:" + max);
});
return max;
}
/*
*以下是测试代码
*/
console.log(subArrayWithMaxSum([-2, 1, -3, 4, -1, 2, 1, -5, 4]))
// i:-2 sum:-2 max:-2
// i:1 sum:1 max:1
// i:-3 sum:-3 max:1
// i:4 sum:4 max:4
// i:-1 sum:3 max:4
// i:2 sum:5 max:5
// i:1 sum:6 max:6
// i:-5 sum:1 max:6
// i:4 sum:5 max:6
14、输出题
let obj = {
name: "bytedance",
fun: function(){
console.log(this.name,this);
}
}
let a = obj.fun;
a(); // Window 和 Window对象
obj.fun(); // bytedance 和 obj对象
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date(), i);
}, 1000);
}
console.log(new Date(), i);
// 先有个5 过一秒再 5 5 5 5 5
15.【手撕】bind call apply
// call函数实现
Function.prototype.myCall = function(context) {
// 判断调用对象
if (typeof this !== "function") {
console.error("type error");
}
// 获取参数
let args = [...arguments].slice(1),
result = null;
// 判断 context 是否传入,如果未传入则设置为 window
context = context || window;
// 将调用函数设为对象的方法
context.fn = this;
// 调用函数
result = context.fn(...args);
// 将属性删除
delete context.fn;
return result;
};
// apply 函数实现
Function.prototype.myApply = function(context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
let result = null;
// 判断 context 是否存在,如果未传入则为 window
context = context || window;
// 将函数设为对象的方法
context.fn = this;
// 调用方法
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
// 将属性删除
delete context.fn;
return result;
};
// bind 函数实现
Function.prototype.myBind = function(context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
// 获取参数
var args = [...arguments].slice(1),
fn = this;
return function Fn() {
// 根据调用方式,传入不同绑定值
return fn.apply(
this instanceof Fn ? this : context,
args.concat(...arguments)
);
};
};
回答:
call 函数的实现步骤:
- 1.判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
- 2.判断传入上下文对象是否存在,如果不存在,则设置为 window 。
- 3.处理传入的参数,截取第一个参数后的所有参数。
- 4.将函数作为上下文对象的一个属性。
- 5.使用上下文对象来调用这个方法,并保存返回结果。
- 6.删除刚才新增的属性。
- 7.返回结果。
apply 函数的实现步骤:
- 1.判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
- 2.判断传入上下文对象是否存在,如果不存在,则设置为 window 。
- 3.将函数作为上下文对象的一个属性。
- 4.判断参数值是否传入
- 4.使用上下文对象来调用这个方法,并保存返回结果。
- 5.删除刚才新增的属性
- 6.返回结果
bind 函数的实现步骤:
- 1.判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
- 2.保存当前函数的引用,获取其余传入参数值。
- 3.创建一个函数返回
- 4.函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。