弹出和隐藏进度条

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
private Dialog dialog;

private void showDialog(final Context ctx) {
if (ctx instanceof Activity) {
final Activity context = (Activity) ctx;
context.runOnUiThread(new Runnable() {
@Override
public void run() {
int spacing = Uscreen.dp2Px(context, 16);
LinearLayout layout = new LinearLayout(context);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layout.setLayoutParams(layoutParams);
layout.setGravity(Gravity.CENTER);
layout.setPadding(spacing, spacing, spacing, spacing);
// add ProgressBar
ProgressBar bar = new ProgressBar(context);
layout.addView(bar, layoutParams);

dialog = new Dialog(context, android.R.style.Theme_Holo_Dialog_NoActionBar);
dialog.setCancelable(false);
dialog.getWindow().setDimAmount(0.3f);
dialog.setContentView(layout);
dialog.show();
}
});
}

}

private void dismissDialog() {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
}

单个操作的 alert

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public class AlertOneItem {
private Context context;
private String title;
private String message;
private Consumer<Boolean> consumer;
private String positiveTips = "确定";
private String negativeTips = "取消";

private AlertOneItem(Context context, Consumer<Boolean> consumer) {
this.context = context;
this.consumer = consumer;
}

public static AlertOneItem builder(Context context, Consumer<Boolean> consumer) {
return new AlertOneItem(context, consumer);
}

public AlertOneItem title(String title) {
this.title = title;
return this;
}

public AlertOneItem message(String message) {
this.message = message;
return this;
}

public AlertOneItem positiveTips(String positiveTips) {
this.positiveTips = positiveTips;
return this;
}

public AlertOneItem negativeTips(String negativeTips) {
this.negativeTips = negativeTips;
return this;
}


public void show() {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
if (!TextUtils.isEmpty(title)) {
builder.setTitle(title);
}
if (!TextUtils.isEmpty(message)) {
builder.setMessage(message);
}
if (!TextUtils.isEmpty(negativeTips)) {
builder.setNegativeButton(negativeTips, (dialog, which) -> consumer.accept(false));
}

if (!TextUtils.isEmpty(positiveTips)) {
builder.setPositiveButton(positiveTips, (dialog, which) -> consumer.accept(true));
}

builder.setCancelable(true);
builder.create();
builder.show();
}
}
// 调用
Udialog.AlertOneItem.builder(context, result -> {
if (result) {
toSetWallpaperAsync(context, imageView, color);
}
}).message("设置成壁纸?").show();

多个操作的 alert (方案 1)

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
enum OperateType {
REFRESH("刷新"),
COPY_LINK("复制链接"),
COPY_MD_LINK("复制md链接"),
OPEN_WITH_BROWSER("在浏览器中打开"),
;
String title;

OperateType(String title) {
this.title = title;
}

public static OperateType indexOf(int index) {
return OperateType.values()[index];
}

public static String[] toStrArray() {
OperateType[] values = OperateType.values();
String[] result = new String[values.length];
for (int i = 0; i < values.length; i++) {
result[i] = values[i].title;
}
return result;
}
}

private void onMorePressed() {
new AlertDialog.Builder(mContext)
.setTitle("操作")
.setItems(OperateType.toStrArray(), (dialog, which) -> {
switch (OperateType.indexOf(which)) {
case REFRESH:
mWvContent.reload();
break;
case COPY_LINK:
copyToClipboard(mWvContent.getUrl(), "已复制到剪切板");
break;
case COPY_MD_LINK:
String title = mWvContent.getTitle();
String url = mWvContent.getUrl();
copyToClipboard("- [" + title + "]" + "(" + url + ")", "已复制到剪切板");
break;
case OPEN_WITH_BROWSER:
Uri uri = Uri.parse(mWvContent.getUrl());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
break;
default:
}
})
.create().show();
}

