JavaScript 学习笔记
引子
最近几个月复习JavaScript时做的笔记,以及一些小问答的记录,后续可能会更新…
JS历史
- ES3:ECMAScript 3,1999年12月,ECMAScript 3.0版发布,成为JavaScript的通行标准,得到了广泛支持。
- ES5:ECMAScript 5,2008年发布的标准,由ECMAScript3.1更名而来
- ES6:2015年6月,ECMAScript 6正式发布,并且更名为“ECMAScript 2015”,有了非常多的新特性和语法糖。
浏览器渲染机制
- 解析HTML标签,构建DOM树
- 解析CSS标签,构建CSSOM树
- 把DOM和CSSOM树合成渲染树
- 在渲染树的基础上进行布局,计算每个节点的几何结构
- 把每个节点绘制到屏幕上
Repaint和Reflow
- 回流(Reflow)
- 对于DOM结构中的各个元素都有自己的盒子(模型),这些都需要浏览器根据各种样式(浏览器的、开发人员定义的等)来计算并根据计算结果将元素放到它该出现的位置,这个过程称之为reflow
- 重绘(Repaint)
- 当各种盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来后,浏览器于是便把这些元素都按照各自的特性绘制了一遍,于是页面的内容出现了,这个过程称之为repaint。
加载异步
1 | <script src="script.js"></script> |
没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。
1 | <script async src="script.js"></script> |
有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。
1 | <script defer src="script.js"></script> |
有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。
defer
:脚本延迟到文档解析和显示后执行,有顺序async
:不保证顺序
白屏与FOUC
- CSS、JS脚本放在页面文档前加载时,浏览器加载CSS、JS等待过程中,就会出现白屏或FOUC
- Chrome浏览器会处于白屏状态,等待加载内容加载完毕后,展现后面页面的内容,而Firefox浏览器则会展现页面内容,等待CSS加载完毕后闪烁页面,展现带有样式的页面内容
JS数据类型
- number
- string
- boolean
- undefined
- null
- object
- symbol
数值、字符串、布尔值这三种类型,合称为原始类型(primitive type)的值,即它们是最基本的数据类型,不能再细分了。对象则称为合成类型(complex type)的值,因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。至于undefined
和null
,一般将它们看成两个特殊值。
判断类型
可以通过typeof
运算符判断数据类型:
1 | typeof 123 // "number" |
运算符
+
会有字符串相关处理,-、*、/
等会直接把表达式两边都转化为数字。
比较运算符
==
不严格相等,不同类型会转换为同类型作比较===
严格相等,不同类型会不等!=
不相等!==
严格不相等
位运算
|
按位或&
按位与~
取反>>
<<
>>>
运算符的优先级
运算符的优先级决定了表达式中运算执行的先后顺序,优先级高的运算符最先被执行。
结合性节
结合性决定了拥有相同优先级的运算符的执行顺序。考虑下面这个表达式:
1 | a OP b OP c |
左结合(左到右)相当于把左边的子表达式加上小括号(a OP b) OP c
,右关联(右到左)相当于a OP (b OP c)
。赋值运算符是右关联的,所以你可以这么写:
1 | a = b = 5; |
结果 a
和 b
的值都会成为5。这是因为赋值运算符的返回结果就是赋值运算符右边的那个值,具体过程是:b
被赋值为5,然后a
也被赋值为 b=5
的返回值,也就是5。
汇总表节
下面的表将所有运算符按照优先级的不同从高到低排列。
优先级 | 运算类型 | 关联性 | 运算符 | ||
---|---|---|---|---|---|
20 | 圆括号 |
n/a | ( … ) |
||
19 | 成员访问 |
从左到右 | … . … |
||
需计算的成员访问 |
从左到右 | … [ … ] |
|||
new (带参数列表) |
n/a | new … ( … ) |
|||
函数调用 | 从左到右 | … ( … ) |
|||
18 | new (无参数列表) | 从右到左 | new … |
||
17 | 后置递增(运算符在后) | n/a | … ++ |
||
后置递减(运算符在后) | … -- |
||||
16 | 逻辑非 | 从右到左 | ! … |
||
按位非 | ~ … |
||||
一元加法 | + … |
||||
一元减法 | - … |
||||
前置递增 | ++ … |
||||
前置递减 | -- … |
||||
typeof | typeof … |
||||
void | void … |
||||
delete | delete … |
||||
await | await … |
||||
15 | 幂 | 从右到左 | … ** … |
||
14 | 乘法 | 从左到右 | … * … |
||
除法 | … / … |
||||
取模 | … % … |
||||
13 | 加法 | 从左到右 | … + … |
||
减法 | … - … |
||||
12 | 按位左移 | 从左到右 | … << … |
||
按位右移 | … >> … |
||||
无符号右移 | … >>> … |
||||
11 | 小于 | 从左到右 | … < … |
||
小于等于 | … <= … |
||||
大于 | … > … |
||||
大于等于 | … >= … |
||||
in | … in … |
||||
instanceof | … instanceof … |
||||
10 | 等号 | 从左到右 | … == … |
||
非等号 | … != … |
||||
全等号 | … === … |
||||
非全等号 | … !== … |
||||
9 | 按位与 | 从左到右 | … & … |
||
8 | 按位异或 | 从左到右 | … ^ … |
||
7 | 按位或 | 从左到右 | `… | …` | |
6 | 逻辑与 | 从左到右 | … && … |
||
5 | 逻辑或 | 从左到右 | `… | …` | |
4 | 条件运算符 | 从右到左 | … ? … : … |
||
3 | 赋值 | 从右到左 | … = … |
||
… += … |
|||||
… -= … |
|||||
… *= … |
|||||
… /= … |
|||||
… %= … |
|||||
… <<= … |
|||||
… >>= … |
|||||
… >>>= … |
|||||
… &= … |
|||||
… ^= … |
|||||
`… | = …` | ||||
2 | yield | 从右到左 | yield … |
||
yield* | yield* … |
||||
1 | 展开运算符 | n/a | ... … |
||
0 | 逗号 | 从左到右 | … , … |
类型转换
类型 | 结果 |
---|---|
Undefined | false |
Null | false |
Boolean | 直接判断 |
Number | +0, −0, 或者 NaN 为 false, 其他为 true |
String | 空字符串为 false,其他都为 true |
Object | true |
x == y
x | y | 结果 |
---|---|---|
null | undefined | true |
Number | String | x == toNumber(y) |
Boolean | (any) | toNumber(x) == y |
Object | String or Number | toPrimitive(x) == y |
otherwise | otherwise | false |
toNumber
type | Result |
---|---|
Undefined | NaN |
Null | 0 |
Boolean | ture -> 1, false -> 0 |
String | “abc” -> NaN, “123” -> 123 |
函数
立即执行函数
在声明时就直接执行的函数,它拥有独立的词法作用域,不仅避免了外界访问此 函数 中的变量,而且又不会污染全局作用域。
1 | // 立即执行函数 |
递归
1 | // 求n! |
声明提前
1 | console.log(a) // 不会报错 |
作用域
作用域链
遇到一个变量,在变量的作用域找,找不到则找它的上层作用域。
- 函数在执行的过程中,先从自己内部找变量
- 如果找不到,再从创建当前函数所在的作用域去找, 以此往上
- 注意找的是变量的当前的状态
引用类型
- 基本类型 数值 布尔值 null undefined,保存在栈内存中
- 引用类型 对象 数组 函数 正则 存在堆内存中,变量中保存的实际只是一个指针
1 | // 对象的浅拷贝与深拷贝 |
对象
1 | var company = { |
JSON
- 复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象。
- 简单类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和
null
(不能使用NaN
,Infinity
,-Infinity
和undefined
)。 - 字符串必须使用双引号表示,不能使用单引号。
- 对象的键名必须放在双引号里面。
- 数组或对象最后一个成员的后面,不能加逗号。
1 | // 深拷贝 |
数组
1 | let arr = [1, 2, 3] |
1 | // 写一个函数,操作数组,返回一个新数组,新数组中只包含正数。 |
1 | // 用 splice函数分别实现 push、pop、shift、unshift方法。 |
1 | // 对以下代码 users中的对象,分别以 name 字段、age 字段、company 字段进行排序 |
1 | // 分别举例说明ES5数组方法 indexOf、forEach、map、every、some、filter、reduce的用法? |
1 | // 实现一个reduce函数,作用和原生的reduce类似下面的例子。 |
1 | // 实现一个flatten函数,将一个嵌套多层的数组 array(数组) (嵌套可以是任何层数)转换为只有一层的数组,数组中元素仅基本类型的元素或数组,不存在循环引用的情况。 |
字符串
1 | // 多行字符串的声明有哪几种常见写法? |
1 | var str = 'hello jirengu.com' |
Math
1 | // 写一个函数,生成一个随机 IP 地址,一个合法的 IP 地址为 0.0.0.0~255.255.255.255。 |
1 | // 写一个函数,生成一个随机颜色字符串,合法的颜色为#000000~ #ffffff。 |
1 | // 写一个函数,返回从min到max之间的 随机整数,包括min不包括max |
1 | // 写一个函数,生成一个长度为 n 的随机字符串,字符串字符的取值范围包括0到9,a到 z,A到Z。 |
DATE
1 | // 写一个函数,参数为时间对象毫秒数的字符串格式,返回值为字符串。假设参数为时间对象毫秒数t,根据t的时间分别返回如下字符串: |
正则表达式
贪婪模式和非贪婪模式
贪婪模式
贪婪模式下,正则表达式会尽可能多的匹配重复字符,举例来说:
1 | var str = 'I hate "boring" and "lazy", but i can\'t control myself !'; |
我们预想的结果是[ '"boring"', '"lazy"' ]
,而实际结果是[ '"boring" and "lazy"' ]
,这就是正则的贪婪模式🔒造成的。
- 正则先匹配到第一个字符,第一个字符是
"
,很快就匹配到了对应的字符。 - 第二个字符是
.
,他表示任意字符,所以匹配到了b
。 - 第三个是
*
,他表示匹配前一个表达式0次或者多次,而.
表示任意字符,所以会循环匹配到字符串结尾。 - 到达字符串结尾了,还没有找到第四个字符
"
,所以,开始回溯,一个一个的缩减所匹配的字符串,直到遇到"
,匹配结束。 - 得到结果
[ '"boring" and "lazy"' ]
。
非贪婪模式
非贪婪模式下,正则表达式会尽可能少的重复匹配字符,举例说明:
1 | var str = 'I hate "boring" and "lazy", but i can\'t control myself !'; |
- 第一步与上面的类似,匹配到
"
。 - 第二个字符是
.
,他表示任意字符,所以匹配到了b
。 - 第三步就不同了,在非贪婪模式下,此时会尽可能的匹配
"
,可是b
后面的字符是o
,所以匹配不上,由.
来进行了匹配。 - 一直匹配直到遇到了
"
结束,此时才算匹配到了第一个结果,匹配模式是global
的,所以会从此处开始匹配第二个结果。 - 最后结果为
[ '"boring"', '"lazy"' ]
。
常见用例
1 | // 写一个函数isValidUsername(str),判断用户输入的是不是合法的用户名(长度6-20个字符,只能包括字母、数字、下划线)。 |
1 | // 写一个函数isPhoneNum(str),判断用户输入的是不是手机号。 |
1 | // 写一个函数isEmail(str),判断用户输入的是不是邮箱。 |
1 | // 写一个函数trim(str),去除字符串两边的空白字符。 |
\d,\w,\s,[a-zA-Z0-9],\b,.,*,+,?,x{3},^,$分别是什么?
\d
,数字\w
,所有单字字符,包括字母、数字或者下划线\s
, 匹配一个空白字符,包括空格、制表符、换页符和换行符[a-zA-Z0-9]
,匹配一个字母或者数字\b
, 匹配一个词的边界,/\bm/
匹配“moon”中的‘m’.
,匹配除换行符之外的任何单个字符。+
,匹配前面一个表达式1次或者多次*
,匹配前一个表达式0次或多次?
,匹配前面一个表达式0次或者1次x{3}
,匹配xxx
字符串^
,匹配输入的开始$
,匹配输入的结束
定时器
setTimeout
:执行一次。
setInterval
:执行无数次,必须调用clearInterval停止。
单线程模型
Event loop
callback queue
WebApi
setTimeout
会将当前代码移除本次EventLoop,在下次loop时判断条件,满足条件就执行,否则不执行。
JavaScript是单线程的,意思是JavaScript 同时只能执行一个任务,其他任务都必须在后面排队等待,JavaScript 运行时,除了一个正在运行的主线程,引擎还提供一个任务队列(task queue),里面是各种需要当前程序处理的异步任务,当我们使用setTimeout
函数时,setTimeout
的callback
就被放到了任务队列。
在执行代码时,主线程会先执行所有的同步任务,等到主线程里的任务都执行完毕后,才会执行任务队列的异步函数,所以setTimeout
里的函数,不一定是真的等待了指定时间执行的,如果主线程里的事件耗时太长,等到执行任务队列的回调函数时,已经超出了开始所设置的等待时间。
1 | var a = 1; |
1 | var flag = true; |
1 | // 实现一个节流函数 |
DOM
1 | <ul class="ct"> |
1 | <ul class="ct"> |
事件
事件流
- IE模型:
事件冒泡模型 | 事件捕获模型 | DOM事件流 |
---|---|---|
div->body->html->document | document->html->body->div | document->html->body->div->body->html->document |
Dom2事件处理程序
addEventListener
removeEventListener
接受三个参数
- 事件类型
- 事件处理函数
- 布尔值,true表示在事件捕获阶段触发,false表示在事件冒泡阶段触发,默认为false
优势:能够绑定多次处理程序,后面的不会覆盖前面的
`
javascript
btn.addEventListener(‘click’,function(){console.log('helllo')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
### 事件冒泡
### 常见的HTML事件
```javascript
click
dblclick // 双击左键
mouseover // 鼠标移入 移入子元素也会触发一次out与over
mouseout // 鼠标移出
mousenter // 鼠标移入 移入子元素不会出发enter和leave
mousleave // 鼠标移出
focus // 获取焦点
blur // 失去焦点
keyup // 按键抬起
change // 值的变动
submit // form 提交事件
scroll // 滚动 触发多次
resize // 窗口发生变化 触发多次
onload // 页面所有资源加载完成触发
DOMContentLoaded // DOM结构渲染完成
事件传播机制
DOM2级事件定义了两个方法用于处理指定和删除事件处理程序的操作:
- addEventListener
- removeEventListener
所有的DOM节点都包含这两个方法,并且它们都接受三个参数:
- 事件类型
- 事件处理方法
- 布尔参数,如果是true表示在捕获阶段调用事件处理程序,如果是false,则是在事件冒泡阶段处理
事件传播主要分为两个部分,一个是捕获阶段,一个是冒泡阶段,假设我们有如下四个部分:
document、html、body、div
在事件的捕获阶段,事件是从外层往内层传播的,顺序如下:
document—>html—>body—>div
在事件冒泡阶段,事件是从内层逐级像外层冒泡的,顺序如下:
div—>body—>html—>document
还有一个阶段,处于目标阶段,它处在捕获与冒泡间,此时目标实际接收事件。
阻止传播
在事件的传播过程中中途中断事件传播,让其在指定元素层停止。
1 |
|
取消默认事件
某些元素,例如a
元素,当用户点击时会自动跳转到a
中href
所指的链接,我们可以通过设置,阻止这个跳转操作,进行地址检测,只允许部分链接跳转。
1 | $('a').onclick = function (e) { |
事件代理
把一个元素的响应事件函数绑定到另一个元素上,就叫做事件代理。
举个例子,我们也买呢有n个divs
元素,我们需要给这些div
元素添加点击事件,点击时打印出标签的innerText
,同时我们还有一个按钮会在点击时添加新的div
,这时候,新添加的div
元素的点击事件就不那么好设置了,我们可以通过把div
的点击事件函数绑定到div
的父元素container
上,这就是一个典型的事件代理的例子:
1 | $('#container').onclick = function(e){ |
onlick
与addEventListener
的区别
- 使用方式不同,
onlick
属于dom
对象的一个属性,使用时直接通过赋值方式将一个响应函数传递给onlick
,以此来作为事件响应。addEventListener
时对象的一个方法,接受三个参数:- 事件类型
- 事件处理函数
- 布尔值,true表示在事件捕获阶段触发,false表示在事件冒泡阶段触发,默认为false
- 作用次数不一样,
onlick
方式只能绑定一个响应函数,后面绑定的响应函数会覆盖前面的,addEventListener
方式可以绑定多次处理程序,后面的不会覆盖前面的。
1 |
BOM
window.onload
和document.onDOMContentLoaded
有什么区别?
window.onload
设置的函数会在load
触发时执行,此时,在文档中的所有对象都在DOM中,所有图片,脚本,链接以及子框都完成了装载。document.onDOMContentLoaded
:当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完成加载
1 | // 如何获取图片真实的宽高? |
HTMLElement.offsetHeight 是一个只读属性,它返回该元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数。
1 | // URL编码解码 |
为什么要编码
首先,因为网络标准RFC 1738做了硬性规定:
“…Only alphanumerics [0-9a-zA-Z], the special characters “$-.+!*’(),” [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL.”
“只有字母和数字[0-9a-zA-Z]、一些特殊符号”$-.+!*’(),”[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL。”
然后在某些时候,url里面的参数可能是另一个url,此时需要使用encodeURIComponent()
,将”$””&””=”等等字符也进行编码,避免出现错误。
cookie session localstorage
Cookie 和 locakstorage存储的值都是字符串
cookie
HTTP Cookie(也叫Web Cookie或浏览器Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie使基于无状态的HTTP协议记录稳定的状态信息成为了可能。
Cookie主要用于以下三个方面:
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
Cookie曾一度用于客户端数据的存储,因当时并没有其它合适的存储办法而作为唯一的存储手段,但现在随着现代浏览器开始支持各种各样的存储方式,Cookie渐渐被淘汰。由于服务器指定Cookie后,浏览器的每次请求都会携带Cookie数据,会带来额外的性能开销(尤其是在移动环境下)。
session
session使用中能够让服务器识别某个用户的机制,一般存储在服务器内存或者数据库中,实现session一般需要使用cookie,一个常见的使用机制如下
- 创建session后,将session_id通过setCookie添加到http响应头中。
- 浏览器在加载页面时发现响应头又set-cookie字段,就把该cookie加到浏览器指定域名下。
- 下次刷行域名时,请求会带上cookie,服务器更具cookie中的session_id来识别用户。
localStorage
- localStorage HTML5本地存储web storage特性的API之一,用于将大量数据(最大5M)保存在浏览器中,保存后数据永远存在不会失效过期,除非用 js手动清除。
- 不参与网络传输。
- 一般用于性能优化,可以保存图片、js、css、html 模板、大量数据。
AJAX
Asynchronous JavaScript + XML(异步的JavaScript+XML),本身并不是一种新技术,依赖于现有的CSS/HTML/JavaScript,其中最核心的依赖是浏览器提供的XMLHttpRequest对象,这个对象使得浏览器可以发送HTTP请求或者接受HTTP响应,实现在页面不刷新的情况下与服务器进行数据交互。
1 | // 简单封装一个ajax |
MOCK
mock数据有三种方式:
- 文件访问,将需要获取的数据直接存在文件里,访问时直接访问对应的静态文件
- 搭建本地mock服务器,模拟数据
- 使用第三方mock网站,例如easymock,rap等
跨域
同源策略
浏览器处于安全策略考虑,只允许与本域下的接口交互,不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。
同源
- 同协议
- 同域名
- 同端口
对于当前页面来说页面存放的JS文件的域不重要,重要的是加载该JS页面所在什么域
注意,同源策略是浏览器的安全策略。
实现跨域
JSONP
HTML中的script标签可以加载其他域的js。
JSONP通过script标签加载数据的方式,获取数据当作JS执行
CORS
IE10+,前端W加入一个Origin头,后台返回数据后加入一个Access-Control-Allow-Origin头
降域
闭包
测试题
如下代码输出多少?如果想输出3,那如何改造代码?
1
2
3
4
5
6
7 var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = function(){
return i
};
}
console.log( fnArr[3]() )
1 | for (var i = 0; i < 10; i++) { |
封装一个 Car 对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 var Car = (function(){
var speed = 0;
//补充
return {
setSpeed: setSpeed,
getSpeed: getSpeed,
speedUp: speedUp,
speedDown: speedDown
}
})()
Car.setSpeed(30)
Car.getSpeed() //30
Car.speedUp()
Car.getSpeed() //31
Car.speedDown()
Car.getSpeed() //30
1 | var Car = (function () { |
如下代码输出多少?如何连续输出 0,1,2,3,4?
1
2
3
4
5 for(var i=0; i<5; i++){
setTimeout(function(){
console.log('delayer:' + i )
}, 0)
}
1 | for (var i = 0; i < 5; i++) { |
补全代码,实现数组按姓名、年纪、任意字段排序。
1
2
3
4
5
6
7
8 var users = [
{ name: "John", age: 20, company: "Baidu" },
{ name: "Pete", age: 18, company: "Alibaba" },
{ name: "Ann", age: 19, company: "Tecent" }
]
users.sort(byField('age'))
users.sort(byField('company'))
1 | var users = [{ |
写一个 sum 函数,实现如下调用方式。
1
2 console.log( sum(1)(2) ) // 3
console.log( sum(5)(-1) ) // 4
1 | function sum(i) { |
JQuery
图片懒加载
设置图片默认动画,一般设置成一个loading图。
通过判断滚动容器视窗高度
height
,容器滚动高度scrollTop
,图片相对于容器的高度offsetHeight
三个值,heigth+scrollTop>=offsetHeight
时表示图片出现在了用户视野中,此时加载图片。滚动事件可以使用函数节流的方式减少事件触发次数,提高效率,已加载图片可以设置标
志,减少图拍链接修改次数,提高效率。
瀑布流布局
- 通过容器宽度和需要进行布局的元素宽度计算除瀑布列数
- 设置一个数组,数组长度就是瀑布列数,值时对应列数的高度
- 当一个新的待布局元素加载时,使用绝对定位,将其拼接到高度最低的列后面
- 依次加载,就实现了一个瀑布流布局
木桶布局的实现原理
- 设置容器宽度,和容器基准高度。
- 将第一个待布局的图片进行对基准高度进行等比缩放,放在第一行。
- 依次将后面的图片放到第一行,当最后一个图片放入时会导致超过容器宽度时将其放到第二行,同时将第一行的所有图片作为一个整体,等比拉伸(可以对row使用flex布局),使其宽度等于容器宽度。
- 依次渲染,实现木桶布局。
JS面向对象
如下代码中, new 一个函数本质上做了什么?
1
2
3
4 function Modal(msg){
this.msg = msg
}
var modal = new Modal()
- 新建一个空对象,空对象的
__proto__
就是Modal.prototype
- 将this的初始化的值传递到这个对象中
- 将这个对象返回给modal
画出如下代码的原型图。
1
2
3
4
5
6
7
8
9
10 function People (name){
this.name = name;
}
People.prototype.walk = function(){
console.log(this.name + ' is walking');
}
var p1 = new People('饥人谷');
var p2 = new People('前端');
扩展 String 的功能增加 reverse 方法,实现字符串倒序
1
2
3 var str = 'hello jirengu'
var str2 = str.reverse()
console.log(str2) // 'ugnerij olleh'
1 | String.prototype.reverse = function () { |
apply、call 、bind有什么作用,什么区别
- apply传入两个参数,一个作为函数的目标对象,一个数组作为函数的参数
- call传入一个对象作为函数的目标对象,然后传入多个参数作为函数参数
- bind传入以一个对象,返回一个新的函数,新函数的this指向传入的对象
call()方法的作用和 apply() 方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。
有如下代码,解释Person、 prototype、proto、p、constructor之间的关联。
1
2
3
4
5
6
7
8 function Person(name){
this.name = name;
}
Person.prototype.sayName = function(){
console.log('My name is :' + this.name);
}
var p = new Person("若愚")
p.sayName();
- Person: 函数Person
- constructor: Person.prototype的constructor指向Person
- __proto__: p.__proto__ === Person.prototype
- p是Person的一个实例
对String做扩展,实现如下方式获取字符串中频率最高的字符
1
2
3 var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因为d 出现了5次
1 | String.prototype.getMostOften = function () { |