【面筋烧烤手册】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 调用,其余情况都传入指定的上下文对象。
posted @ 2021-03-01 11:43  嗨Sirius  阅读(58)  评论(0编辑  收藏  举报