My Block


  • Startseite

  • Archiv

session、localStorage入门

Veröffentlicht am 2018-04-23

1. cookie和session的区别

1. cookie

  • cookie是由服务器发送给浏览器的响应头里的Set-Cookie:的值构成的。
  • cookie保存在客户端,并且每次都随着请求发送给server。
  • 没有session之前,cookie里保存的是用户信息,由于任何人可以读写,不安全

    2. session

  • session是依附于cookie而存在的
  • 有了session,服务器将用户的信息保存在服务器中的session表里,然后赋予相应的信息一个sessionID,于是将响应头里的Set-Cookie的值改为sessionID
  • 浏览器请求时带上cookie,服务器就通过cookie里的sessionID查找session表里对应的信息
  • 这样暴露给其他人的就只有sessionID,很安全。

    2. localStorage

    • 与cookie不同,请求的时候浏览器不会带上localStorage
      • 而且每个域名localStorage最大存储量5Mb左右,cookie只有4k左右
      • 而且localStorage理论上不会过期,除非清理缓存
      • 所以持续化存东西的时候用localStorage
  1. session是服务器上的hash,localStorage是浏览器上的hash,localStorage里存的东西保存在本地。
  2. 只有相同域名的网页才能互相读取localStorage。
  3. API:

    1
    2
    localStorage.setItem('a',1);
    localStorage.getItem('a'); //1
  4. 用来记录有没有提示过用户等信息,不能用来记录密码之类的

3. sessionStorage

  1. sessionStorage和session没有关系
  2. sessionStorage和localStorage的1、2、3点是一样的,区别是关掉浏览器后sessionStorage就会被清除

Cookie入门

Veröffentlicht am 2018-04-22

1. 看一遍注册登陆的代码

  • github
  • Cookie 默认在用户关闭页面后就失效,后台代码可以任意设置 Cookie 的过期时间
  • 大小大概在 4kb 以内

2. 以注册登陆为例

  1. 你注册账号时,服务器把你的用户名、密码存入数据库。
  2. 登陆的时候,浏览器发送post请求,服务器把你的账号密码和数据库里的匹配,若匹配成功,则发送一个响应头给浏览器,如:
    Set-Cookie: sign_in_email=xxx@xxx.com
    这就是cookie,里面记录着你的登陆信息,浏览器会在一段时间内保存cookie
  3. 当你再访问相同域名的网页时,浏览器会带着这个cookie发送GET请求,服务器会将cookie里的信息和数据库匹配,若匹配上了,则直接发送给你已经登陆上的页面
  4. cookie默认在关闭页面后被清除,而后台可以 设置cookie的过期时间

3. 前端永远不要读写cookie

前端用localStorage

4. 设置cookie过期时间

  1. setMaxAge

    1
    2
    3
    cookie.setMaxAge(0);//不记录cookie
    cookie.setMaxAge(-1);//会话级cookie,关闭浏览器失效
    cookie.setMaxAge(60*60);//过期时间为1小时
  2. 过时了的expires

    1
    2
    Set-Cookie: name=Nicholas; expires=Sat, 02 May 2009 23:38:25 GMT
    //星期六 5月2号 2009年 23:38:25时过期

JS基础知识考试

Veröffentlicht am 2018-04-18

1. 关于new

1
2
3
4
function fn(){
console.log(this)
}
new fn() //会执行fn

答:this就是fn,它有__proto__属性,__proto__指向这个fn的原型
fn的原型里有两个属性{contructor: fn()}和__proto__(指向Object.prototype)

