一、TypeScript的特点

1.支持ES6规范

2.强大的IDE支持(集成开发环境)

  1. 允许为变量指定类型,减少你在开发阶段犯错误的几率。

  2. 语法提示,在IDE编写代码时,它会根据你所处的上下文把你能用的类,变量,方法,关键字给你提示出来。

  3. 重构,方便的修改变量,方法,文件的名字,当你修改的时候IDE会帮你把你用到过这些变量,方法的地方给修改掉。

3.Angular2的开发语言。

二、搭建TypeScipt的开发环境

1. 我们需要compiler(编译器)。

我们需要把 .ts 结尾的TypeScript文件给编译成 .js 结尾的JavsScript文件,因为现在有些浏览器是不支持ES6语法的,没办法直接让程序跑起来,所以我们需要编译成支持ES5的JavaScript语法。

2. 使用在线compiler开发 TypeScript

3. 搭建本地开发环境

  1. npm insatll typescript -g全局安装

  2. tsc --version查看版本

  3. ./demo/hello.ts

  4. tsc ./demo/hello.ts会在它的同级目录生成一个hello.js文件

  5. 每次都这样的操作有点麻烦,我们开始使用IDE,它可以帮我做这些事情

    创建项目目录打开CMDtsc --init会生成tsconfig.json配置文件

    1. {
    2. "compilerOptions": {
    3. "target": "es5",//翻译出来的语法
    4. "module": "commonjs",//使用commonjs模块
    5. "outDir": "./js/",//翻译出来的文件存放在./js文件夹中
    6. "rootDir": "./tscript/",//需要翻译的文件放在./tscript文件夹中
    7. "esModuleInterop": true
    8. // esModuleInterop取决于设置的内容module。
    9. // 如果有"module": "commonjs",则只需启用"esModuleInterop": true。
    10. // 如果您有"module": "es2015"或者"module": "esnext",
    11. //您还必须启用"allowSyntheticDefaultImports": true以便导入CommonJS模块(如React)作为默认值。
    12. }
    13. }

    我们采用以上配置;

    我们今天用Visual Studio Code来做示范打开创建好的项目文件夹,webstorm上的话会有提示插件更加方便。

    新建tscript、js文件夹,分别用作存放typescript、javascript文件,在tscript目录中新建test.ts文件。

    打开>菜单>终端>运行任务>

    点击运行后,只要我们修改ts文件的代码且保存后会自动翻译

    这就配置好了,接下来就可以正常开发了。

三、学习字符串

1、多行字符串

JS中我们声明变量是不可以换行的

  1. var str = 'aaa
  2. bbb
  3. ccc'
  4. /*上面这样的写法是会报错的,我们通常用下面的写法*/
  5. var str = 'aaa'+
  6. 'bbb'+
  7. 'ccc';

TS中有多行字符串的写法用``来包裹

  1. var str = `aaa
  2. bbb
  3. ccc`
  4. //在这个里面你是可以任意换行的
  5. //翻译成JS是这样的
  6. var str = 'aaa\nbbb\nccc'

2、字符串模板

  1. var myName = 'huoqingchi'
  2. var getName = function () {
  3. return 'huoqingchi';
  4. }
  5. console.log(`hello ${myName}`);//可以直接写表达式
  6. console.log(`hello ${getName()}`);//也可以直接调用方法
  7. //切记能这样做的原因是因为它们写在了``当中。

接下来我们见识下字符串模板的威力,用字符串拼接一段HTML

  1. var myName = 'huoqingchi';
  2. console.log(`<div>
  3. <h1>你们好我是${myName}</h1>
  4. <h1>${getName()}</h1>
  5. </div>`);//可读性和书写实在是太好了。

3、自动拆分字符串

当你在用一个字符串模板去调用一个方法的时候这个字符串模板里面表达式的值会自动赋给被调用方法中的参数。

  1. function test(template,name,age) {
  2. console.log(template)
  3. console.log(name)
  4. console.log(age)
  5. };
  6. var myName = 'huoqingchi';
  7. var getAge = function(){
  8. return 18;
  9. }
  10. //如果你想使用字符串拆分的特性就不能直接圆括号调用test方法,需要用``。
  11. //第一个参数是你的字符串模板。
  12. //第二个参数就是你出现的第一个表达式的值。
  13. //第三个参数就是你出现的第二个表达式的值。
  14. test`hello ${myName},${getAge()}`

