wenjinhua / interviewquestions Goto Github PK
View Code? Open in Web Editor NEW前端面试题
前端面试题
闭包是有权限访问其他函数作用域内的变量的一个函数。(包含三点:a. 为什么其他非闭包的函数没有权限访问另一个函数的内部作用域、 b. 为什么闭包有这个权限、 c. 什么是函数作用域)
总结后:由于在JS中,变量的作用域属于函数作用域,在函数执行后作用域就会被清理、内存也随之回收,但是由于闭包是建立在一个函数内部的子函数,由于其可访问上级作用域的原因,即使上级函数执行完,作用域也不会随之销毁,这时的子函数——也就是闭包,便拥有了访问上级作用域中的变量的权限,即使上级函数执行完后作用域内的值也不会被销毁。
闭包就是将函数内部和函数外部连接起来的一座桥梁。由于闭包可以缓存上级作用域,那么就使得函数外部打破了“函数作用域”的束缚,可以访问函数内部的变量。
a. 一个Ajax请求的成功回调
b. 一个事件绑定的回调方法
c. 一个setTimeout的延时回调
d. 一个函数内部返回另一个匿名函数,这些都是闭包
fun.call(thisArg, args1, args2,...);//call方法接收的参数里,第一个是传入的this,剩余的是fun的函数参数
fun.apply(thisArg, argsArr);//第一个参数是传入的this,第二个是参数组成的数组
先看一个例子
var person = {
fullName: function(txt) {
console.log(txt + this.firstName + " " + this.lastName);
}
}
var person1 = {
firstName:"John",
lastName: "Doe"
}
person.fullName.call(person1, "Hello, "); // 输出"Hello, John Doe"
可知call主要做了以下三件事:
(1)改变函数的this指向
注:person.fullName()是隐式绑定了this,根据this绑定优先级(==箭头函数>关键字new>显式绑定call\apply\bind>隐式绑定obj.foo()>默认绑定foo()==)
(2)将call接收的从第二个参数开始的参数作为函数的参数
(3)不更改person(call的调用者)和person1(call中传入的this)的任何属性和方法
实现如下:
Function.prototype.myCall = function(context){
//context为传入的this,即person1
//此时的this指向myCall的调用者,即person.fullName
context.fn = this;
context.fn();
}
优化点:
a.兼容this为空时,this指向window: context = context || window
b. 兼容调用函数有返回值: var result = context.fn();
return result;
第一步的代码如下:
Function.prototype.myCall = function(context){
//context为传入的this,即person1
//此时的this指向myCall的调用者,即person.fullName
context = context || window;//优化点1
context.fn = this;
var result = context.fn();
return result;//优化点2
}
Function.prototype.myCall = function(context){
context = context || window;
context.fn = this;
//使用arguments获得myCall方法所有的参数
var args = [];
for(var i=1; i<arguments.length; i++){
args.push(arguments[i]);
}
var result = eval("context.fn(" + args + ")");
var result = context.fn();
return result;
}
==思路如下==:
a. 使用arguments可以获取所有的参数,在这儿我们利用arguments是伪数组(有length属性),来遍历从第二个参数开始的参数,并放到数组中。
b. 为什么不直接这样写呢?以下两种写法里,args都是数组,与形参的类型不匹配
var result = context.fn(args);
var result = eval("context.fn(args)");
var result = context.fn(args);
c. 既然数组的类型不匹配,那么可否把数组里边的元素拆分成形参的形式呢?将数组转化为字符串
var result = context.fn(args.toString());//形式上感觉是对了,但是args.toString()还是作为一个整体对应形参的一个参数,而没有挨个与形参对应。
d. 既然不能正确的将数组转化后的字符串与形参参数一一对应,那么可以转变一下思路,==让函数来迎合数组==,也就是利用eval方法,因为eval方法就接收一个字符串,所以正好用上了c中数组转化后的字符串。
var args_str = args.toString();
var result = eval("context.fn(args_str)");//字符串又是作为一个整体
var result = eval("context.fn(" + args + ")");//字符串的每一项都可以作为一个个体
e. d中的两种写法,同样都是传入一个字符串,但是第一种写法里字符串又只能作为一个整体,即匹配第一个形参。这是为什么呢==?==
==好像是eval中的变量需要拼接的写法,这是规定吗?==
那怎么办呢? 我们可以采用Math.random()随机生成一个id,把这个id作为函数名,当preson1中已经存在这个id时,那么就再生成一个id。
Function.prototype.myCall = function(context){
context = context || window;
//生成随机数作为函数名称
var uniqueId = "00" + Math.Random();
while(context.hasOwnProperty(uniqueId)){
uniqueId = "00" + Math.Random();
}
context[uniqueId] = this;
var args = [];
for(var i=1; i<arguments.length; i++){
args.push(arguments[i]);
}
var result = eval("context.fn(" + args + ")");
var result = context.fn();
return result;
}
//父类
function Person(name){
this.name = name;
}
Person.prototype.job = 'frontend';
Person.prototype.sayHello = function() {
console.log('Hello '+this.name);
}
var person = new Person('name111');
person.sayHello(); // Hello jia ming
function Child() {
this.name = 'child';
}
Child.prototype = new Person();//关键
var child = new Child();
console.log(child.job); // frontend
// instanceof 判断元素是否在另一个元素的原型链上
// child是Person类的实例
console.log(child instanceof Person); // true
特点:
a. 实例可继承的属性有:实例的构造函数Child的属性,父类构造函数Person的属性,父类原型Person.prototype上的属性。(新实例不会继承父类实例person的属性)
b. 所有新实例都会共享父类实例的属性。(原型上的属性是共享的)
2.构造函数继承: 用call或apply将父类构造函数引入子类函数
function Child() {
Person.call(this, 'reng');//关键
}
var child = new Child();
console.log(child.name); // reng
console.log(child instanceof Person); // false
child.sayHello(); // 报错,继承不了父类原型上的东西
特点:
a. 只继承了父类构造函数的属性,没有继承父类原型的属性。
b. 可以继承多个构造函数的属性(call可以多个),但是无法实现构造函数的复用,且臃肿。
c. 在子实例中可以向父实例传参。
// 组合继承
function Child(name) {
Person.call(this, name);//构造函数继承
}
Child.prototype = new Person();//原型继承
var child = new Child('jia');
child.sayHello(); // Hello jia
console.log(child instanceof Person); // true
特点:
a. 结合了两种模式的优点--向父类传参(call)和复用(prototype)。
b. 调用了两次父类的构造函数(耗内存)
// 先封装一个函数容器,用来承载继承的原型和输出对象
function object(obj) {
function F() {}
F.prototype = obj;
return new F();
}
var super0 = new Person();
var super1 = object(super0);
console.log(super1 instanceof Person); // true
console.log(super1.job); // frontend
特点:
a. 所有的实例都会继承原型上的属性。
Object.create()规范了原型式继承: 这个方法接收两个参数,一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。
// 传一个参数的时候
var anotherPerson = Object.create(new Person());//anotherPerson继承了Person
console.log(anotherPerson.job); // frontend
console.log(anotherPerson instanceof Person); // true
// 传两个参数的时候
var anotherPerson = Object.create(new Person(), {
name: {
value: 'come on'
}
});
anotherPerson.sayHello(); // Hello come on
function object(obj) {
function F(){}
F.prototype = obj;
return new F();
}
var sup = new Person();
// 以上是原型式继承,给原型式继承再套个壳子传递参数
function subobject(obj) {
var sub = object(obj);
sub.name = 'ming';
return sub;
}
var sup2 = subobject(sup);
// 这个函数经过声明后就成了可增添属性的对象
console.log(sup2.name); // 'ming'
console.log(sup2 instanceof Person); // true
特点:
a. 就是给原型式继承外面套个壳子。
// 寄生继承
function object(obj) {
function F(){}
F.prototype = obj;
return new F();
}
var obj = object(Person.prototype);//obj继承了Person
// 组合继承
function Sub() {
this.age = 100;
Person.call(this); // 这个继承了父类构造函数的属性
} // 解决了组合式两次调用构造函数属性的特点
// 重点(不太懂)
Sub.prototype = obj;
console.log(Sub.prototype.constructor); // Person
obj.constructor = Sub; // 一定要修复实例
console.log(Sub.prototype.constructor); // Sub
var sub1 = new Sub();
// Sub实例就继承了构造函数属性,父类实例,object的函数属性
console.log(sub1.job); // frontend
console.log(sub1 instanceof Person); // true
1. ToPrimitive(转换为原始值),ES7规范。
只针对引用类型,把引用类型转化为原始类型
/**
* @obj 需要转换的对象
* @type 期望转换为的原始数据类型,可选
*/
ToPrimitive(obj,type)
其中,对type不同值的说明:
对于toString()和valueOf()作如下说明:
var str = new String('123');
console.log(str.valueOf());//123
var num = new Number(123);
console.log(num.valueOf());//123
var date = new Date();
console.log(date.valueOf()); //1526990889729
var bool = new Boolean('123');
console.log(bool.valueOf());//true
var obj = new Object({valueOf:()=>{
return 1
}})
console.log(obj.valueOf());//1
2. Number运算符转换规则:
3. String 运算符转换规则
String(null) // 'null'
String(undefined) // 'undefined'
String(true) // 'true'
String(1) // '1'
String(-1) // '-1'
String(0) // '0'
String(-0) // '0'
String(Math.pow(1000,10)) // '1e+30'
String(Infinity) // 'Infinity'
String(-Infinity) // '-Infinity'
String({}) // '[object Object]'
String([1,[2,3]]) // '1,2,3'
String(['koala',1]) //koala,1
4. ToBoolean 运算符转换规则
除了下述 6 个值转换结果为 false,其他全部为true:
1. 什么时候自动转换为string类型?
'2' + 1 // '21'
'2' + true // "2true"
'2' + false // "2false"
'2' + undefined // "2undefined"
'2' + null // "2null"
//toString的对象
var obj2 = {
toString:function(){
return 'a'
}
}
console.log('2'+obj2)
//输出结果2a
//常规对象
var obj1 = {
a:1,
b:2
}
console.log('2'+obj1);
//输出结果 2[object Object]
//几种特殊对象
'2' + {} // "2[object Object]"
'2' + [] // "2"
'2' + function (){} // "2function (){}"
'2' + ['koala',1] // 2koala,1
对下面'2'+obj2详细举例说明如下:
(1)左边为string,ToPrimitive原始值转换后不发生变化
(2)右边转化时同样按照ToPrimitive进行原始值转换,==由于指定的type是number(type为空时,非date对象则为number)==,进行ToPrimitive转化调用obj2.valueof(),得到的不是原始值,进行第三步
(3)调用toString()return 'a'
(4)符号两边存在string,而且是+号运算符则都采用String规则转换为string类型进行拼接
(5)输出结果2a
对下面'2'+obj1详细举例说明如下:
(1)左边为string,ToPrimitive转换为原始值后不发生变化
(2)右边转化时同样按照ToPrimitive进行原始值转换,由于指定的type是number,进行ToPrimitive转化调用obj2.valueof(),得到{ a: 1, b: 2 }
(3)调用toString()return [object Object]
(4)符号两边存在string,而且是+号运算符则都采用String规则转换为string类型进行拼接
(5)输出结果2[object Object]
2. 什么时候自动转换为Number类型
true + 0 // 1
true + true // 2
true + false //1
'5' - '2' // 3
'5' * '2' // 10
true - 1 // 0
false - 1 // -1
'1' - 1 // 0
'5' * [] // 0
false / '5' // 0
'abc' - 1 // NaN
null + 1 // 1
undefined + 1 // NaN
//一元运算符(注意点)
+'abc' // NaN
-'abc' // NaN
+true // 1
-false // 0
3. 判断等号也放在Number里面特殊说明
1 == 2 //false
var obj1 = {
valueOf:function(){
return '1'
}
}
1 == obj1 //true
//obj1转为原始值,调用obj1.valueOf()
//返回原始值'1'
//'1'toNumber得到 1 然后比较 1 == 1
[] == ![] //true
//[]作为对象ToPrimitive得到 ''
//![]作为boolean转换得到0
//'' == 0
//转换为 0==0 //true
//boolean 先转成number,按照上面的规则得到1
//3 == 1 false
//0 == 0 true
3 == true // false
'0' == false //true
//'0' toNumber()得到 0
//0 == 0 true
'0' == 0 //true
4. 什么时候进行布尔转换
if ( !undefined
&& !null
&& !0
&& !NaN
&& !''
) {
console.log('true');
} // true
//下面两种情况也会转成布尔类型
expression ? true : false
!! expression
三种方式,分别为 typeof、instanceof 和Object.prototype.toString()
typeof 'seymoe' // 'string'
typeof true // 'boolean'
typeof 10 // 'number'
typeof Symbol() // 'symbol'
typeof null // 'object' 无法判定是否为 null
typeof undefined // 'undefined'
typeof {} // 'object'
typeof [] // 'object'
typeof(() => {}) // 'function'
上面代码的输出结果可以看出,
[] instanceof Array // true
({}) instanceof Object // true
(()=>{}) instanceof Function // true
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call(() => {}) // '[object Function]'
Object.prototype.toString.call('seymoe') // '[object String]'
Object.prototype.toString.call(1) // '[object Number]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(Symbol()) // '[object Symbol]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(new Date()) // '[object Date]'
Object.prototype.toString.call(Math) // '[object Math]'
Object.prototype.toString.call(new Set()) // '[object Set]'
Object.prototype.toString.call(new WeakSet()) // '[object WeakSet]'
Object.prototype.toString.call(new Map()) // '[object Map]'
Object.prototype.toString.call(new WeakMap()) // '[object WeakMap]
NaN 是一个全局对象的属性,NaN是一种特殊的Number类型。
let index = 0
const array = [1,2,3,4,5,6]
while(index<array.length){
console.log(array[index])
index++
}
//result:1 2 3 4 5 6
const array = [1,2,3,4,5,6]
for(let index = 0; index < array.length; index++) {
console.log(array[index])
}
//result:1 2 3 4 5 6
const array = [1,2,3,4,5,6]
array.forEach(function(current_value,index,value){
console.log(`At index ${index} in ${array} value is ${current_value}`)
})
/*
At index 0 in 1,2,3,4,5,6 value is 1
At index 0 in 1,2,3,4,5,6 value is 2
At index 0 in 1,2,3,4,5,6 value is 3
At index 0 in 1,2,3,4,5,6 value is 4
At index 0 in 1,2,3,4,5,6 value is 5
At index 0 in 1,2,3,4,5,6 value is 6
*/
const array = [1,2,3,4,5,6]
const square = x => Math.pow(x,2)
const squares = array.map(square)
console.log(`Original array: ${array}`)
console.log(`squared array ${squares}`)
/*
Original array: 1,2,3,4,5,6
squared array 1,4,9,16,25,36
*/
const array = [1,2,3,4,5,6]
const sum = (x,y) => x + y
const array_sum = array.reduce(sum,0)
console.log(`The sum of ${array} is ${array_sum}`)
//The sum of 1,2,3,4,5,6 is 21
const array = [1,2,3,4,5,6]
const even = x => x < 7
const even_array = array.filter(even)
console.log(`Even numbers in array ${array} is ${even_array}`)
//Even numbers in array 1,2,3,4,5,6 is 2,4,6
every
const array = [1,2,3,4,5,6]
const under_seven = x => x < 7
if(array.every(under_seven)) {
console.log('所有在该数组中的元素均小于7')
}else{
console.log('在该数组中的元素至少有一项不小于7')
}
//所有在该数组中的元素均小于7
const array = [1,2,3,4,5,6]
const over_seven= x => x > 7
if(array.every(over_seven)) {
console.log('至少有一个元素大于7')
}else{
console.log('没有元素大于7')
}
//没有元素大于7
我的csdn上有写
参考:https://segmentfault.com/a/1190000018428170
(防抖中为什么要使用闭包?)
参考: https://segmentfault.com/a/1190000015264821
方法有如下几种
下面将对如下几种数据进行判断
var bool = true
var num = 1
var str = 'abc'
var und = undefined
var nul = null
var arr = [1,2,3]
var obj = {name:'haoxl',age:18}
var fun = function(){console.log('I am a function')}
console.log(typeof bool); //boolean
console.log(typeof num);//number
console.log(typeof str);//string
console.log(typeof und);//undefined
console.log(typeof nul);//object no
console.log(typeof arr);//object no
console.log(typeof obj);//object no
console.log(typeof fun);//function
console.log(Object.prototype.toString.call(bool));//[object Boolean]
console.log(Object.prototype.toString.call(num));//[object Number]
console.log(Object.prototype.toString.call(str));//[object String]
console.log(Object.prototype.toString.call(und));//[object Undefined]
console.log(Object.prototype.toString.call(nul));//[object Null]
console.log(Object.prototype.toString.call(arr));//[object Array]
console.log(Object.prototype.toString.call(obj));//[object Object]
console.log(Object.prototype.toString.call(fun));//[object Function]
function Person(){}
function Student(){}
Student.prototype = new Person()
var haoxl = new Student()
console.log(Object.prototype.toString.call(haoxl));//[object Object]
参考:https://www.jianshu.com/p/bad857d649f2
使用方法如下:
target.addEventListener(type, listener[, options]);
target.addEventListener(type, listener[, useCapture]);
不会
[参考详细分析](https://github.com/wenjinhua/my-blog/issues/2)
由于类的方法默认不会绑定this,因此在调用的时候如果忘记绑定,this的值将会是undefined。
class Button extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
2 在调用的时候使用bind绑定this
class Button extends React.Component {
handleClick(){
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick.bind(this)}>
Click me
</button>
);
}
}
class Button extends React.Component {
handleClick(){
console.log('this is:', this);
}
render() {
return (
<button onClick={()=>this.handleClick()}>
Click me
</button>
);
}
}
class Button extends React.Component {
handleClick=()=>{
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
const EnhancedComponent = higherOrderComponent(WrappedComponent);
<DataProvider render={data => (
<h1>Hello {data.target}</h1>
)}/>
1.setState只在合成事件和钩子函数中是“异步”的,在原生事件和setTimeout 中都是同步的。
2.setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的“异步”,当然可以通过第二个参数setState(partialState, callback)中的callback拿到更新后的结果。(hooks中通过在useEffect中拿到更新后的值)
3.在“异步”中如果对同一个值进行多次setState,setState的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时setState多个不同的值,在更新时会对其进行合并批量更新。
如果DOM上绑定了过多的事件处理函数,整个页面响应以及内存占用可能都会受到影响。React为了避免这类DOM事件滥用,同时屏蔽底层不同浏览器之间的事件系统差异,实现了一个中间层——SyntheticEvent。
React并不是将click事件绑在该div的真实DOM上,而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装并交由真正的处理函数运行。
1.绑定机制
2.源码分析
浏览器事件执行的三个阶段:
(其中,stopImmediatePropagation :如果有多个相同类型事件的事件监听函数绑定到同一个元素,则当该类型的事件触发时,它们会按照被添加的顺序执行。如果其中某个监听函数执行了 event.stopImmediatePropagation()方法,则剩下的监听函数将不会被执行)
componentDidMount() {
document.body.addEventListener('click', e => {
if (e.target && e.target.matches('div.code')) {
return;
}
this.setState({ active: false, }); });
}
function createMarkup() {
return {__html: 'First · Second'};
}
function MyComponent() {
return <div dangerouslySetInnerHTML={createMarkup()} />;
}
class Input extends Component{
constructor(){
super();
this.state = {val:'100'}
}
handleChange = (e) =>{ //e是事件源
let val = e.target.value;
this.setState({val});
};
render(){
return (<div>
<input type="text" value={this.state.val} onChange={this.handleChange}/>
{this.state.val}
</div>)
}
}
class Sum extends Component{
constructor(){
super();
this.state = {result:''}
}
//通过ref设置的属性 可以通过this.refs获取到对应的dom元素
handleChange = () =>{
let result = this.refs.a.value + this.b.value;
this.setState({result});
};
render(){
return (
<div onChange={this.handleChange}>
<input type="number" ref="a"/>
{/*x代表的真实的dom,把元素挂载在了当前实例上*/}
<input type="number" ref={(x)=>{
this.b = x;
}}/>
{this.state.result}
</div>
)
}
}
参考:https://segmentfault.com/a/1190000016539430
https://segmentfault.com/a/1190000018914249 https://zhuanlan.zhihu.com/p/20346379
直接在服务端层获取数据,渲染出完成的 HTML 文件,直接返回给用户浏览器访问。
属性代理 (Props Proxy): 返回出一个组件,它基于被包裹组件进行 功能增强;
function proxyHoc(Comp) {
return class extends React.Component {
render() {
const newProps = {
name: 'tayde',
age: 1,
}
return <Comp {...this.props} {...newProps} />
}
}
}
function withOnChange(Comp) {
return class extends React.Component {
constructor(props) {
super(props)
this.state = {
name: '',
}
}
onChangeName = () => {
this.setState({
name: 'dongdong',
})
}
render() {
const newProps = {
value: this.state.name,
onChange: this.onChangeName,
}
return <Comp {...this.props} {...newProps} />
}
}
}
反向继承 (Inheritance Inversion): 返回出一个组件,继承于被包裹组件,常用于以下操作
function IIHoc(Comp) {
return class extends Comp {
render() {
return super.render();
}
};
}
function withTiming(Comp) {
return class extends Comp {
constructor(props) {
super(props);
this.start = Date.now();
this.end = 0;
}
componentDidMount() {
super.componentDidMount && super.componentDidMount();
this.end = Date.now();
console.log(`${WrappedComponent.name} 组件渲染时间为 ${this.end - this.start} ms`);
}
render() {
return super.render();
}
};
}
@[TOC]
一. 浏览器的缓存机制
二. 如何进行性能优化
三. 从输入网址到网页出现全过程
服务端渲染(SSR)
单页应用需要等JS加载完毕后在前端渲染页面,也就是说在JS加载完毕并开始执行渲染操作前的这段时间里浏览器会产生白屏。
服务端渲染(Server Side Render,简称SSR)的意义在于弥补主要内容在前端渲染的成本,减少白屏时间,提升首次有效绘制的速度。可以使用服务端渲染来获得更快的首次有效绘制。
使用import函数动态导入模块
(1)scheme - 定义因特网服务的类型。常见的协议有 http、https、ftp、file,其中最常见的类型是 http,而 https 则是进行加密的网络传输。
host - 定义域主机(http 的默认主机是 www)
domain - 定义因特网域名,比如 http://w3school.com.cn
port - 定义主机上的端口号(http 的默认端口号是 80)
path - 定义服务器上的路径(如果省略,则文档必须位于网站的根目录中)。
filename - 定义文档/资源的名称
(1) 浏览器缓存
当用户通过浏览器访问某域名时,浏览器首先会在自己的缓存中查找是否有该域名对应的IP地址(若曾经访问过该域名且没有清空缓存便存在)
(2)系统缓存
当浏览器缓存中无域名对应IP则会自动检查用户计算机系统Hosts文件DNS缓存是否有该域名对应IP. (==windows和mac下各自所在的路径是什么?==)
(3)路由器缓存
当浏览器及系统缓存中均无域名对应IP则进入路由器缓存中检查.
以上三步均为客户端的DNS缓存;
(4)ISP(互联网服务提供商)DNS缓存
当在用户客服端查找不到域名对应IP地址,则将进入ISP DNS缓存中进行查询。比如你用的是电信的网络,则会进入电信的DNS缓存服务器中进行查找;
(5)根域名服务器
当以上均未完成,则进入根服务器进行查询。全球仅有13台根域名服务器,1个主根域名服务器,其余12为辅根域名服务器。根域名收到请求后会查看区域文件记录,若无则将其管辖范围内顶级域名(如.com)服务器IP告诉本地DNS服务器;
(6)顶级域名服务器
顶级域名服务器收到请求后查看区域文件记录,若无则将其管辖范围内主域名服务器的IP地址告诉本地DNS服务器;
(7)主域名服务器
主域名服务器接受到请求后查询自己的缓存,如果没有则进入下一级域名服务器进行查找,并重复该步骤直至找到正确纪录;
(8)保存结果至缓存
本地域名服务器把返回的结果保存到缓存,以备下一次使用,同时将该结果反馈给客户端,客户端通过这个IP地址与web服务器建立链接。
http请求包括请求航、请求头、请求体
POST /chapter17/user.html HTTP/1.1
响应报文包括响应行、响应头、响应体
其中,重绘和回流
(1)当页面元素样式的改变不影响元素在文档流中的位置时(例如background-color, border-color,visibility),浏览器只会将新样式赋予元素并进行重绘操作。
(2)当改变影响文档内容或者结构,或者元素位置时,回流操作就会被触发,一般有以下几种情况:
a. DOM操作(对元素的增删改,顺序变化等);
b. 内容变化,包括表单区域内的文本改变;
c. CSS属性的更改或重新计算;
d. 增删样式表内容;
e. 修改class属性;
f. 浏览器窗口变化(滚动或缩放);
g. 伪类样式激活(:hover等)。
2.四次挥手释放连接时,等待2MSL的意义?
一. css盒模型
二. 块级格式化上下文
三. css清除浮动
四. css的伪元素和伪类
五. css的样式优先级
六. css中transition和animation的属性都有哪些?
七. css性能优化
八. 为什么CSS选择器是从右向左匹配的?
九. 隐藏页面中的某个元素的方法有哪些?
CSS盒模型本质上是一个盒子,封装周围的HTML元素.包括margin、border、padding、content
W3C盒子模型(标准盒模型):
盒子总宽度/高度 = width/height + padding + border + margin。( ==即 width/height 只是内容高度,不包含 padding 和 border 值== )
IE盒子模型(怪异盒模型):
盒子总宽度/高度 = width/height + margin = (内容区宽度/高度 + padding + border) + margin。( ==即 width/height 包含了 padding 和 border 值== )
标准:box-sizing: content-box; ( 浏览器默认设置 )
IE: box-sizing: border-box;
(1)dom.style.width/height: 只能取到行内样式的宽和高,style 标签中和 link 外链的样式取不到。
(2)dom.currentStyle.width/height: (只有IE兼容)取到的是最终渲染后的宽和高
(3)window.getComputedStyle(dom).width/height: 同(2)但是多浏览器支持,IE9 以上支持。
(4)dom.getBoundingClientRect().width/height: 也是得到渲染后的宽和高,大多浏览器支持。IE9 以上支持,除此外还可以取到相对于视窗的上下左右的距离。
(5)dom.offsetWidth/offsetHeight: 包括高度(宽度)、内边距和边框,不包括外边距。最常用,兼容性最好。
1. 定义:
它是一个独立的渲染区域,只有块级元素参与, 它规定了内部的块级元素如何布局,并且与这个区域外部毫不相干。
2. 布局规则:
3. 哪些元素会生成BFC?
4. BFC的作用及其原理
(1) 自适应两栏布局:
<style>
body {
width: 300px;
position: relative;
}
.aside {
width: 100px;
height: 150px;
float: left;
background: #f66;
}
.main {
height: 200px;
background: #fcc;
overflow: hidden;
}
</style>
<body>
<div class="aside"></div>
<div class="main"></div>
</body>
默认情况下,main会占据一整行的宽度,且在aside下方
给main设置了overflow:hidden之后,形成了bfc,由于bfc元素不会与浮动元素发生重叠,所以main就自然占据了aside剩余的行宽。从而形成了两栏自适应布局。
(2)清除浮动(详见3)
<style>
.par {
border: 5px solid #fcc;
width: 300px;
overflow: hidden;
}
.child {
border: 5px solid #f66;
width:100px;
height: 100px;
float: left;
}
</style>
<body>
<div class="par">
<div class="child"></div>
<div class="child"></div>
</div>
</body>
(3)防止垂直margin重叠
<style>
.wrap{
overflow: hidden;
}
p {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align:center;
margin: 100px;
}
</style>
<body>
<p>Haha</p>
<p>Hehe</p>
/*修改后*/
<div class='wrap'>
<p>Hehe</p>
</div>
</body>
修改后:另第二个p标签处在另外一个bfc中
在非IE浏览器(如Firefox)下,==当容器的高度为auto,且容器的内容中有浮动(float为left或right)的元素==,在这种情况下,容器的高度不能自动伸长以适应内容的高度,使得内容溢出到容器外面而影响(甚至破坏)布局的现象。这个现象叫==浮动溢出==,为了防止这个现象的出现而进行的CSS处理,就叫CSS清除浮动。
.news {
background-color: gray;
border: solid 1px black;
}
.news img {
float: left;
}
.news p {
float: right;
}
<div class="news">
<img src="news-pic.jpg" />
<p>some text</p>
</div>
(1) 使用带clear属性的空元素: 给news增加一个子元素
.clear{
clear: both
}
<div class="clear"></div>
其中,clear属性为不允许元素的某一方位(left、right、both)有浮动元素出现。
优点:简单,代码少,浏览器兼容性好。
缺点:需要添加大量无语义的html元素,代码不够优雅,后期不容易维护。
(2) 使用邻接元素处理:给浮动元素本来的非浮动兄弟节点增加clear属性(原理同1)
.news {
background-color: gray;
border: solid 1px black;
}
.news img {
float: left;
}
.news p {
float: right;
}
.content{
clear:both;
}
<div class="news">
<img src="news-pic.jpg" />
<p>some text</p>
<div class="content">***</div> /*浮动元素的非浮动兄弟节点*/
</div>
(3) 使用CSS的:after伪元素:原理也是利用clear属性,只不过是利用伪元素增加一个隐藏的节点
.news {
background-color: gray;
border: solid 1px black;
}
.news img {
float: left;
}
.news p {
float: right;
}
.clearfix:after{
content: "020";
display: block;
height: 0;//是否能省略高度的设置
clear: both;
visibility: hidden;
}
<div class="news clearfix">
<img src="news-pic.jpg" />
<p>some text</p>
</div>
(4) 使用CSS的overflow属性:利用bfc的高度计算要包含浮动元素的特性
.news{
overflow: hidden;
}
(5) 给浮动的元素的容器添加浮动:原理同(4)
但是这样会使其整体浮动,影响布局,不推荐使用。
引入css样式的方式
行内式 > 嵌入式 > 链接式 (还有导入式@import(url(demo.css)))
不同级别:
!important > 行内样式 > id选择器 > 类选择器 > 标签选择器 > 通配符 > 继承 > 浏览器默认属性
同一级别:后写的样式会覆盖先写的样式
参考:https://juejin.im/post/5b6133a351882519d346853f
<link rel="alternate stylesheet" href="mystyles.css" onload="this.rel='stylesheet'">
<link rel="preload" href="mystyles.css" as="style" onload="this.rel='stylesheet'">
举例:div > div p em(不匹配时效率高)
<div hidden></div>
position:absolute;
left: -99999px;
position: relative;
left: -99999px;
height: 0
margin-left: -99999px;
height: 0;
transform: scale(0);
height: 0;
transform: translateX(-99999px);
height: 0
transform: rotateY(90deg);
height: 0;
width: 0;
overflow: hidden;
clip-path: polygon(0 0, 0 0, 0 0, 0 0);
<div aria-hidden="true">
</div>
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.