2. MVC

  1. MVC是Model View Controller
    View:是这个js模块对应在html中的部分,就是展示给用户看的那一部分

    Model:可以从服务器获得数据,把数据传给Controller。还要将Controller监听到的用户提交的数据上传到服务器。

    Controller:调用model的数据,用来更新view。还要监听用户在view上的操作,获取用户提交的数据,传给model。

  2. 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    window.Model = function(options){
    let resourceName = options.resourceName;
    return {
    init : function(){},
    fetch: function(){},
    save: function(){}
    }
    }

    window.View = function(selector){
    return document.querySelector(selector);
    }

    window.Controller = function(options){
    let init = options.init;

    let object = {
    view: null,
    model: null,
    init: function(view,model){
    this.view = view;
    this.model = model;
    this.model.init();
    init.call(this.view);
    this.bindEvents.call(this)
    }
    };
    for(let key in options){
    if(key !== 'init'){
    object[key] = options[key]
    }
    }
    return object;
    }

3. 用函数模拟一个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Animal(species) {
this.species = species; //自有属性
}

Animal.prototype = {
constructor: Animal,
walk : function () {}, //走路的代码
run: function () {}, //跑步的代码
eat: function () {}, //吃东西的代码
sleep: function () {} //睡觉的代码
};

let cat = new Animal('cat')
cat.specise === cat //true
//并且cat对象的__proto__指向Animal.prototype,有里面的动作属性

4. promise

1
2
3
4
5
6
7
8
9
promiseTest = function (a,b){
return new Promise(function(resolve,reject){
if(a+b>5){
resolve(); //若参数a+b大于五则执行resolve
}else{
reject(); //若参数a+b大小于等于五则执行resolve
}
})
}

使用:

1
2
3
4
5
6
7
8
promiseTest(4,6).then(
() => {
console.log('大于5');
},
() => {
console.log('小于5')
},
) //'大于5'

5. JSON

AJAX入门

ES6入门

Veröffentlicht am 2018-04-13

1. let语法,用法和var一样