输出结果:


四、参数的新特性

1、参数类型

在参数的名称后面我们可以使用冒号来指定参数的类型

因为我已经给str这个变量指定了string类型,所以我再给它赋值一个数值类型时会报错,这种情况只会出现在我们编写.ts文件时,当它给我们翻译成.js文件的时候还是会被赋值数值型的。

可是上面代码我明明没有给它指定类型了,为什么还是报错呢?

这是因为TypeScript有一个类型推断机制,如果你一次给这个变量存储的是字符串值,它会规定你这个变量只能存储字符串值。

如果想让一个变量又是字符串又是数值型;

我们可以给这个变量赋值一个any类型,它代表这个变量可以存储任何类型的值;

除了string和any类型我们还有

​ 1、number //数值

​ 2、boolean //true||false

​ 3、void //用来声明方法的返回值的void代表这个函数不需要返回值,你也可以给这个方法设置返回规定的类性。除了给方法设置类性外,我们也可以给方法的参数设置类型,规定必须传入的参数。

​ 4、自定义类型:

  1. class Person {
  2. name:string;
  3. age:number;
  4. }
  5. var zhangsan :Person = new Person();
  6. zhangsan.name = 'zhangsan'
  7. zhangsan.age = 18;
  8. //当你声明好Person类型后去调用会有语法提示你它当前有那些属性且他们的类性是什么。

如果你声明了一个变量,再声明一个同名函数会报错,


2、默认参数

这个时候我们可以给第三个形参设置一个默认值:

切记,需要设置默认参数的形参从后面依次排列,因为传入的参数是从第一个开始匹配的


3、可选参数

在方法的参数声明后面用?来标明此参数为可选参数

这个时候运行会输出:

使用可选参数要注意的有两点:

​ 1.可选参数没传的时候怎么处理,b参数没有传入,但是如果我在函数体里面直接去调它的话会报错;

​ 例子:console.log(b.lenght)//这种错误非常常见undefined不能打点

​ 2.可选参数是不可以声明在必选参数的前面;


五、函数新特性

1、Rest and Spread 操作符

1.1声明可以传入任意参数的方法(主要)

  1. function func1(...args) {//这个...就是Rest and Spread 操作符
  2. //用...声明的args参数可以传入任意数量的参数
  3. args.forEach(function (arg) {
  4. console.log(arg)
  5. })//args就是一个数组,它内部用的是arguments,可以去观察翻译后的.js文件。
  6. };
  7. func1(1,2,3);
  8. func1(4,5,6,7,8);

输出结果:

1.2 把任意长度的数组一个固定数量的方法的调用

  1. function func1(a,b,c) {
  2. console.log(a);//第一次传过来的是1,2没有第三个参数所以c是undefined
  3. console.log(b);//第二次传过来的是5,4,2,34,2但是我们只有a,b,c三个形参接受,所以只会拿取前三个。
  4. console.log(c);
  5. };
  6. var args = [1,2];
  7. func1(...args);//这样的操作会把args数组里面的每一项给出来,当做实参传过去。
  8. var args2 = [5,4,2,34,2];
  9. func1(...args2);//因为TypeScript还不支持这种语法所以会报错,但是编译好的js文件可正常运行。

运行编译后的js文件输出结果:


2、generator函数

它可以控制函数的执行过程,手工暂停和恢复代码执行。

  1. function* get() {//在function和函数名中间加*就是generator函数
  2. console.log("start");
  3. yield;//yield会将函数打断停留不继续往下执行
  4. console.log("finish")
  5. }
  6. var func1 = get();//如果你直接去调用get函数是没用的,需要将它赋给一个变量。
  7. func1.next();//通过调用.next()可以让函数执行。//输出start;
  8. func1.next();//输出finish,//每次调用next会让函数执行且停留在下一个yield。

