tools

通用工具网站

前端

服务器

IDE获取激活码

社区

npm

设置为淘宝源

1
npm config set registry https://registry.npm.taobao.org

yarn

查看源

1
yarn config get registry

设置为淘宝源

1
yarn config set registry https://registry.npm.taobao.org

设置为默认

1
yarn config set registry https://registry.yarnpkg.com

安装node-sass慢的问题

参考链接

对node-sass镜像源进行设置

1
2
3
yarn config set sass-binary-site http://npm.taobao.org/mirrors/node-sass
或者
npm config set sass-binary-site http://npm.taobao.org/mirrors/node-sass

ReactWheels02_01面向对象

面向对象

OOP的历史

面向对象是一种编程范式(方法论,思考方法等)

历史

  • 1950

    1
    2
    objects和 oriented等技术名词在 MIT里出现,概念尚未明确
    ALGOL 语言里有一些面向对象的早期形态,如消息/方法/成员函数等
  • 1960

    1
    2
    Simula 语言初步实现面向对象思想,一些重要的概念得以实现,如类/对象/继承/动态绑定等。
    不过 Simula 没实现 private 和 public 等访问修饰符
  • 1970

    1
    2
    Smalltalk 出现。 它主要是受 Simula启发。
    Lisp 又受到 Smalltalk 影响,开始接纳面向对象思想,最终导致 Flavors (首个引入 mixin 的语言)/ CommonLoops(支持多继承),这两门语言导致了 Common Lisp 对象系统的出现
  • 1980

    1
    2
    3
    1981 Adele Golderg 携文将 Smalltalk 和面向对象编程介绍给更多的人。
    1986 第一届 面向对象编程峰会 举办 吸引了1000多人
    期间 c++ 和 Object C 受此影响诞生
  • 1990

    1
    2
    3
    4
    5
    面向对象思想被广泛采纳,甚至成为主流编程思想,尤其是用户界面编程领域。
    事件驱动编程在它带领下也开始流行(如nodejs)。
    一些不支持面向对象的语言开始慌了 BASIC/Pascal
    一些从一开始就支持面向对象,也支持以前过程式编程的语言被发明出来如 python ruby
    最重要的商业化面向对象语言是 sun发明的 java 以及微软发明的 c#, VB .net

面向对象和函数式不是对立的

ReactWheels01_01函数式编程

Lisp

  1. Lisp是函数式的正宗,而React抄袭了函数式,我们应该学习正宗的,追根溯源
  2. 你的知识范围应该大于 工作需要用到的知识,这样才能游刃有余
  3. 推荐书籍 SICP

lisp 基本语法

表达式(算术运算)

1
2
3
4
5
6
7
8
9
10
11
# 1 + 2
> (+ 1 2)
< 3

# 1 + 2 + 3 + 4
> (+ 1 2 3 4)
< 10

# 3*3 + 4*4
> (+ (* 3 3) (* 4 4))
< 25

较长的表达式(组合的表达式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(+ (+ 3 (+ (* 2 4) (+ 3 5))) (+ (- 10 7) 6))

// 表达式复杂建议换行
(+
(+
3 (+
(* 2 4)
(+ 3 5)
)
)

(+
(- 10 7)
6
)
)

命名 (定义,不叫赋值)

1
2
3
4
< (define size 5)
>
< (* size 2)
> 10

复杂过程(函数定义)

1
2
3
4
5
6
7
8
# 也是要 define声明 第一个括号(函数名 参数1,参数2) 第二个括号(函数的实现)
< (define (add a b) (+ a b))
< (add 1 2)
> 3

< (define (square x) (* x x))
< (square 4)
> 16

递归求值

1
2
3
4
5
6
7
8
9
10
(+
(*
2
(+ 7 8)
)
(+
3
(- 10 6)
)
)

带入求值

1
2
3
4
5
6
7
8
9
10
11
12
(define (sq x) (* x x))
(defined
(sqsum a b)
(+ (sq a)
(sq b)
)
)
)

(define (f z)
(sqsum z (+ z 1))
)

注意:

  1. 代码只是为了方便我们理解函数,并不一定是实际的工作原理
  2. 不是所有代码都能代入的,必须满足一定的条件

if

求绝对值的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(define (abc a)
(if (> a 0)
a
(-a)
)
)