1. 作用域不同
若用let来声明变量,只在let命令所在的代码块内有效。而var只有在function内用才能有块级作用域效果,除了function,在其他地方用var全声明的是全局变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//例1
{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1

//例2
for (let i = 0; i < 3; i++) {
let i = 'abc'; //这个i和上面的数字i不互相影响
console.log(i);
}
// abc
// abc
// abc

2. let不会变量提升!

2. 解构语法

1
2
3
4
5
6
7
//es5
let options = response.options
let method = options.method;
let body = options.body;
let successFn = options.successFn
//es6,下面一行等于上面四行
let {options:method,body,successFn} = response;

若是用在函数里:

1
2
3
4
5
6
7
8
function(response){
let {options:method,body,successFn} = response;
}

//上面这样可以简化为下面
function({options:method,body,successFn}){
//直接把这个当参数,省略options
}

3.

1
2
3
4
5
6
7
8
9
10
11
//es5 
object{
go: function(){
}
}

//es6
object{
go(){
}
}

实现AJAX

Veröffentlicht am 2018-04-13

1. 原生JS实现AJAX

第一步:let request = new XMLHttpRequest();

1. 设置请求

用AJAX设置请求的第一部分:

1
request.open('get','/xxx')  //设置get的请求方式,再设置路径为/xxx

设置第二部分:

1
2
3
request.setRequestHeader('Accept','text/html')
```
设置第四部分:

request.send(‘请求体’) //请求一般没有第四部分,可以直接send空字符串

1
2
3

### 2. 获取响应
获取HTTP状态码

request.status //200
request.statusText //OK

1
获取响应第二部分

request.getAllResponseHeaders() //获取第二部分所有
request.getResponseHeader(‘Content-Type’) //获取Content-Type

1
获取第四部分

requeset.responseText

1
2
3

# 2. jQuery实现AJAX
1. 封装ajax

jQuery.ajax=function({url,method,body,headers}){
return new Promise(function(resolve,reject){
let request = new XMLHttpRequest()
request.open(method,url) //配置request
for(let key in headers){
let value = headers[key];
request.setRequestHeader(key,value);
}
request.onreadystatechange = ()=>{
if(request.state === 4){
if(request.status >= 200 && request.status < 300){
resolve.call(undefined,request.responseText)
}else if{request.status >= 400}{
reject.call(undefined,request)
}
}
}
request.send(body); //body是第四部分
})
}

1
2
3
返回一个promise对象,传入的两个参数resolve、reject,分别代表成功时执行的内容和失败时执行的内容,下面的then就是使用promise。

2. 使用ajax

$.ajax({
url: ‘/xxx’,
method: ‘get’,
headers:{
‘content-type’:’application/x-www-form-urlencoded’,
‘pyz’:21
}
}).then(
(responseText) =>{
console.log(responseText);
return responseText; //上面的返回的是成功就执行这个,失败就执行下面那个
},
(request)=>{
console.log(‘error’); return ‘error’ //失败就执行这个
}
)
`

AJAX入门

Veröffentlicht am 2018-04-11

1. 历史

1. 如何发请求

  • form可以发送GET和POST请求,会刷新页面或新开页面
  • a可以发送GET请求,会刷新页面或新开页面
  • img可以发送GET请求,只能以图片形式展示
  • link可以发送GET请求,只能以css或favicon形式展示
  • script可以发送GET请求,只能以脚本形式运行

    2. 进化

    IE5在JS中引入ActiveX对象(API),使JS可以直接发送请求,其他浏览器跟进,取名XMLHttpRequest,被纳入W3C规范。现在进化成AJAX

2. AJAX

Jesse James Garrett将这个技术取名为AJAX:异步的JavaScript和XML。

  1. 使用XMLHttpRequest发请求
  2. 服务器返回XML格式的字符串,只能返回字符串
  3. JS解析XML,并更新局部页面

API:readyState === 4 //表示整个请求过程已完毕

3. 用的是JSON

1. JSON是抄袭了JavaScript的一门语言

区别:

  1. JSON没有抄袭function和undefined和symbol
  2. JSON的字符串首尾必须用双引号”pyz”
  3. JSON有6种数据类型
  • null
  • number
  • string(必须用双引号)
  • boolean(true false)
  • array([“a”,”b”])
  • object({“name”:”pyz”})
  1. JSON没有原型

    2. API

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    1. let request = new XMLHttpRequest();
    2. request.open('GET','/xxx') //初始化request
    3. request.send() //发送请求
    4. request.onreadystatechange //监听请求状态的变化
    5. request.readyState === 1 //request.open()已经完成
    6. request.readyState === 2 //request.send()已经完成
    7. request.readyState === 3 //request.responseText正在下载
    5. request.readyState === 4 //响应完成
    6. request.status //HTTP状态码
    7. var string = request.responseText //响应的内容
    8. var value = JSON.parse(request.responseText) //把符合JSON语法的字符串转换成JS,解析响应返回的内容
    9. value.node //若value是对象,这就是对象里内容
    10. value.node.name //对象里的name的值

4. 同源策略

  1. form、img、script等上面提到的请求方式,是可以对别的域名发送请求的。
    但用AJAX不能对别的域名放送请求,只有协议、域名、端口号一摸一样才允许发送AJAX(多个www是不同的域名)
    因为AJAX是可以获取响应内容的,如果没有同源策略的限制,别的网站可以通过AJAX获取另一个网站的所有信息。
  2. AJAX可以通过CORS发送请求到别的网站
    跨域资源共享:Cross-Origin Resource Sharing
    在需要访问的服务器里添加一句

    1
    response.setHeader('Access-Control-Allow-Origin', 'http://pyz.com:8888')

    http://pyz.com:8888是我的协议+域名+端口号,这样我就可以访问他的服务器了,即使我们域名不同

    1
    response.setHeader('Access-Control-Allow-Origin', '*')  //这样这个服务器就可以接受所有网站的AJAX请求

5. 面试题

请使用原生JS发送AJAX

1
2
3
4
5
6
7
8
9
10
11
let request = new XMLHttpRequest();
request.open('GET','/xxx');
request.send();
request.onreadystatechange = ()=>{
if(request.readyState === 4){
if(request.status >= 200 && request.status < 300){
var string = request.responseText;
var value = JSON.parse(string);
}
}
}

(重要)JSONP入门

Veröffentlicht am 2018-04-10

1. 必考面试,什么是JSONP

请求方:frank.com的前端程序员(浏览器)
响应方:jack.com的后端程序员(服务器)

  1. 请求方用JS创建一个script标签,它的src指向响应方,同时传查询参数(?callback=…),如下
    1
    script.src = 'http://jack.com:8002/pay?callback=' + functionName;

并用document.body.appendChild(script)将它添加进页面中

  1. 响应方通过查询参数callback构造
    functionName.call(undefined,'数据')
    这样的响应
  2. 浏览器接到响应就会执行 functionName.call(undefined,'数据')
  3. 那么请求方就知道了他想要的数据,’success’ or ‘fail’

以上就是JSONP

functionName.call(undefined,'数据')
‘数据’叫做JSON,’数据’左边的叫JSON的左padding,右边的括号叫右padding,合起来叫JSONP

2. 必考面试题:JSONP为什么不支持POST请求

答:因为JSONP是通过动态创建script的方法进行的,而script只能发送get请求不能发送post请求。

3. jquery的写法

1
2
3
4
5
6
7
8
9
$.ajax({
url:"http://jack.com:8002/pay",
dataType: "jsonp",
success:function (response) {
if(response === 'success'){
amount.innerText = amount.innerText-1;
}
}
})

DOM事件

Veröffentlicht am 2018-04-09

1. DOM0时代html和js的那些事儿

<html>

1
2
3
4
5
6
7
8
9
10
11
12
<head>
<script>
function print() {
console.log('hi');
}
</script>
</head>
<body>
<button id="x" onclick="print">a</button> //html里的onclick相当于eval('print') ,这样只会打印出print这个函数
<button id="y" onclick="print()">b</button> //'hi'
<button id="z" onclick="print.call()">c</button> //'hi'
</body>

<js>

1
2
3
x.onclick = print;  //js里这样是执行函数,输出'hi'
x.onclick = print(); //这样写是得到函数的返回值,undefined
x.onclick = print.call(); //同上,undefined

2. DOM2

1. 监听事件

1
2
3
4
5
6
7
xxx.onclick = function(){};  //不要用这个,因为可能会覆盖掉别人的事件
//用下面这个

function f1(){}

xxx.addEventListener('click',f1) //EventListener是队列,先绑定的就先触发
xxx.removeEventListener('click',f1);

若想让事件被点一次后就取消监听,可以将f1写成下面这样

1
2
3
4
5
6
function f1(){
console.log(1);
xxx.removeEventListener('click',f1); //这样f1执行一次后就自动取消xxx的监听,
}

xxx.addEventListener('click',f1)

这就是$btn.one(‘click’,fn);

2. 嵌套的div被点击的顺序

HTMLJavaScript

  • 面试题1:请问点击儿子的div,这三个函数的执行顺序是什么?
    内部执行顺序
    默认的顺序是像右边的箭头序列,先最里面的儿子再爸爸再爷爷,但如果给addEventListener加个true的话,事件就会到左边来,如下
    1
    2
    3
    grand1.addEventListener('click',function fn1(){
    console.log('爷爷')
    },true)

addEventListener(true)
这样执行顺序就是爷爷 -> 儿子 -> 爸爸。
左边的(加true的顺序),叫做捕获阶段,右边叫冒泡阶段。

  • 面试题2:若给同一个div加上true和false呢?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    child1.addEventListener('click',function fn1(){
    console.log('儿子冒泡')
    },false)
    child1.addEventListener('click',function fn1(){
    console.log('儿子捕获')
    },true)
    //点击child出现'儿子捕获','儿子冒泡'
    //若是给被点击的本身加上true和false,则按事件添加的顺序执行
    //若给爸爸或是爷爷添加true和false,则是按上图箭头顺序执行
  • stopPropagation()
    这个方法可以让它那一层停止往上传播

    1
    2
    3
    child1.addEventListener('click',function fn1(e){
    e.stopPropagation();
    }) //这样点击儿子,就只会执行儿子,不会执行爸爸和爷爷

3. 点击别处关闭浮层

html

1
2
3
4
5
6
<div id="wraper" class="wraper">
<button id="clickMe">点我</button>
<div id="popover" class="popover">
<input type="checkbox">浮层
</div>
</div>

错误示范1,js

1
2
3
4
5
6
7
8
$(clickMe).on('click',function () {
$(popover).show();
});
$(wrapper).on('click',false);
//这里有错误,浮层出来后无法点击checkbox,因为这里的false,阻止了所有默认事件,应该改成下面那样
$(document).on('click',function () {
$(popover).hide();
});

更新版1,还是不完美

1
2
3
4
5
6
7
8
9
$(clickMe).on('click',function () {
$(popover).show();
});
$(wrapper).on('click',function(e){
e.stopPropagation(); //阻止冒泡
});
$(document).on('click',function () {
$(popover).hide();
}); //这样若有多个浮层,则会监听多次document,浪费资源,可以改成下面的

错误示范2,js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$(clickMe).on('click',function () {
$(popover).show();
$(document).one('click',function () { //改为one
$(popover).hide();
});
}); //若没有阻止冒泡,浮层不会显示出来,因为hide也会执行

//可以添加一个setTimeout使它不会马上执行,如下
$(clickMe).on('click',function () {
$(popover).show();
setTimeout(function(){
$(document).one('click',function () {
$(popover).hide();
});
},0) //添加setTimeout后,document.onclick不会马上执行,当下一次点击屏幕的时候才会执行
//这样还是有bug,点击popover内部也会执行hide()
});

完美版本1

1
2
3
4
5
6
7
8
9
$(clickMe).on('click',function () {
$(popover).show();
$(document).one('click',function () {
$(popover).hide();
}); //只在浮层show的时候监听document一次
});
$(wrapper).on('click',function(e){
e.stopPropagation(); //阻止冒泡,这样点击popover内部就不会执行document.onclick,但这个事件还是会存放在那里
});

完美版本2
更新上个版本点按钮不会关闭浮层的bug

1
2
3
4
5
6
7
8
9
10
11
12
13
$(clickMe).on('click',function () {
if($(popover).is(':hidden')){ //若浮层是关闭的,点击按钮则打开
$(popover).show();
}else {
$(popover).hide(); //和上面相反
}
$(document).one('click',function () {
$(popover).hide();
});
});
$(wrapper).on('click',function(e){
e.stopPropagation();
});

期中考试

Veröffentlicht am 2018-04-07

1. 写一个html文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>我的页面</title> //页面标题
<link rel="stylesheet" href="/style.css"> //引入一个css
<link rel="stylesheet" href="/print.css" media="print"> //css仅在打印时生效
<link rel="stylesheet" href="/mobile.css" media="screen and (max-width:500px)"> //css仅在屏幕小于500px时生效
</head>
<body>

<script src="/gbk.js" charset="gb2312"> </script> //指定文件用GBK编码
</body>
</html>

2. 移动端适配

  1. 在html的head里加上meta(背下来)
    1
    <meta name="viewport" content="width=device-width, user-scalable=no ,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

快捷键:meta:vp + tab

  1. media query(媒体查询)
    在引用css的时候加上media属性
    1
    <link rel="stylesheet" href="mobile.css" media="(max-width:768px)">

在css里用media

1
2
3
4
5
6
7
8
9
10
@media (max-width: 800px) {  //屏幕宽度小于800px时
body{
background-color: black;
}
}
@media (min-width:325px) and (max-width: 800px) { //屏幕宽度在325px到800px时
body{
background-color: black;
}
}

  1. 常用单位
    px:像素,网页的默认font-size是16px
    em:本身元素的font-size

    1
    2
    3
    4
    5
    p{
    border: 1px solid red;
    font-size: 20px;
    height:2em;
    } //则p元素的高度就是40px

    rem:根节点(html)的font-size(默认font-size是16px),若设置html的font-size为14px,则整个页面都可以通过设置rem来使其字体是14px的倍数
    vh:100vh === 视口高度
    vw:100vw === 视口宽度

  2. 动态REM(手机专用!)
    rem是根节点(html)的font-size(默认font-size是16px)大小。
    js可以获得当前屏幕的宽度pageWidth,把pageWidth赋给font-size,这样整个页面可以通过设置rem来动态的设置所有间距大小

    1
    2
    3
    4
    5
    <script>
    var pageWidth = window.innerWidth
    document.write('<style>html{font-size:'+pageWidth/10+'px;}</style>')
    //注意!font-size不能小于12px,所以这里可以除以10,但不能除以100,除以100就小于12了
    </script>
1
2
3
4
5
6
7
8
9
10
11
12
<styel>
*{margin: 0;padding: 0;}
body{font-size: 16px;}
.clearfix::after{content: ""; clear: both; display: block;}
.child{
background: #ddd;
width: 4rem;
height: 2rem;
margin: 0.5rem 0.5rem; //一行两个width加上左右margin正好是10rem,因为script里font-size除以了10
float: left;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<body>
<div class="father clearfix ">
<div class="child">
可以
</div>
<div class="child">
可以
</div>
<div class="child">
可以
</div>
<div class="child">
可以
</div>
</div>
</body>

通过rem动态设置间距
当设置很小的东西的时候,直接写像素就行了,比如设置边框的时候。
把body的font-size设置成16px。

使用SCSS更方便的调整rem,Sass入门

3. 用css3实现圆角矩形和阴影

设置border-radius和box-shadow,具体请看css入门

4. 闭包

JS函数

5. call、apply和bind

请看面向对象编程

6. 7. HTTP

HTTP入门

8. 算法

几种常见算法

9. 一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

10. 数组去重

  1. ES5

    • 方法一:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      Array.prototype.distinct = function (){
      var arr = this,
      i,
      obj = {},
      result = [],
      len = arr.length;
      for(i = 0; i< arr.length; i++){
      if(!obj[arr[i]]){ //如果能查找到,证明数组元素重复了
      obj[arr[i]] = 1;
      result.push(arr[i]);
      }
      }
      return result;
      };
      var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,];
      var b = a.distinct();
      console.log(b.toString()); //1,2,3,4,5,6,56
    • 方法二:(递归)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      Array.prototype.distinct = function (){
      var arr = this,
      len = arr.length;
      arr.sort(function(a,b){ //对数组进行排序才能方便比较
      return a - b;
      })
      function loop(index){
      if(index >= 1){
      if(arr[index] === arr[index-1]){
      arr.splice(index,1);
      }
      loop(index - 1); //递归loop函数进行去重
      }
      }
      loop(len-1);
      return arr;
      };
      var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,56,45,56];
      var b = a.distinct();
      console.log(b.toString()); //1,2,3,4,5,6,45,56
    • 方法三:(利用indexOf以及forEach)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      Array.prototype.distinct = function (){
      var arr = this,
      result = [],
      len = arr.length;
      arr.forEach(function(v, i ,arr){ //这里利用map,filter方法也可以实现
      var bool = arr.indexOf(v,i+1); //从传入参数的下一个索引值开始寻找是否存在重复
      if(bool === -1){
      result.push(v);
      }
      })
      return result;
      };
      var a = [1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,2,3,3,2,2,1,23,1,23,2,3,2,3,2,3];
      var b = a.distinct();
      console.log(b.toString()); //1,23,2,3

      方法三的indexOf和forEach都是遍历,双重循环效率不高,所以差评

  2. ES6
    set数据结构

    1
    2
    3
    4
    function dedupe(array){
    return Array.from(new Set(array));
    }
    dedupe([1,1,2,3]) //[1,2,3]

    拓展运算符(…)内部使用for…of循环

    1
    2
    3
    let arr = [1,2,3,3];
    let resultarr = [...new Set(arr)];
    console.log(resultarr); //[1,2,3]