因为这个语法TypeScript暂时还不支持,它是es6规范的一部分,所以我们用到了babel翻译

  1. function *get() {
  2. while (true) {//这个循环没有一直执行,只有下面price>limit为true的时候才会执行
  3. yield Math.random()*100;
  4. }
  5. }
  6. var priceG = get();//拿到get的执行权
  7. var limit = 15;//最低15
  8. var price = 100;//起始100
  9. while (price>limit) {//如果低于15就停。
  10. price = priceG.next().value;//通过.value得到get函数中yield返回的随机数且赋值给price
  11. console.log(`${price}`)//输出yield返回的值
  12. }
  13. console.log(`${price}`);//如果拿到了小于15的数就会最后弹出

输出结果:


3、析构表达式

通过表达式将对象或数组拆解成任意数量的变量。

3.1 Object

  1. function get() {
  2. return {
  3. xing:'huo',
  4. age:18
  5. }
  6. }
  7. var {xing,age} = get();
  8. //{}中的变量名要跟你函数返回对象中的属性名相同
  9. //如果想改名字:{xingshi:xing,age}
  10. //console.log(xingshi);//'huo'
  11. console.log(xing);//'huo'
  12. console.log(age);//18
  1. function get() {
  2. return {
  3. xing:'huo',
  4. yifu:{//如果你返回的又是一个对象
  5. kuzi:400,
  6. shangyi:200
  7. }
  8. }
  9. }
  10. //那么我们可以再把里面的属性给析构
  11. var {xing,yifu:{kuzi}} = get();
  12. console.log(xing);//'huo'
  13. console.log(kuzi);//400

3.2 Array

  1. var arr1 = [1,2,3,4];
  2. var [number1,number2] = arr1;
  3. console.log(number1)//1
  4. console.log(number2)//2
  5. //如果要拿3和4
  6. var [, , number1, number2] = arr1;
  7. //站位,但是我不拿出来。
  8. console.log(number1)//3
  9. console.log(number2)//4
  10. //如果要拿1和4
  11. var [number1, , number2] = arr1;
  12. console.log(number1)//1
  13. console.log(number2)//4

3.2 析构表达式和Rest操作符共用

  1. var arr1 = [1,2,3,4];
  2. var [number1,number2,...shengyu] = arr1;
  3. console.log(number1)//1
  4. console.log(number2)//2
  5. console.log(shengyu)//[3,4]
  1. var arr1 = [1,2,3,4];
  2. function test([number1, number2, ...shengyu]) {
  3. console.log(number1)//1
  4. console.log(number2)//2
  5. console.log(shengyu)//[3,4]
  6. }
  7. test(arr1);//类型“number[]”的参数不能赋给类型“[any, any, ...any[]]”的参数,但不影响我们使用。

六、表达式与循环

1、箭头表达式

用来声明匿名函数,消除传统匿名函数的this指向问题。

var sum = (arg1,arg2) => arg1+arg2;这就是最简单的一行箭头表达式。如果返回值只有一行的话可以省略{}也不需要写return方法。如果是多行的话是需要写{}的。

var sum = () => {}如果没有参数的话是这样的写法。

var sum = arg => {return arg}如果只有一个参数的话圆括号都可以省略。

例子:

  1. var myArray = [1,2,3,4,5,6];
  2. console.log(myArray.filter(value => value%2 == 0))
  3. //filter()是过虑的意思,()里面放的是表达式,如果取余2==0的话就返回,会得到[2,4,6]。

箭头表达式最大的好处this指向:

  1. function get(name:string) {
  2. this.name = name;
  3. // setInterval(function () {
  4. // console.log("name is"+this.name);
  5. // //什么都得不到因为this指向的是window
  6. // }, 1000);
  7. setInterval(() => {
  8. console.log("name is " + this.name);
  9. //跟想得到的是一样的,因为this是它所处的上下文
  10. }, 1000);
  11. }
  12. var stock = new get("huo");

2、循环

1、forEach

2、for...in...

3、for...of...


七、面向对象特性

1、类(class)

类是TypeScript的核心,使用TypeScript开发时,大部分代码都是写在类里面的。

这里会介绍类的定义,构造函数,以及类的继承。

  1. class People {//TypeScript声明类的方法
  2. name;//属性
  3. getName(){//方法
  4. console.log("huoqingchi");
  5. }
  6. //类拥有属性和方法
  7. }
  8. var p1 = new People();//我们通过new实例化了这个类,且赋值给了p1
  9. p1.name = "rope";
  10. p1.getName();
  11. //同样一个类我们可以new出多个实例,且这些实例都拥有相同的属性和方法,但是状态不同。
  12. var p2 = new People();//我们可以在实例化一个类,且赋值给了p2
  13. p2.name = "scarf";
  14. p2.getName();