多个操作的 alert(方案 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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class AlertMultiItem {
private List<String> nameList = new ArrayList<>();
private List<Runnable> taskList = new ArrayList<>();
private Context context;
private String title;

private AlertMultiItem(Context context) {
this.context = context;
}

public static AlertMultiItem builder(Context context) {
return new AlertMultiItem(context);
}

public AlertMultiItem title(String title) {
this.title = title;
return this;
}

public AlertMultiItem add(String title, Runnable runnable) {
nameList.add(title);
taskList.add(runnable);
return this;
}

private String[] getItemNames() {
String[] result = new String[nameList.size()];
for (int i = 0; i < nameList.size(); i++) {
result[i] = nameList.get(i);
}
return result;
}

public void show() {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
if (!TextUtils.isEmpty(title)) {
builder.setTitle(title);
}
builder.setItems(getItemNames(), (dialog, which) -> taskList.get(which).run());
builder.create();
builder.show();
}
}

// 调用
Udialog.AlertMultiItem.builder(mContext)
.add("复制内容", () -> copyContent())
.add("复制全部", () -> copyAll())
.add("删除此项", () -> delete())
.show();

步骤

  1. 配置ndk路径
    ctrl+shift+alt+s,ndk location

  2. 配置app下 build.gradle

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 指定生成lib so文件的名称
    defaultConfig{
    ndk{
    moduleName "MyJniLib"
    }
    }
    // 指定jni路径
    sourceSets{
    main{
    jni.srcDirs = ['src/main/jni','src/main/jni/']
    }
    }
  3. 修改gradle.properties文件

    1
    android.userDeprecatedNdk=true
  4. 设置native接口

    1
    2
    3
    4
    5
    6
    7
    8
    package com.lyloou.secretjni;
    public class Ujni {
    static {
    System.loadLibrary("MyJniLib");//之前在build.gradle里面设置的so名字,必须一致
    }

    public static native String getSec(int type, int hashcode);
    }
  5. build项目,生成Ujni.class文件

  6. 通过Ujni.class文件生成头文件

    1
    javah -d jni -classpath MyProject/app/build/intermediates/classes/debug/com.lyloou.secretjni.Ujni
  7. 编写c文件
    将上一步骤生成的头文件,放在main/jni文件夹下
    另外新建一个cpp文件实现业务逻辑。

  8. 获取so文件
    编译运行后,在build/intermediates/ndk/debug/lib文件夹下得到一系列包含so文件的文件夹。

  9. 只需要保留so文件即可运行项目,jni文件备份起来吧。

参考资料

下载网络图片

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
// 第一步:根据流得到bitmap
// 方案1
Bitmap bitmap = Glide.with(applicationContext)
.load(url)
.asBitmap()
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.get();
// 方案2
Bitmap bitmap = BitmapFactory.decodeStream(new URL(url).openStream());

// 压缩图片
// bitmap = Bitmap.createScaledBitmap(bitmap, 120, 120, true);

// 第二步:保存成文件
// 保存图片
File imgDir = new File(getDiskCacheDir(applicationContext), "image_caches");
if (!imgDir.exists()) {
imgDir.mkdirs();
}
File imgFile = new File(imgDir, fileName);
fileOutputStream = new FileOutputStream(imgFile);
Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.PNG;
bitmap.compress(compressFormat, 100, fileOutputStream);
fileOutputStream.flush();

Glide预加载图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void preloadImage(Context context, AdZone adZone) {
for (AdZone.Item item : adZone.getItems()) {
new Thread(() -> {
try {
Glide.with(context.getApplicationContext())
.load(item.getPic())
.downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}).start();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Glide.with(getApplicationContext())
.load(pic)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(new GlideDrawableImageViewTarget(ivWelcome) {
@Override
protected void setResource(GlideDrawable resource) {
// https://github.com/bumptech/glide/issues/275
super.setResource(resource);

ivWelcome.setOnClickListener(v -> {
sendAdZoneItemBroadcast(item);
});
ivWelcome.setVisibility(View.VISIBLE);

// set countDown
toCountDown();
}

@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
super.onLoadFailed(e, errorDrawable);
}
});

主要介绍Android图片OutOfMemory异常bitmap size exceeds VM budget的原因及解决方法,顺带提及Dalvik heap size

面向对象设计原则

(单开里依接组迪:把面有 `花)

  1. 单一职责原则:设计目的单一的类;
  2. 开放封闭原则:对扩展开放,对修改关闭;
  3. 里氏(Liskov)替换原则:子类可以替换父类;
  4. 依赖倒置原则:要依赖抽象,而不是具体实现;针对接口编程,不要针对实现编程;
  5. 接口隔离原则:使用多个专门的接口,比使用一个单一的总接口好;
  6. 组合重用原则:要尽量使用组合,而不是继承关系达到重用的目的;
  7. 迪米特(Demeter)原则(最少知识法则):一个对象应该对其他对象有尽可能少的了解;

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
public class P66{
private static void main(String []args) {
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
Singleton.getInstance().doSth(); // ok, only create one instance
// Singleton.getInstance2().doSth(); // error, will create more than one instance
// Singleton.getInstance3().doSth(); // error, will create more than one instance, too
// Singleton.getInstance4().doSth(); // error, maybe cause NullPointerException
}).start();
}
}

private static class Singleton {
private static Singleton instance;
private static int count;

private Singleton() {
count = count + 1;
if (count > 0) {
System.out.println(count);
}
}

private void doSth() {
// do something
}

// double check
public static Singleton getInstance() {
if (instance == null) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}

public static Singleton getInstance2() {
if (instance == null) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton();
}
return instance;
}

public static Singleton getInstance3() {
if (instance == null) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}

public static Singleton getInstance4() {
if (instance == null) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}

if (count > 0) {
return instance;
} else {
instance = new Singleton();
}
}
return instance;
}
}
}

HTTP The Definitive Guide 读书笔记

逆序记录

| Status –p59

  • 100-199: Informational Status Codes
  • 200-299: Success Status Codes
  • 300-399:Redirection Status Codes

| The TRACE method is used primarily for diagnostics;
It’s also a good tool for seeing the effects of proxies and other applications
on your requests. –p56

| The TRACE method allows clients to see how its request looks when it finally
makes it to the server. –p55

| PUT:
Because PUT allows you to change content, many web servers require you to log in
with a password before you can perform a PUT. –p55

| HEAD METHOD:
The HEAD method behaves exactly like the GET method, but the server returns
only the headers in the response. No entity body is ever returned.
Using HEAD, you can:

  • Find out about a resource without getting it.
  • See if an object exists, by looking at the status code of the response.
  • Test if the resource has been modified, by looking at the headers.
  • -p54

| The GET and HEAD methods are said to be safe, meaning that no action should
occur as a result of an HTTP request that uses either the GET or HEAD method.
–p53

| HTTP mesages can carry many kinds of digital data: –p52

  • images;
  • video;
  • HTML documents;
  • software applications;
  • credit card transactions;
  • electronic mail;

| HTTP headers are classified into: –p51

  • General headers;
  • Request headers;
  • Response headers;
  • Entity headers;
  • Extension headers;

| Version:
Note that version numbers are not treated as fractional numbers.
Each number in the version is treated as a separate number.
HTTP/2.22 > HTTP/2.3, because 22 > 3

| The numeric code makes error processing easy for programs, while the reason
phrase is easily understood by humans.(这样的存在总是有意义的)
status_code

| The method begins the start line of requests, telling the server what to do.
–p48

  • GET
  • POST
  • PUSH
  • DELETE
  • HEAD
  • TRACE
  • OPTIONS
    HTTP method

| The headders are terminated by a blank line (CRLF), marking the
end of the list of headers and the beginning of the entity body.
–p47

| messages –p46
request message:

1
2
3
4
<method> <request-URL> <version>
<headers>

<entity-body>

response message:

1
2
3
4
<version> <status> <reason-phrase>
<headers>

<entity-body>

| Both request and response messages have the same basic message structure.
(start line; headers; body) –pp45

| The Parts of a Message: –p44

  • a start line describing the message;(Start line)
  • a block of headers containing attributes; (Headers)
  • an optional body containing data. (Body)

| HTTP messages flow like rivers. All messages flow downstream,regardless of
whether they are request messages or response messages.(所有的消息流都downstream)
The sender of any message is upstream of the receiver.
在图3-2中,代理1是代理3请求的上流,回应的下流。 –p44

| Messages travel inbound to the origin server, and when their work is done,
they travel outbound back to the user agent. –p43

| Describe message direction: –p43

  • inbound
  • outbound
  • upstream
  • downstream

| HTTP messages are the blocks of data sent between HTTP applications (clients,
servers, and proxies). These blocks of data begin with some text meta-information
describing the message contents and meaning, followed by optional data. –p43

| The chapter 3 aim to: –p43

  • how to create them;
  • how to understand them;

If HTTP is the Internet’s courier, HTTP messages are the packages it uses
to move things around. –p43

CHAPTER 3: HTTP Messages

| https: The https scheme is a twin to the http scheme. The only difference is
that the https scheme uses Netscape’s Secure Sockets Layer (SSL), which provides
end-to-end encryption of HTTP connnections. Its syntax is idential to that of
HTTP, with a default port of 443. –p38

| In general, applications interpreting URLs must decode the URLs before
processing them. –p37

| 字符限制(Character Restrictions):有些字符是保留的,是有特殊意义的,
不允许直接在URL中使用。(例如:% / . # ? ; : % + @ & = { } [ ] ~ < >)–p36

| Encoding Mechanisms –p36

  • %7E == ~
  • %20 == [space]
  • %25 == %
  • %40 == -

| Shady Characters
nonprinting characters also are prohibited in URLs, even though these characters
may pass through mailers and otherwise be portable. –p35

| Expandomatic URLs –p34
two flavors:

  • Hostname expansion.(eg. if you type “yahoo” in the address, your browser
    can automatically insert “www.” and “.com” onto the hostname)
  • History expansion.(eg. if you were typing in the start of a URL that
    you had visited previously, such as http://www.joes- your browser
    could suggest http://www.joes-hardware.com)
    Note: Be aware that URL auto-expansion may behave differently when used with proxies.

| Using this URL as a base, we can infer the missing information. –p32

| Fragments (): To allow referencing of parts or fragments of a resource,
URLs support a frag component to identify pieces within a resource. –p30
(精确定位到文档具体位置,这个过程在 client 端进行,而不是 server 端。
the server sends the entire object and the agent applies the fragment
identifier to the resource)

| Query component: There is no requirement for the format of the query component, except that some
characters are illegal.(查询组件对格式没有要求,但必须是合法的字符) –p29
跟在 ? 后面的名值对,多个查询条件用 & 分割:?item=12731&color=blue

| Auery Strings:
Some resources, such as database services, can be asked questions or queries to
narrow down the type of resource being requested. –p29

| If an application is using a URL scheme that requires a username and password,
such as FTP, it generally will insert a default username and password if
they aren’t supplied. –p27

| Scheme names are case-insensitive –p27
(Scheme的名字不区分大小写:例如http://HTTP://是等效的)

| The scheme is really the main identifier of how to access a given resource.
–p27

| Most URL schemes base their URL syntax on this nine-part general format: –p26

1
2
3
4
-------------------------------------------------------------------------
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
-------------------------------------------------------------------------
eg. http://www.joes-hardware.com:80/index.html

| Urls give you and your browser all you need to find a piece of
information. They define the particular resource you want,
where it is located, and how to get it.

| URL Component

CHAPTER 2: URLs and Resources

| Agents
User agents (or just agents) are client programs that make HTTP requests on the
user’s behalf. (用来发出HTTP请求的客户端程序,例如:web浏览器) –p19

| Tunnels
HTTP tunnels are often used to transport non-HTTP data over one or more HTTP
connections, without looking at the data. –p19

| Gateways

| Caches

| Proxies
A proxy sits between a client and a server.
Proxies are often used for security, acting as trusted intermediaries
through which all web traffic flows. –p18

Architectrual Components of the Web

| Protocol Versions –p16
HTTP/0.9 supports only the GET method.
1.0 was the first version of HTTP that was widely deployed.

| An HTTP transaction using telnet:

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
[root@localhost ~]# telnet www.lyloou.com 80
Trying 151.101.192.133...
Connected to www.lyloou.com.
Escape character is '^]'.
GET /index.html HTTP/1.1 # input this
Host: www.lyloou.com # input this
# input this

HTTP/1.1 301 Moved Permanently
Server: GitHub.com
Content-Type: text/html
Location: http://lyloou.com/index.html
X-GitHub-Request-Id: 26A4:06EC:8E05E6C:B479C11:58CB8810
Content-Length: 178
Accept-Ranges: bytes
Date: Fri, 17 Mar 2017 06:54:08 GMT
Via: 1.1 varnish
Age: 0
Connection: keep-alive
X-Served-By: cache-lax8651-LAX
X-Cache: MISS
X-Cache-Hits: 0
X-Timer: S1489733648.903540,VS0,VE68
Vary: Accept-Encoding
X-Fastly-Request-ID: b8d3f5bbb2343450fd125b92f1dde483c5109377

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>

| Telnet is commonly used for remote terminal sessions, but it can
generally connect to any TCP server, including HTTP servers.

| Establish a TCP/IP connection between the client and server:

  • Internet protocol (IP) addresses
  • Port numbers

| TCP/IP
Once a TCP connections is established, messages exchanged between the client and
server computers will never be lost, damaged, or received out of order. –p12

| HTTP messages consist of three parts: –p11

  1. Start line; (indicating what to do for a request and what happened for a
    response)
  2. Header fields; (Note: The headers end with a blank line)
  3. Body; (can contain arbitray binary data. eg., images, videos, audio tracks,
    software applications.)

| Messages

  • request messages: sent from web clients to web servers.
  • response messages: messages from servers to clients.
    they are very similar.

| Status Codes
Every HTTP response message comes back with a status code. –p9

| Methods
The method tells the server what action to perform (e.g. fetch a web page,
delete a file, etc.) –p8

  • GET
  • POST
  • DELETE
  • PUT
  • HEAD

| Transactions
An HTTP transaction consists of: –p8

  • a request command (sent from client to server).
  • a response result (sent from the server back to the client)

| URNs
A URNs serves as a unique name for a particular piece of content,
independent of where the resource currently resides.
URNs are still experimental and not yet widely adopted. –p7

| URLs
URLs describe the specific location of a resource on a particular server.
contains three main parts: –p7

  • scheme: (e.g., http://)
  • server Internet address (e.g., www.lyloou.com)
  • names a resource on the web server (e.g., hello.gif)

| URIs
URIs come in two flavors: URLs and URNs.

| Media Types
MIME was originally designed to solve problems encountered in moving messages
between different electronic mail systems.
MIME worked so well for email that HTTP adopted it to describe and label its
own multimedia content. –p5
eg.

| Resources

  • static file: text files, HTML files, Word files, JPEG files, AVI…
  • dynamic content: generate content based on your identity, on what
    information you’ve requested, or on the time of day.(eg. show live image
    from a camera, trade stocks, search databases, buy gifts from online
    stores)

| Because HTTP uses reliable data-transmission protocols, it guarantees that
your data will not be damaged or scrambled in transit, even when it comes from
the other side of the globe. –p3

| Throughout the book, we are careful to explain the “why” of HTTP, not just the
“how”.

| There are many books that explain how to use Web,
but this is the book that explains how the Web works.

| The Definitive Guide is in understanding how the Web works
and how to apply that knowledge to web programming and administration.

| crypto模块:提供通用的加密和哈希算法。

| 服务器案例(模块http、path、fs的运用):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
'use strict'

var http = require("http");
var path = require("path");
var fs = require("fs");

var server = http.createServer(function(request, response) {
var workDir = path.resolve("."); // 获取当前目录
var filepath = path.join(workDir, "showdate.html"); // 定位showdate.html文件

// 将本地的文件作为响应返回
response.writeHead(200);
fs.createReadStream(filepath).pipe(response);
});

server.listen(3000);
console.log("服务已开启,请登录:http://localhost:3000");

| pipe

1
2
3
4
var fs = require("fs");
var rs = fs.createReadStream("hello.js");
var ws = fs.createWriteStream("copy.js");
rs.pipe(ws);

| stream 是node.js提供的仅在服务端可用的模块;
基于事件的、异步的方式:

1
2
3
4
5
var fs = require("fs");
var rs = fs.createReadStream("hello.js", "utf-8");
rs.on("data", f);
rs.on("end", f);
rs.on("error", f);

| 同步的写文件:fs.writeFileSync()

| 写文件:fs.writeFile("output.txt", data, function(x){}),如果data是String,默认
编码是UTF-8;如果传入的是Buffer,则写入的是二进制文件;回调函数只关心成功与否。

| 同步读文件使用fs.readFileSync()方法,不接受回调函数,函数直接返回结果。
通过try...catch来捕获同步获取文件时的错误。

| Buffer对象可以和String做转换:

1
2
3
4
5
6
// Buffer -> String
var text = data.toString("utf-8");
console.log(text);
// String -> Buffer
var buf = new Buffer(text, "utf-8");
console.log(buf);

| fs模块

  • 读取文件编码是utf-8的文件;
    1
    2
    var fs = require("fs");
    fs.readFile("hello.js", "utf-8", console.log);
  • 读取二进制文件,不传入文件编码,回调函数将返回一个Buffer对象。
    1
    fs.readFile("hello.js", console.log);

| 在需要使用回调函数的地方,传入console.log,可以打印出回调函数的参数信息。

| 建议始终使用module.exports的方式,而不是省写的exports

| 如果要输出一个键值对象{},可以利用exports这个已经存在的空对象{}
并继续在上面添加新的键值;

var exported = load(module.exports, module);
因为对exports重新赋值,对module.exports没有任何副作用。

如果要输出一个函数或数组,必须直接对module.exports对象赋值;

| 实现“模块”功能的奥妙就在于JavaScript是一种函数式编程语言,它支持闭包。

| 引入的对象具体是什么,取决于引用模块输出的变量。(输出的变量可以是任意对象、函数、数组等等)

| 一个模块想要对外暴露变量(函数也是变量),可以用module.exports = variable;
一个模块想要引用其他模块暴露的变量,用var ref = require('module_name')就拿到了引用模块变量;

| 使用模块的好处:

  • 提高了代码的可维护性;
  • 代码重用;
  • 避免了函数名和变量名冲突;

| 在Node环境中,一个.js文件就称之为一个模块(module)。

| 让node直接为所有js文件都开启严格模式:

1
node --use_strict myFile.js

http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000

0%