面向对象编程

Veröffentlicht am 2018-04-07

1. This关键字

这三个方法都可以绑定this值

1. call()

  • this

    1
    2
    3
    4
    5
    6
    7
    8
    var obj = {};

    var f = function () {
    return this;
    };

    f() === window // true
    f.call(obj) === obj // true

    call方法的参数,应该是一个对象。
    如果参数为空、null和undefined,正常模式下默认传入全局对象(window),严格模式下为undefined。
    call方法可以改变this的指向,指定this指向对象obj。

    1
    2
    3
    4
    5
    var f = function () {
    return this;
    };

    f.call(5) //Number {[[PrimitiveValue]]: 5}

    若call方法的参数是一个原始值,那么这个原始值会转成对应的对象

  • arguments

    1
    2
    3
    4
    5
    6
    function add(a, b) {
    console.log(arguments[0]);
    console.log(arguments[1]);
    }

    add.call(this, 1, 2) // 1,2,第一个参数传给this,后面的都存入arguments对象

    arguments是伪数组

2. apply()

apply方法的第一个参数用法和call一样,不同的是第二个参数必须是一个数组

1
2
3
4
function f(x, y){
console.log(x + y);
}
f.apply(null, [1, 1]) // 2

所以利用这一点
(1)找出数组最大元素
JavaScript 不提供找出数组最大元素的函数。结合使用apply方法和Math.max方法,就可以返回数组的最大元素。

