JS
js对象是通过引用来传递的,我们创建的每个递归函数是在一个函数通过名字调用自身的情况下造成的
function factorial (num) {
if (num <= 1) {
return 1;
} else {
return num * factorial(num - 1);
}
}
call apply bind继承
第二个参数不一样,call()第二个参数是数,apply()第二个参数是数组
模块化:公共&私有方法(闭包)
块级作用域(通常称为私有作用域)的匿名函数的语法:
function关键字会被当做一个函数声明的开始,函数声明后面不能跟圆括号。函数表达式的后面可以跟圆括号,用一个圆括号将function包裹起来,转换成函数表达式
(function () {
})();
1. 静态方法和属性
静态方法即只允许父类调用,其他的实例均无法访问和调用的方法和属性。
var user = function(age){
// 变量 age 是 user 对象的私有属性
var age = age;
}
// user.age 是 user 对象的静态方法
user.age = function(){
return this.age;
}
// 当我们将user对象实例化的时候, zhangsan 无法使用 user对象中的 age 方法
// 实例中没有继承 user 对象的 age 方法
var zhangsan = new user(18);
2. 公共方法
即 依此父类生成的所有实例均可以使用的方法
var user = function(name, age){
// 公共变量
this.name = name;
this.age = age;
}
user.prototype = {
getInfo: function(){
return "他的名字叫:" +this.name+ ",他的年龄是:" +this.age;
}
}
// zhangsan 可以访问到name, age, getInfo
var zhangsan = new user('张三', 18)
3. 私有方法
即只有父类可以访问的方法和属性,他和静态方法一致,只是表现形式不一样,构造器中的 var 变量和参数都是私有方法。
var user = function(age){
// age 是 user 对象的私有属性
var age = age;
// getAge 是 user 对象的私有方法
function getAge() {
return age;
}
}
var zhangsan = new user(18);
// 实例中不包含 user 对象的 age 属性和 getAge 方法
zhangsan.age // undefined
zhangsan.getAge // undefined
4. 特权方法
可以访问私有方法,并且在公共域中可见的方法称为特权方法。特权方法不可被修改,只能替换或者删除。
var user = function(age){
// age 是 user 对象的私有属性
var age = age;
// 创建一个特权方法用来获取 user 对象下的私有属性 age
this.getInfo = function(){
return age;
}
}
var zhangsan = new user(18);
zhangsan.getInfo() == 18
Object.defineProperty():数据属性、访问器属性
数据属性
数据属性包含四个属性描述符:
[[Configurable]] : 表示能否通过delete删除属性从而重新定义属性,能否修改属性特性,能否把属性修改为访问器属性。通过以上方式添加的对象属性,默认为true。当configurable设为false时,1、不可以通过delete去删除该属性从而重新定义属性;2、不可以转化为访问器属性;3、configurable和enumerable不可被修改;4、writable可单向修改为false,但不可以由false改为true;5、value是否可修改根据writable而定。
[[Enumerable]] : 表示能否通过for-in 循环访问属性。通过以上方式添加的对象属性,默认为true。
[[Writable]] : 表示能否修改属性的值。通过以上方式添加的对象属性,默认为true。
[[Value]] : 包含这个属性的数据值,可读取写入。通过以上方式添加的对象属性,默认为undefined。
访问器属性
访问器属性包含四个属性描述符:
[[Configurable]] : 表示能否通过delete删除属性从而重新定义属性,能否修改属性特性,能否把属性修改为数据属性。直接在对象上定义的属性,默认为true。
[[Enumerable]] : 表示能否通过for-in 循环访问属性。直接在对象上定义的属性,默认为true。
[[Get]] : 读取属性时调用的函数,默认为undefined。
[[Set]] : 写入属性时调用的函数,默认为undefined。
链式调用
链式调用这种风格有助于简化代码的编写工作,让代码更加简洁、易读,同时也避免多次重复使用一个对象变量
词法分析
当函数调用的一瞬间,会先形成一个激活对象:Active Object(AO),并会分析一下3个方面
01:函数参数,如果有,则会将此参数赋值给AO,且值为undefined。如果没有,则不做任何操作
02:函数局部变量,如果AO上有同名的值,则不做任何操作,如果没有,则将此变量赋值给AO,并且值为undefined
03:函数声明,如果AO上有,则会将AO上的对象覆盖,如果没有,则不做任何操作。
案例01:var age=18; //(第二步:发现没有函数参数,不做任何操作)
function foo(){
//(第三步,发现下面有局部变量age的声明,此时的AO的变量名字是age,且值为undefined()
//即:age=undefined。所以这时的age的值是undefined 在这之前是还未执行到age=22的。)
console.log(age);
var age=22; //如果没有这个变量声明,打印的值应该是18
console.log(age);
}
foo(); //调用函数,(第一步:瞬间形成了一个AO对象)
//调用函数得到的值
--> undefined
-->22
词法分析例子02:
var age=18;
function foo(){
console.log(age);
var age=22;
console.log(age);
function age(){ //#发现age这个函数名也是变量,将OA上的变量给替换了,那么函数在执行的时候,
//去OA上找,发现OA是个函数,然后执行到age=22的时候,age才被重新赋值
console.log("呵呵");
}
console.log(age);
}
foo(); //调用执行函数
结果:
--> ƒunction age(){
console.log("呵呵");
}
--> 22
--> 22
1、分析参数,有一个参数,形成一个 AO.age=undefine;
2、分析变量声明,有一个 var age, 发现 AO 上面已经有一个 AO.age,因此不做任何处理
3、分析函数声明,有一个 function age(){…} 声明, 则把原有的 age 覆盖成 AO.age=function(){…};
最终,AO上的属性只有一个age,并且值为一个函数声明
执行过程:
注意:执行过程中所有的值都是从AO对象上去寻找
1、执行第一个 console.log(age) 时,此时的 AO.age 是一个函数,所以第一个输出的一个函数
2、这句 var age=22; 是对 AO.age 的属性赋值, 此时AO.age=22 ,所以在第二个输出的是 22
3、同理第三个输出的还是22, 因为中间再没有改变age值的语句了
new、new 生成一个对象的过程
new关键字进行了如下的操作(为了便于描述,obj用来表示创建的空对象、用constrc来表示构造函数):
1创建一个新对象2将构造函数的作用域赋给新对象(因此this就指向了这个新对象)3执行构造函数中的代码(为这个新对象添加属性)4返回新对象
1.创建一个空对象obj({});
将obj的[[prototype]]属性指向构造函数constrc的原型(即obj.[[prototype]] = constrc.prototype)。
2.将构造函数constrc内部的this绑定到新建的对象obj,执行constrc(也就是跟调用普通函数一样,只是此时函数的this为新创建的对象obj而已,就好像执行obj.constrc()一样);
3.若构造函数没有返回非原始值(即不是引用类型的值),则返回该新建的对象obj(默认会添加return this)。否则,返回引用类型的值。
4.这里补充说明一下:[[prototype]]属性是隐藏的,不过目前大部分新浏览器实现方式是使用__proto__来表示。构造函数的prototype属性我们是可以显式访问的。
作用域链
- 每当执行一个函数,就会进入一个 新的作用域 下;
- 函数在执行的过程中,先从自己 内部 找变量;
- 如果找不到,再从 创建当前函数所在的作用域 去找, 依次往上;
- 注意找的是变量的 当前 的状态。
IIFE( 立即执行函数表达式)
是一个在定义时就会立即执行的 JavaScript 函数。这是一个被称为 自执行匿名函数 的设计模式,主要包含两部分。第一部分是包围在圆括号运算符 () 里的一个匿名函数,这个匿名函数拥有 独立的词法作用域。第二部分再一次使用 () 创建了一个立即执行函数表达式,JavaScript 引擎到此将 直接执行函数
(function () {
var name = 'yuuko';
})();
console.log(name); // undefined
将 IIFE 分配给一个变量,不是存储 IIFE 本身,而是存储 IIFE 执行后返回的结果
var result = (function () {
var name = 'yuuko';
return name;
})(); // IIFE 执行后返回的结果
console.log(result); // "yuuko"
作用:不仅避免了外界访问此 IIFE 中的变量,而且又不会污染全局作用域。
调用栈call stack
调用栈是解释器(就像浏览器中的javascript解释器)追踪函数执行流 的一种机制。当执行环境中调用了多个函数时,通过这种机制,我们能够追踪到哪个函数正在执行,执行的函数体中又调用了哪个函数。
- 每调用一个函数,解释器就会把该函数 添加 进调用栈并开始 执行。
- 正在调用栈中执行的函数还调用了其它函数,那么新函数也将会被添加进调用栈,一旦这个函数被调用,便会立即执行。
- 当前函数执行完毕后,解释器将其 清出 调用栈,继续执行当前执行环境下的剩余的代码。当分配的调用栈空间被占满时,会引发“堆栈溢出”。
数据类型
- 简单数据类型 (Number,String,Boolean,Undefined,Null)
- 复杂数据类型/引用数据类型 (object)
1、原型/原型链/构造函数/实例/继承
2、有几种方式可以实现继承
原型链继承 、构造继承、实例基础、拷贝继承、组合基础、寄生组合继承、Class继承(es6新增)
3、用原型实现继承有什么缺点,怎么解决
4、arguments
5、数据类型判断
6、作用域链、闭包、作用域
7、Ajax的原生写法
8、对象深拷贝、浅拷贝
9、图片懒加载、预加载
10、实现页面加载进度条
11、this关键字
12、函数式编程
13、手动实现parseInt
14、为什么会有同源策略
15、怎么判断两个对象是否相等
16、事件模型
- 事件委托、代理
- 如何让事件先冒泡后捕获
17、window的onload事件和domcontentloaded
18、for…in迭代和for…of有什么区别
19、函数柯里化
20、call apply区别,原生实现bind
共同点 : 都可以改变this指向
不同点:
call 和 apply 会调用函数, 并且改变函数内部this指向.
all 和 apply传递的参数不一样,call传递参数使用逗号隔开,apply使用数组传递
bind 不会调用函数, 可以改变函数内部this指向.
应用场景: call 经常做继承。 apply经常跟数组有关系, 比如借助于数学对象实现数组最大值最小值。 bind 不调用函数,但是还想改变this指向. 比如改变定时器内部的this指向.
21、async/await
22、立即执行函数和使用场景
23、设计模式(要求说出如何实现,应用,优缺点)/单例模式实现
24、iframe的缺点有哪些
25、数组问题
-
数组去重
-
数组常用方法
-
查找数组重复项
-
扁平化数组
-
按数组中各项和特定值差值排序
26、BOM属性对象方法
27、服务端渲染
28、垃圾回收机制和内存 泄露
29、eventloop
- 进程和线程
- 任务队列
30、如何快速让字符串变成已千为精度的数字
31、数组方法、数组乱序、数组扁平化、 事件委托、事件监听、事件模型、typescript、promise使用及实现、promise并行执行和顺序执行
JS里面重要的概念
函数的内部属性:在函数内部有两个特殊的 对象 arguments 和this. arguments是一个类数组对象,包含着函数中的所有参数,主要用途是保存函数参数,有一个callee的属性,这个属性是一个指针,指向拥有这个arguments对象的函数。
**函数是对象,函数名是指针。**函数实际上是对象。每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没有什么不同。换句话说,一个函数可能有多个名字。
作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量。
闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的常见方式就是在一个函数中创建另一个函数。
Object是在javascript中一个被我们经常使用的类型,而且JS中的所有对象都是继承自Object对象的。
apply() , call()可以用来扩充函数赖以运行的作用域。
构造函数本身就是一个函数,只不过该函数是出于创建新对象的目的而定义的。
bind()是es5时定义的一个新方法,它会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。
ES6
1、声明 let、const
let声明的变量只在所处于的块级有效、使用let关键字声明的变量才具有块级作用域,使用var声明的变量不具备块级作用域特性。使用 var 声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象。使用 let 声明的变量,其作用域为该语句所在的代码块内,不存在变量提升。使用 const 声明的是常量,在后面出现的代码中不能再修改该常量的值
2、解构赋值
ES6中允许从数组中提取值,按照对应位置,对变量赋值,对象也可以实现解构,如果结构不成功,变量跟数值个数不匹配的时候,变量的值为undefined
2、箭头函数
() => {} ():代表是函数; =>:必须要的符号,指向哪一个代码块;{}:函数体。定义箭头函数中的作用域的this指向谁,它就指向谁。
3、剩余参数
3、声明类与继承:class、extend
4、Promise的使用与实现
5、generator(异步编程、yield、next()、await 、async)
6、箭头函数this指向问题、拓展运算符
7、map和set有没有用过,如何实现一个数组去重,map数据结构有什么优点?
8、ES6怎么编译成ES5, css-loader原理,过程
9、ES6转成ES5的常见例子
使用es5实现es6的class
10、箭头函数和function的区别
箭头函数根本就没有绑定自己的this,在箭头函数中调用this时,仅仅是简单的沿着作用域链向上寻找,找到一个最近的this拿来使用。
html
1、语义化
见名知意。1.代码可读性提高,便于其他人快速的能读懂代码。2.能呈现清晰的架构。3.能够提高团队效率。4.有利于SEO. 爬虫依赖于标签来确定上下文和各个关键字的比重。SEO(Search Engine Optimization):汉译为搜索引擎优化
2、新标签新特性
article: 定义页面独立的内容区域;aside 定义页面的侧边栏区域; details: 用于描述文档或文档某个部分的细节; figure: 规定独立的流内容; footer: 定义section 或者documnet的页脚 ; header: 文档的头部区域;nav: 定义导航链接;section: 定义文档中的节或者区段;
3、input和textarea的区别
input 是单行文本框,不会换行。textarea 是多行文本框,可容纳无限的文本,没有value属性,一般通过CSS height 和 width属性改变文本框的大小。
4、用一个div模拟textarea的实现
<div contenteditable="true"></div>
5、移动设备忽略将页面中的数字识别为电话号码的方法
<meta name="format-detection" content="telephone=no"/>
5、websockets
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
https://www.runoob.com/html/html5-websocket.html
css
:after 是css 3里面的一个选择器。::after是一个伪元素
1、盒模型:
元素内容,内边距,边框,外边距。
相邻块元素垂直外边距的合并(塌陷): 尽量只给一个盒子添加外边距
嵌套块元素垂直外边距的合并(塌陷):可以为父元素定义 上边框/ 上内边距/ overflow:hidden
一个块级盒子实现水平居中必须:盒子必须指定了宽度(width)然后就给左右的外边距都设置为auto
盒子内文字居中:text-align: center;
盒子模型布局稳定性:width > padding > margin margin会有外边距合并的问题和在IE6下加倍的问题,padding 会撑大盒子,需要计算。
2、flex
https://www.runoob.com/css3/css3-flexbox.html
3、css单位
4、css选择器
后代选择器、子元素选择器、并集选择器(重点)、交集选择器、 链接伪类选择器(重点)、
5、bfc 清除浮动
6、层叠上下文
7、常见页面布局
8、响应式布局
9、css预处理,后处理
10、css3新特性
- animation和transiton的相关属性
- animate和translate
11、display哪些取值
12、相邻的两个inline-block节点为什么会出现间隔该如何解决
13、meta viewport 移动端适配
14、CSS实现宽度自适应100%,宽高16:9的比例的矩形
15、rem布局的优缺点
16、画三角形
17、1像素边框问题
浏览器
以下是 HTTP 请求/响应的步骤:
\1. 客户端连接到Web服务器
一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字(套接字socket)连接。例如,http://www.luffycity.com。
\2. 发送HTTP请求
通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。
\3. 服务器接受请求并返回HTTP响应
Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。
\4. 释放连接TCP连接
若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;
\5. 客户端浏览器解析HTML内容
客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。
1、输入url到展示页面过程发生了什么?
-
浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
-
解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接;
-
浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
-
服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
-
释放 TCP连接;
-
浏览器将该 html 文本并显示内容;
2、重绘与回流
- 重绘(repaint): 当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要UI层面的重新像素绘制,因此 损耗较少
- 回流(reflow): 当元素的尺寸、结构或触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作。会触发回流的操作:
* 页面初次渲染
* 浏览器窗口大小改变
* 元素尺寸、位置、内容发生改变
* 元素字体大小变化
* 添加或者删除可见的 dom 元素
* 激活 CSS 伪类(例如::hover)
* 查询某些属性或调用某些方法
* clientWidth、clientHeight、clientTop、cli