// (if arg1 arg2 arg3)
/*
arg1 条件
arg2 真
arg2 假

注意:为什么没有return ,不是所有语言都需要return
if是默认返回的
*/

递归

  • 阶乘

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    f(n) = n!

    f(1) = 1
    f(2) = 1 * 2
    f(3) = 1 * 2 * 3
    f(n) = 1 * 2 * 3 ... * (n-1) * n

    演变一下

    f(1) = 1
    f(2) = f(1) * 2
    f(3) = f(2) * 3
    f(n) = f(n-1) * n
  • lisp 的形式

    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
    (define (f n)
    (if (= n 1)
    1
    (*
    n
    (f (- n 1))
    )
    )
    )

    // 此时我想问 f(6) 的结果是什么
    f(6)
    (* 6 f(5))
    (* 6 (* 5 f(4)))
    (* 6 (* 5 (* 4 f(3)))
    (* 6 (* 5 (* 4 (* 3 f(2)))
    (* 6 (* 5 (* 4 (* 3 (* 2 f(1)))
    (* 6 (* 5 (* 4 (* 3 (* 2 1))
    (* 6 (* 5 (* 4 (* 3 2))))
    (* 6 (* 5 (* 4 6)))
    (* 6 (* 5 24))
    (* 6 120)
    720

    // 这就是 递归

迭代

之前我们求阶乘咋求的 从后往前 f(6) > 6 * f(5)

  • 我们正着想呢?
1
2
3
4
5
6
7
8
9
10
11
12
6!  ?

1!
2!
3!
4!
5!
6!

// 伪代码
result = n * result
n = n + 1

伪代码(迭代过程)

1
2
3
4
5
6
7
8
9
10
11
12
13
(f 6)
(j result n n-max)
// 第一个参数是 结果
// 第二个参数是 当前的 n
// 第三个参数是 结束条件

(j 1 1 6)
(j 2 2 6)
(j 6 3 6)
(j 24 4 6)
(j 120 5 6)
(j 720 6 6) // 还要再循环一次 因为不知道该不该结束
(j ? 7 6) // 7 > 6 返回到 f(6)

lisp 代码

1
2
3
4
5
6
7
8
9
10
11
(define (fac n)
(fact-iter 1 1 n))
(define (fact-iter result max-n)
(if (> n max-n)
result
(fact-iter (* n result)
(+ n 1)
max-n
)
)
)
  • 递归:先递进(展开),在回归(求值)
  • 迭代:从一个状态到下一个状态(状态便明亮的数目固定)

高阶函数

有空在完善lisp代码吧。。。

  • 接受一个或多个函数当作参数
  • 输出一个函数

总结

  1. 代入法求值
  2. 递归与迭代的区别
  3. 高阶函数

Py009-01-05restful协议

restful协议

1.API与用户的通信协议,推荐使用 HTTPS

2.域名

  • 子域名方式

    1
    2
    3
    4
    www.luffycity.com
    api.luffycity.com

    存在跨域,还要买域名
  • URL方式(推荐)

    1
    2
    3
    4
    www.luffycity.com
    www.luffycity.com/api/

    不存在跨域,便宜

3.版本

4.路径,视网络任何东西都是资源,均用名词表示

1
2
3
4
5
URL 推荐 www.luffycity.com/api/v1/名词/

# 增删改查这种动词不该出现在 url 里
www.luffycity.com/api/v1/user/ 正确格式
www.luffycity.com/api/v1/get_user/ 没遵守规范

5.method

  • get 从服务器获取资源(一项或多项)
  • post 新建一个资源
  • put 在服务器更新资源(客户端提供改变后的完整资源)全部更新
  • patch 在服务器更新资源(客户端提供改变的属性)局部更新
  • delete 从服务器删除资源

6.过滤,通过url传参的形式传递条件

7.状态码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

通常结合code一起使用

1
2
3
4
5
6
7
8
9
10
11
因为状态码有限,而code可以任意定制

{
code:1004,
msg:'用户不存在'
}

{
code:2004,
msg:'用户已禁用'
}

8.错误处理,状态码是4xx时,应返回错误信息,error当做key。

1
2
3
{
error: "Invalid API key"
}

9.返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档

# 例子

GET /user 返回资源对象的列表(数组)
GET /user/id 返回单个资源对象
POST /user 返回新生成的资源对象
PUT /user/id 返回完整的资源对象(全部修改)
PATCH /user/id 返回完整的资源对象(局部修改)
DELETE /user/id 返回一个空文档

10.Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/order/
[
{
id:1,
name:'apple',
url:'http://www.xxx.com/1' # 资源的详细信息
},
{
id:2,
name:'orange',
url:'http://www.xxx.com/2' # 资源的详细信息
}
]

# 免去你单独拼接 url 访问资源

谈谈你对 restful api 规范的认识

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
本质就是一个api, 定义一些规范,目的就是为了更好的让后台处理和前端方便记住这些url.

其实就是url上体现对api的操作
在以前如 get/post 也都可以实现这些 crud 但是要声明很多 url
http://www.xxx.com/get_user/
http://www.xxx.com/update_user/
http://www.xxx.com/add_user/
http://www.xxx.com/delete_user/

前端遇到跨域问题就导致发两次请求 一次 option 一次 get
设置 cors

除了这个跨域还有没其他方式解决 => jsonp

状态码都记得什么
2系列
3系列
4系列
5系列

和上面总结的十条规则

协同开发时更加的统一

如果你写接口推荐使用 CBV的方式

Py009-01-04接口开发之restful由来

以前的用户管理接口实现

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
http://www.xxx.com/add_user
http://www.xxx.com/update_user
http://www.xxx.com/get_user
http://www.xxx.com/delete_user


在 django 里

urlpatterns = [
re_path(r'^get_user/',views.get_user),
re_path(r'^update_user/',views.update_user),
re_path(r'^add_user/',views.add_user),
re_path(r'^delete_user/',views.delete_user),
]

views.py里定义四个视图函数

def get_user(request):
return HttpResponse('')

def update_user(request):
return HttpResponse('')

def add_user(request):
return HttpResponse('')

def delete_user(request):
return HttpResponse('')
  • 这样会导致 url 越来越多,如果是对十张表crud 就会出现40个url
  • 渐渐的出现了一个潜规则 —— 根据请求方法来区分 这样只写一个url就可以了

restful 风格的接口开发

  • 根据 method 不同做不同的操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
urlpatterns = [
re_path(r'^user/',views.user),
]

views.py 里只写一个视图函数

def user(request):
method = request.method
if method == 'GET':
return HttpResponse('')
elif method == 'POST':
return HttpResponse('')
elif method == 'PUT':
return HttpResponse('')
elif method == 'DELETE':
return HttpResponse('')

基于CBV的 restful 规范开发接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
urls.py

urlpatterns = [
re_path(r'^students/', views.StudentsView.as_view()),
]

views.py

class StudentsView(View):
def get(self,request,*args,**kwargs):
return HttpResponse('get');

def post(self,request,*args,**kwargs):
return HttpResponse('post');

def put(self,request,*args,**kwargs):
return HttpResponse('put');

def delete(self,request,*args,**kwargs):
return HttpResponse('delete');

Py009-01-03CBV之csrf问题

面试题

1.django中间件最多几个

最多五个

  • process_request
  • process_view
  • process_response
  • process_exception
  • process_render_template

2.用中间件做过什么

  • 权限
  • 用户登录验证
  • csrftoken

3.django的 csrftoken怎么实现的

  • django 里默认中间件 有一个 csrf ,它放在process_view 里(为什么是 ,它放在process_view阶段而不是process_request,因为在响应视图函数时要判断是否存在忽略csrftoken验证的装饰器)
  • 而且是全局的,如果注释掉全局都不校验 token

4.我想要单独某个不校验 csrftoken 如何实现?

  • 装饰器 csrf_exempt 免除csrftoken验证
1
2
3
4
5
6
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def users(request):
user_list = ['alex','aaa','bbb']
return HttpResponse(json.dumps(user_list))

5.全局的csrftoken注释了,我想单独给某个视图函数加csrf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

#
from django.views.decorators.csrf import csrf_exempt,csrf_protect

@csrf_protect # 该函数需要 csrftoken验证
def users(request):
user_list = ['alex','aaa','bbb']
return HttpResponse(json.dumps(user_list))

CBV忽略csrf

  • from django.views.decorators.csrf import csrf_exempt,csrf_protect
  • from django.utils.decorators import method_decorator
  • 在 dispatch上添加 装饰器 method_decorator
  • 在 method_decorator 里传入 csrf_exempt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django.utils.decorators import method_decorator
class StudentsView(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(StudentsView,self).dispatch(self,request,*args,**kwargs);
def get(self,request,*args,**kwargs):
return HttpResponse('get');

def post(self,request,*args,**kwargs):
return HttpResponse('post');

def put(self,request,*args,**kwargs):
return HttpResponse('put');

def delete(self,request,*args,**kwargs):
return HttpResponse('delete');

或者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django.utils.decorators import method_decorator

@method_decorator(csrf_exempt,name='dispatch')
class StudentsView(View):

def get(self,request,*args,**kwargs):
return HttpResponse('get');

def post(self,request,*args,**kwargs):
return HttpResponse('post');

def put(self,request,*args,**kwargs):
return HttpResponse('put');

def delete(self,request,*args,**kwargs):
return HttpResponse('delete');

Py009-01-02CBV基本使用

CBV结构实现的原理

StudentsView 的 get/post等方法如何调用的呢?

  • 反射——(反射代码在哪里?)
1
2
3
4
5
6
7
8
9
10
11
12
13
from django.views import  View;
class StudentsView(View):
def get(self,request,*args,**kwargs):
return HttpResponse('get');

def post(self,request,*args,**kwargs):
return HttpResponse('post');

def put(self,request,*args,**kwargs):
return HttpResponse('put');

def delete(self,request,*args,**kwargs):
return HttpResponse('delete');

urls.py里 as_view函数

1
2
3
4
5
6
# 在路由系统里永远是 一个url 对应一个函数
urlpatterns = [
re_path(r'^students/', views.StudentsView.as_view())
]
# views.StudentsView.as_view() 返回一个函数
# StudentsView 本身没有 as_view 方法 => 它的父类 View 里

View 源码里的 as_view

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
def as_view(cls, **initkwargs):
"""Main entry point for a request-response process."""
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
# 定义了一个view 函数并返回
def view(request, *args, **kwargs):
# cls就是当前请求的类 StudentsView
# self = StudentsView() 实例化
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# 返回当前的 dispatch 方法 =》 一个请求进来实际是执行 dispatch
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs

# take name and docstring from class
update_wrapper(view, cls, updated=())

# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view

dispatch

1
2
3
4
5
6
7
8
9
10
11
class View:
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

def dispatch(self, request, *args, **kwargs):
# 获取请求方式 get/post/put/delete
if request.method.lower() in self.http_method_names:
# 反射
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)

经典面试题:你知道的http请求方式有哪些

1
2
3
4
5
6
7
8
9
10
[
'get', #查
'post', #增加
'put', #更新
'patch', #局部
'delete', #删除
'head',
'options',
'trace'
]

原理

1
url => view方法 => dispatch方法 => (反射执行其他 get/post/put/delete)
  • 请求进来要先执行 dispatch方法

定制自己的 dispatch 方法

  • 触发 dispatch 之前/之后 做一些操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from django.views import  View;
class StudentsView(View):
def dispatch(self, request, *args, **kwargs):
# 调用 父类的 dispatch
print('before')
ret = super(StudentsView,self).dispatch(request, *args, **kwargs)
print('after')
return ret

def get(self,request,*args,**kwargs):
return HttpResponse('get');

def post(self,request,*args,**kwargs):
return HttpResponse('post');

def put(self,request,*args,**kwargs):
return HttpResponse('put');

def delete(self,request,*args,**kwargs):
return HttpResponse('delete');

多个类公用功能,为了避免重复编写

假如此时有个TeachersView,这样要复制两份dispatch

  • 使用继承
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
35
36
class MyBaseView(object):
def dispatch(self, request, *args, **kwargs):
# 调用 父类的 dispatch
print('before')
ret = super(StudentsView, self).dispatch(request, *args, **kwargs)
print('after')
return ret

class StudentsView(MyBaseView,View):

def get(self,request,*args,**kwargs):
return HttpResponse('get');

def post(self,request,*args,**kwargs):
return HttpResponse('post');

def put(self,request,*args,**kwargs):
return HttpResponse('put');

def delete(self,request,*args,**kwargs):
return HttpResponse('delete');


class TeachersView(MyBaseView,View):

def get(self,request,*args,**kwargs):
return HttpResponse('get');

def post(self,request,*args,**kwargs):
return HttpResponse('post');

def put(self,request,*args,**kwargs):
return HttpResponse('put');

def delete(self,request,*args,**kwargs):
return HttpResponse('delete');

Py009-01-01restful由来

1.开发模式

  • 普通开发模式(前后端放在一起写)
  • 前后端分离

2.后端开发

  • 为前端提供URL(API/接口开发)
  • 永远返回 HttpResponse

3.Django 中的 FBV/CBV

  • FBV(function base view)
  • CBV(class base view)

实践

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
# step001 新建 django项目 dj_restful    
# app 名为 app001

# step002 修改 urls.py

from app001 import views;
urlpatterns = [
re_path(r'^users/',views.users)
]

# step003 修改 app001/views.py

import json
from django.shortcuts import render,HttpResponse

def users(request):
user_list = ['alex','aaa','bbb'];
return HttpResponse(json.dumps(user_list));


# step004 启动 django 项目
访问 http://localhost:8000/users/

# 返回
["alex","aaa","bbb"]

# 这就是你的第一个接口

FBV 函数作为视图

1
2
3
def users(request):
user_list = ['alex','aaa','bbb'];
return HttpResponse(json.dumps(user_list));

CBV 类作为视图

假如写个学生信息接口

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
# 第一步 修改 urls.py
from django.urls import path,re_path
from app001 import views;

urlpatterns = [
re_path(r'^students/', views.StudentsView.as_view())
]

# 第二步 继承 View
from django.views import View;
class StudentsView(View):
def get(self,request,*args,**kwargs):
return HttpResponse('get');

def post(self,request,*args,**kwargs):
return HttpResponse('post');

def put(self,request,*args,**kwargs):
return HttpResponse('put');

def delete(self,request,*args,**kwargs):
return HttpResponse('delete');

# 第三步 注释掉 settings.py 里的 csrf验证

# 第四步 安装 postman
对 http://localhost:8000/students/ 发起 get/post/put/delete请求

4.列表生成式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Foo:
pass

class Bar:
pass

v = [item() for item in [Foo,Bar]]
'''
相当于
v = [];
for i in [Foo,Bar]:
obj = i() # 循环时Foo(), Bar() 实例对象
v.append(obj)

v # 对象列表
'''

5.面向对象

  • 封装

    • 对同一类方法封装到类中

      1
      2
      3
      4
      5
      6
      7
      8
      9
      class File:
      # 文件crud方法
      def get ...
      def update ...

      class DB:
      # sql crud方法
      def get ...
      def update ...
    • 将数据封装到对象中

      1
      2
      3
      4
      5
      6
      class Student:
      def __init__(self,name,age):
      self.name = name
      self.age = age

      stu1 = Student('Alex',18)

6.封装示例

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
class Request():
def __init__(self,obj):
self.obj = obj;

@property
def user(self):
return self.obj.authticate()

class Auth():
def __init__(self,name,age):
self.name = name
self.age = age

def authticate(self):
return self.name

# 接口 class
class APIView():
# 派发事件
def dispatch(self):
# 利用反射 get/post/put/delete
self.get();


def get(self):
a = Auth('alex',18)
req = Request(a);
print(req.user)

obj = APIView()
obj.dispatch(); # 返回 alex

TS入门008函数下

函数里规定this

1
2
3
4
5
6
7
8
9
10
11
12
13
// 规定函数的this

interface Human{
name:string;
age:number;
}

function fn(this:Human){
console.log(this);
}

fn.call({name:'hjx',age:18})
// fn() // 报错 
  • ts明确规定 this是参数,不传递就导致问题
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function fn(this:any){
    console.log(this);
    function fn2(this:any){
    console.log(this);
    }
    fn2() // 此时this已经变了,谁叫你不用 call
    }

    fn.call({name:'hjx'})

重载

一个函数有不同的调用方式

1
2
3
4
5
6
7
8
//这是js代码
//这是js代码
//这是js代码
function add(a,b){return a + b;}

add(1,2) // 3
add('hjx','hi') // 'hjxhi'
add(1,'2') // '12'

ts重载

1
2
3
4
5
6
7
8
9
function add(a:number,b:number);
function add(a:string,b:string);
function add(a,b){
return a + b;
}

add(1,2) //3
add('hello','world') // helloworld
// add(1,'2') //报错
  • 注意! js不支持不同参数数量的重载,只支持相同参数数量的重载
  • 注意! js不支持不同参数数量的重载,只支持相同参数数量的重载

范型和重载的区别

1
2
3
4
5
6
7
8
function add(a:number,b:number);
function add(a:string,b:string);
function add(a,b){
return a + b;
}

// 重载可以确定具体的参数的类型
// 范型 太广泛了, 而且你无法检查 参数 a ,b是否支持 a + b

类型推断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function add(n1:string,n2:string){
return n1 + n2
}

var s = add('hi','aa');
console.log(s.split('')) // 没有写返回值的类型,为什么不报错

var s2 = {}
s2.split('') //报错


function add2(n1:string,n2:string){
return 0
}
var s3 = add2('hi','aa');
s3.split('') // 报错

如果你这样,ts就会猜 你返回的是什么 string|number

1
2
3
4
5
6
7
8
9
10
11
function add3(n1:string,n2:string){
if(n1 > '1'){
return n1

}else{
return 0
}
}

var s4 = add3('hi','aa');
s4.split('') // 此时他返回的类型有两种可能 string|number

类型兼容

1
2
3
4
5
6
7
8
9
10
11
12
interface Human{
name:string,
age:number
}

let x:Human = {name:'aa',age:18} //正常

// 如果你手贱非要加一个 gender 呢? 报错
// let x2:Human = {name:'aa',age:18,gender:'man'} // 报错

let y = {name:'aa',age:18,gender:'man'}
let x3:Human = y; //这样却没问题

这样做的好处就是节约你的类型个数

soundness 可靠性(浅尝辄止)

sound就是 从语法或逻辑上推断你的代码有木有问题

  • 如果推断出有问题不让你过,就是 sound(非常死板)
  • 如果推断出有问题还让你过,就是 unsound (不那么死板)

TS入门007范型

范型

用一个东西表示广泛的类型

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
//用js 你给我什么就返回什么 
function fn1(something){
return something
}


// 用 ts, 你给我任意类型的东西,我给你任意类型的东西
/*
有问题了
给你 number => string 满足条件 any => any
*/
function fn2(something:any):any{
return something
}

// 用一个占位符
function fn3<T>(something:T):T{
return something
}

let s: string = fn3('hi');
let s2 = fn3('hi') // 因为 'hi'的类型是 string 所以返回值的类型是 string
let s3 = fn3<string>('hi');
let s4 = fn3<number>(1);
let s5 = fn3<boolean>(true);

interface Human{
name:string;
age:number
}

let s6 = fn3<Human>({name:'hjx',age:18});
let s7 = fn3({name:'hjx',age:18});

范型数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function returnArray<T>(array:T[]):T[]{
return array;
}

let a = returnArray([1,2,3]);

interface Human{
name:string;
age:number
}

let a2 = returnArray<Human>([{name:'aa',age:11},{name:'bb',age:12}])
let a3 = returnArray([{name:'aa',age:11},{name:'bb',age:12}])


/*
function returnArray<T>(array:T[]):T[]{
return array;
}
还可以写成
function returnArray<T>(array:Array<T>):Array<T>{
return array;
}
*/

范型还可以这样声明

1
2
3
4
5
6
// 用一个占位符
function xxx<T>(something:T):T{
return something
}

let fn: <T>(something:T)=>T = xxx;

接口和范型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
interface add{
(a:number,b:number):number;
}

let numAdd:add = (a:number,b:number):number=>{
return a + b;
}

// 接口和范型

interface anyAdd<T>{
(a:T,b:T):T;
}

let stringAdd:anyAdd<string> = (a:string,b:string):string =>{
return a + b;
}

let numberAdd:anyAdd<number> = (a:number,b:number):number =>{
return a + b;
}

范型约束

1
2
3
4
5
function fn<T>(something:T):T{ 
console.log(something.length)
return something
}
// 如果参数是 数字 1 就报错了

添加一个约束条件

1
2
3
4
5
6
7
8
interface hasLength{
length:number
}

function fn<T extends hasLength>(something:T):T{
console.log(something.length);
return something
}

使用类类型的约束

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function createT( c ){
// c 必须是 类 才可以 ,而且在js里不报错
return new c();
}
// createT('hi') 报错


class Student{}

class Human{}

// ts里 约束参数是个类
function createT2<T>( c:{new ():T} ):T{
// c 必须是 类 才可以 ,而且在js里不报错
return new c();
}

// createT2<Human>(Student) 报错 因为明确约束了 类
createT2<Human>(Human)