1
2
var a = [10, 2, 4, 15, 9];
Math.max.apply(null, a) // 15

(2)将数组的空元素变为undefined
通过apply方法,利用Array构造函数将数组的空元素变成undefined。

1
2
Array.apply(null, ['a', ,'b'])  
// [ 'a', undefined, 'b' ]

数组的forEach方法会跳过空元素,但是不会跳过undefined。

3. bind()

bind可以绑定this值

1
2
3
4
5
var d = new Date();
d.getTime() // 1481869925657

var print = d.getTime;
print() // Uncaught TypeError: this is not a Date object.

这样会报错,可以像下面这样,将getTime内部的this绑定为d对象

1
2
var print = d.getTime.bind(d);
print() // 1481869925657

下面这样也是,将inc方法内部的this绑定到counter

1
2
3
4
5
6
7
8
9
10
var counter = {
count: 0,
inc: function () {
this.count++;
}
};

var func = counter.inc.bind(counter);
func();
counter.count // 1

还可以绑定其他对象

1
2
3
4
5
6
7
8
9
10
11
12
13
var counter = {
count: 0,
inc: function () {
this.count++;
}
};

var obj = {
count: 100
};
var func = counter.inc.bind(obj);
func();
obj.count // 101

bind还可以绑定原函数的参数