访问控制符

管理类的属性和方法可以在哪里调用,一共有三个,且带声明效果。

1、public
  1. class People {
  2. public name;
  3. public getName(){
  4. console.log("huoqingchi");
  5. }
  6. //public的属性和方法都是可以在类的内部||类的外部访问的,它也是默认的,不写也可以。
  7. }
2、private

3、protected


类的构造函数

  1. class People {
  2. constructor(){//类的构造函数就是它,一个特殊的方法。
  3. //这个方法会在这个类实例化的时候被执行。
  4. console.log("hhh")
  5. }
  6. }
  7. var p1 = new People();//hhh

用处:实例化一个人的时候必须为他指定一个名字等等。。

  1. //第一种写法
  2. class People {
  3. name;//声明了一个name属性
  4. constructor(name:string){//这里接受实例化传来的值且设置参数类型
  5. this.name = name;//这里会访问上面声明的name属性且给他传入我们接收到的值
  6. };
  7. getName(){
  8. console.log(this.name);
  9. }
  10. }
  11. var p1 = new People("rope");//在这里实例化的时候给constructor传入一个值
  12. p1.getName();//rope
  1. //第二种写法
  2. class People {
  3. constructor(public name:string){//这里接受实例化传来的值且设置参数类型
  4. //这个写法会被People类创建一个name属性且把传入的值赋给它。
  5. //构造函数上需要明确的声明访问控制符
  6. };
  7. getName(){
  8. //如果构造函数中name没有声明访问控制符,People类里面也没有name属性。
  9. console.log(this.name);//所以这里是得不到的。
  10. }
  11. }
  12. var p1 = new People("rope");//在这里实例化的时候给constructor传入一个值
  13. p1.getName();//rope

类的继承

1、extends

通过extends关键字可以实现继承

这个时候Student实例化的p1身上也拥有了People的属性和方法。

在Student类中的属性和方法People的实例是没有的。


2、super

第一个用法:调用父类的构造函数

  1. class People {
  2. constructor(public name:string){
  3. //这里是被下面的super调用了。
  4. //这个写法会被People类创建一个name属性且把传入的值赋给它。
  5. console.log("People")
  6. };
  7. getName(){
  8. console.log(this.name);
  9. }
  10. }
  11. class Student extends People {
  12. constructor(name: string, public code:string){//实例化一个学生必须有名字和学号
  13. //这个写法会被Student类创建一个code属性且把传入的值赋给它。
  14. super(name);//通过super可以调用父类(People)的构造函数把name传过去了。
  15. console.log("Student")
  16. }
  17. getCode(){
  18. console.log(this.code);
  19. console.log(this.name)
  20. }
  21. }
  22. var p1 = new Student("huo","18")
  23. p1.getCode()

输出结果,注意顺序:

super调用People的构造函数→Student再执行→p1.getCode()再按顺序输出code和name。


第二个用法:可以调用父类的其他方法

  1. class People {
  2. mifan(){
  3. console.log("吃米饭");
  4. }
  5. }
  6. class Student extends People {
  7. chifan(){
  8. super.mifan();//直接通过super打点就可以调用父类的其他方法。
  9. this.xuexi();
  10. }
  11. private xuexi() {
  12. //这个方法本身是可以这在Student外部调用的,我想让他必须先吃饭再学习。
  13. //也就是只让他在Student内部被调用,所以给他设置了访问控制符。
  14. console.log("吃完米饭学习");
  15. }
  16. }
  17. var p1 = new Student();
  18. p1.chifan();

输出结果:


2、泛型

参数化的类型,一般来限制集合的内容。

  1. class People {
  2. constructor(public name:string){
  3. };
  4. }
  5. class Student extends People {
  6. constructor(name: string, public code:string){
  7. super(name);
  8. }
  9. }
  10. class Teacher extends People {
  11. constructor(name: string, public code: string) {
  12. super(name);
  13. }
  14. }
  15. var arr: Array<People> = [];//<>中就是规定我这个arr数组只能存放跟People类型一样的数据
  16. arr[0] = new Student("huo", "18");
  17. arr[1] = new Teacher("huoqingchi", "23");
  18. console.log(arr)