1
2
3
4
5
6
7
8
9
10
11
var add = function (x, y) {
return x * this.m + y * this.n;
}

var obj = {
m: 2,
n: 2
};

var newAdd = add.bind(obj, 5); //5相当于绑定了add函数里的x
newAdd(5) // 20,这个5相当于add函数里y

若bind第一个对象为null,等于将this绑定到全局对象(window)
bind的注意事项:
(1)每一次返回一个新函数
bind方法每运行一次,就返回一个新函数,所以监听事件的时候,要谨慎使用。更多

2. 用函数模拟一个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Animal(species) {
this.species = species; //自有属性
}

Animal.prototype = {
constructor: Animal,
walk : function () {}, //走路的代码
run: function () {}, //跑步的代码
eat: function () {}, //吃东西的代码
sleep: function () {} //睡觉的代码
};

let cat = new Animal('cat')

cat.specise === cat //true
//并且cat对象的__proto__指向Animal.prototype,有里面的动作属性

加new的三个作用

  • 帮你创建临时对象,用this就可以访问到,比如上面的this.species
  • 帮你绑定原型,使Animal里有个隐藏属性__proto__指向Animal.prototype
  • 帮你return临时对象Animal.prototype.constructor === Animal

未完待续…

123…5

Pengyize

50 Artikel
© 2018 Pengyize
Erstellt mit Hexo
|
Theme — NexT.Muse v5.1.4