输出结果:

如果你存放其他类型的数据会有警告:


3、接口

用来建立某种代码约定,使得其它开发者在调用某个方法或创建新的类时必须遵循接口所定义的代码约定。

第一中用法:作为一个方法的参数类型的声明

  1. //使用interface 来声明一个接口
  2. interface jiekou {//接口的名字就交jiekou
  3. name:string;
  4. age:number;
  5. }
  6. class People{
  7. constructor(public consig: jiekou){//让接口作为一个方法的参数类型的声明
  8. }
  9. }
  10. var p1 = new People({
  11. //当你去调用这个方法的时候TypeScript会去检查你传过去的参数是否符合接口所约定的格式。
  12. name:"huoqingchi",
  13. age:18
  14. //参数不能多也不能少,如果没有值可以填null。
  15. })

第二种用法:用接口来声明方法。

  1. interface People {
  2. chi();//People接口有个吃饭的方法。
  3. }
  4. class Student implements People {
  5. //implements的意思是Student类实现People这个接口
  6. //也就是它必须实现这个接口里面的方法。
  7. chi(){
  8. console.log("我吃素的");
  9. }
  10. }
  11. class Teacter implements People {
  12. chi(){
  13. console.log("我吃肉的");
  14. }
  15. }

4、模块

模块可以帮助开发者将代码分割为可重用的单元。开发者可以自己决定将模块中的那些资源(类,方法,变量)暴露出去供外部使用,那些资源只能在模块内使用,一个文件就是一个模块

./demo/ide/tscript/test.ts

  1. export var a = 10;//export是暴露出去的意思。
  2. var b = 20;//没有暴露出去的就只能在这个模块中使用。
  3. export function fn1() {
  4. console.log("我是fn1")
  5. }
  6. function fn2() {
  7. console.log("我是fn2")
  8. }
  9. export class CLazz1 {
  10. constructor() {
  11. console.log("我是CLazz1类")
  12. }
  13. }
  14. class CLazz2 {
  15. constructor() {
  16. console.log("我是CLazz2类")
  17. }
  18. }

./demo/ide/tscript/test2.ts

  1. import { a, fn1, CLazz1} from './test';
  2. //import是导入的意思,from是从哪里导入,{}中是导入那些东西。
  3. console.log(a);
  4. console.log(fn1);
  5. console.log(CLazz1);
  6. //一个模块中既可以import导入也可以export
  7. export function fn3() {
  8. console.log("我是fn3")
  9. }

输出结果:


5、注解

注解为程序的元素(类,方法,变量)加上更直观明了的说明,这些说明信息与程序的业务逻辑无关,而是供指定的工具或框架使用的。

  1. import {Component} from '@angular/core';//这里是用的angular,后续会增加vue,react。
  2. @Component({//这里就是注解
  3. selector:'app-root',
  4. templaterUrl: './app.component.html',//加载到app.component.html页面中
  5. styleUrls:['./app.component.css']//加载app.component.css样式文件
  6. })
  7. export class AppComponent {//当你用angular加载这个类的时候它会执行上面的注解
  8. title = "app works!";
  9. }

app.component.html

  1. <h1>{{title}}</h1><!--页面会显示app works!-->

6、类型定义文件(*.d.ts)

类型定义文件用来帮助开发者在TypeScript中使用已有的JavaScript的工具包如:JQuery;

我们使用了typingsnpm install -g typings

./demo/ide在项目文件夹下。

打开CMD窗口运行typings install dt~jquery --global//这里是jquery举例,如果需要其它的记得更换。

其中”dt~”为使用DefinitelyTyped类型定义的意思,vscode可以识别这种定义。

没有安装之前:

安装之后:会自动生成typings文件夹


结束语

TypeScript的基础知识点我们就讲完了,后续根据反馈再整理更新。

TypeScript的文档:http://www.typescriptlang.org/docs/home.html

本人的博客:https://www.cnblogs.com/rope/

本人的github:https://github.com/mufengsm

本人的邮箱:scarf666@163.com

作者:Rope

TypeScript 基础知识点整理的更多相关文章

  1. HTML&&CSS基础知识点整理

    HTML&&CSS基础知识点整理 一.WEB标准:一系列标准的集合 1. 结构(Structure):html 语言:XHTML[可扩展超文本标识语言]和XML[可扩展标记语言] 2. ...

  2. 【Android 面试基础知识点整理】

    针对Android面试中常见的一些知识点整理,Max 仅仅是个搬运工.感谢本文中引用文章的各位作者,给大家分享了这么多优秀文章.对于当中的解析,是原作者个人见解,有错误和不准确的地方,也请大家积极指正 ...

  3. Python基础知识点整理(详细)

    Python知识点整理(详细) 输出函数 print()可以向屏幕打印内容,或者在打开指定文件后,向文件中输入内容 输入函数 input([prompt])[prompt] 为输入的提示字符.该函数返 ...

  4. python 基础知识点整理 和详细应用

    Python教程 Python是一种简单易学,功能强大的编程语言.它包含了高效的高级数据结构和简单而有效的方法,面向对象编程.Python优雅的语法,动态类型,以及它天然的解释能力,使其成为理想的语言 ...

  5. PHP初入,基础知识点整理(样式表&选择器的使用整理)

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  6. java基础知识点整理

    1.&和&&的区别? &:逻辑与(and),运算符两边的表达式均为true时,整个结果才为true. &&:短路与,如果第一个表达式为false时,第二 ...

  7. python基础知识点整理

    序列 描述 sequence(序列)是一组有顺序的元素的集合.序列可以包含一个或多个元素,也可以没有任何元素.我们之前所说的基本数据类型,都可以作为序列的元素. 序列有两种:tuple(定值表: 也有 ...

  8. C语言基础知识点整理(函数/变量/常量/指针/数组/结构体)

    函数 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ...

  9. java某些基础知识点整理

    1. \n换行 \r回车 \"双引号 \\反斜杠 2.Java语言提供了八种基本类型.六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型. byte: byte 数据类型是 ...

随机推荐

  1. FW/IDS/IPS/WAF等安全设备部署方式及优缺点

    现在市场上的主流网络安全产品可以分为以下几个大类:1.基础防火墙FW/NGFW类 主要是可实现基本包过滤策略的防火墙,这类是有硬件处理.软件处理等,其主要功能实现是限制对IP:port的访问.基本上的 ...

  2. android 第一次作业

    天气预报界面截图: 源码coding地址:https://coding.net/u/dsy1600802076/p/android/git/tree/master

  3. BZOJ 3622

    直接算 $a_i>b_i$ 对数恰为 $k$ 的不好算 那么可以先算 $a_i>b_i$ 对数至少 $k$ 的 这个排序后随便dp一下就好 那么再除了一下 用 $f_i$ 表示 $a_i& ...

  4. Android SQLite数据库升级,怎么做(事物更改)

    SQLiteOpenHelper // 如果数据库文件不存在,只有onCreate()被调用(该方法在创建数据库时被调用一次) public abstract void onCreate(SQLite ...

  5. TypeScript 函数-Lambads 和 this 关键字的使用

    let people = { name:["a","b","c","d"], /* getName:function() ...

  6. python中的双向链表实现

    引子 双向链表比之单向链表,多数操作方法的实现都没有什么不同,如is_empty, __len__, traverse, search.这些方法都没有涉及节点的变动,也就可通过继承单向链表来实现即可. ...

  7. 高精度乘法-17南宁区域赛F -The Chosen One

    题目大意:给你一个n,然后从1~n隔一个选一个,挑出一个集合然后从集合中继续隔一个挑一个,直到只有一个数,问最后一个数是多少?2<=n<=1050 例如n=5,先选出2,4最后选择4.n= ...

  8. 4.27Linux(5)

    2019-4-27 15:39:03 学了Linux好几天,发现Linux用着还是很爽 你一定要知道你要干啥!!!! 列一下参考博客: mysql博客地址:https://www.cnblogs.co ...

  9. 详解node + mongoDb(mongoDb安装、运行,在node中连接、增删改查)

    一.序言 好久没写博客了,这次主要聊聊 node 和 mongoDb . 先说明一下技术栈  node + express + mongoose + mongoDb.这篇博客,主要讲述 mongoDb ...

  10. pyhton 监听文件输入实例

    def tail(filename): f = open(filename,encoding='utf-8') while True: line = f.readline() if line.stri ...