a blog base on github issue
endday / blog Goto Github PK
View Code? Open in Web Editor NEWa blog base on github issue
a blog base on github issue
登录远程服务器,Ubuntu环境
apt-get update
apt-get upgrade
删除软件及其配置文件
apt-get --purge remove <包名>
删除没用的依赖包
apt-get autoremove <包名>
列出已安装的含有该名称的包
dpkg --get-selections | grep <包名>
apt-get install mysql-server
这个包已经包含了mysql-common,mysql-client,mysql-server
mysql mysql 客户端
mysql-devel 开发用到的库以及包含文件
mysql-server 数据库服务器
netstat -tap | grep mysql
检查是否安装成功
启动:service mysql start
停止:service mysql stop
重启:service mysql restart
查看状态:service mysql status
查看状态:systemctl status mysql.service
我看很多教程基于centos,和ubuntu不同,大部分教程都是service mysqld start
我这里尝试了,用mysql才行,不是mysqld,应该是版本问题
mysql -u root -p
-u 表示选择登陆的用户名, -p 表示登陆的用户密码,上面命令输入之后会提示输入密码,此时输入密码就可以登录到mysql
通过 show databases; 就可以查看当前的数据库
记得要加 ; 分号结束语句
如果你打命令时,回车后发现忘记加分号,你无须重打一遍命令,只要打个分号回车就可以了。
也就是说你可以把一个完整的命令分成几行来打,完后用分号作结束标志就OK
CREATE USER 'user_name'@'host' IDENTIFIED BY 'password';
user_name:要创建用户的名字。
host:表示要这个新创建的用户允许从哪台机登陆,如果只允许从本机登陆,则 填 ‘localhost’ ,如果允许从远程登陆,则填 ‘%’
password:新创建用户的登陆数据库密码,如果没密码可以不写。
例子:CREATE USER 'endday'@'%' IDENTIFIED BY '123456';
创建一个名称为endday的用户,允许远程登录,密码为123456
我用的是navicat
1、用ssh连接登录服务器,在本地登录数据库
主机如上,localhost,端口为mysql默认的3306,帐号为你数据库的帐号
这里就按照正常ssh连接的方式,主机填写远程服务器的公网地址,用户名是远程服务器帐号
主机填写远程服务器的公网地址,用户名是刚刚在数据库新建的允许远程连接的帐号
或者你自己将已有的帐号的权限改为允许远程连接
如果你遇到这个提示,2003 – Can't connect to MySQL server on ‘ubuntu'(10061)
那是因为mysql默认绑定了本地地址
编辑这个配置文件 /etc/mysql/mysql.conf.d/mysqld.cnf
# bind-address = 127.0.0.1
注释掉这行配置
重启mysql
service mysql restart
JavaScript中有六种基本数据类型(也叫做简单数据类型)
分别为:undefined、null、boolean、number、string、symbol(es6新增);
另外还含有一种复杂的数据类型:object.
1.基本数据类型值是指简单的数据段,五种基本类型都是按值访问的(可以操作保存在变量中的实际值);
2.基本类型的值在内存中占据固定大小的空间,被保存在栈内存中。(从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本);
3.不能给基本类型的值添加属性。
1.引用类型值是指那些可以由多个值构成的对象。js不允许直接访问内存中的位置,也就是不能直接访问操作对象的内存空间,在操作对象时,实际上是在操作对象的引用而不是实际的对象;
2.引用类型的值是对象,保存在堆内存中,包含引用类型值的变量实际上包含的并不是对象本身,而是指向该对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终指向同一个对象。
3.对于引用类型的值,可以为其添加属性和方法,也可以改变和删除其属性和方法。
浮动的定义:使元素脱离文档流,按照指定方向发生移动,遇到父级边界或者相邻的浮动元素停了下来。
高度塌陷:浮动元素父元素高度自适应(父元素不写高度时,子元素写了浮动后,父元素会发生高度塌陷)
因为浮动会脱离文档流,使高度自适应的父元素高度塌陷,这样就会让布局错乱,所以在必要的时候需要清除浮动,让后面的元素能够正常布局,不会和浮动的元素相重叠。
一般会用到clear样式
clear:left | right | both | none | inherit // 元素的某个方向上不能有浮动元素
clear:both // 在左右两侧均不允许浮动元素。
{clear:both;height:0;overflow:hidden;}
给浮动元素父级设置高度
以浮制浮(父级同时浮动)
嗯,这算是个基本没人用的蛋疼方法
{display: inline-block}
这就用到了bfc了
<div class="box">
<div class="top"></div>
<br clear="both" />
</div>
br 标签自带clear属性,将它设置成both其实和添加空div原理是一样的。
{overflow:hidden}
这也是用了bfc了
.clear:after{content:'';display:block;clear:both;height:0;overflow:hidden;visibility:hidden;}
.clear{zoom:1;}
const fs = require('fs')
const filePath = '../component/twoEggs/index.vue'
function replace (str) {
var reg = /.?(\d)+(\.\d+)?(rem)/gi
var arr = str.match(reg)
for (let i = 0, len = arr.length; i < len; i++) {
const item = arr[i]
const num = Number(item.slice(0, item.length - 3))
let replaceNum = num * 20000 / 100 + 'px'
if (arr[i].length <= replaceNum.length) {
replaceNum = ` ${replaceNum} `
}
str = str.replace(arr[i], replaceNum)
}
return str
}
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) throw err
const formatData = replace(data)
fs.writeFile(filePath, formatData, 'utf8', (err) => {
if (err) throw err
console.log('文件已保存')
})
})
日常业务可以只用@babel/preset-env(提供语法转译,也提供全局的原型链的polyfill)
useBuiltIns:false,即关闭polyfill
库模式使用@babel/plugin-transform-runtime (提供局部、按需加载的polyfill)
已经在 @babel/preset-env 中配置了polyfill,那么你连 @babel/plugin-transform-runtime 都是不必要的(他们二者都可以提供ES新API的垫片,在这一项功能上是重复的。@babel/preset-env 除了提供 polyfill 垫片,还提供 ES 新语法的转译,这一点 @babel/plugin-transform-runtime 做不了;@babel/preset-env 提供的polyfill垫片会污染原型链,这个既是缺点,也是优点,缺点是在开发第三方 JS 库时不能这么干,会影响使用方的代码,优点是在开发自己的web应用时,一劳永逸,而 @babel/plugin-transform-runtime 不会污染原型链,且按需加载;@babel/preset-env 在提供 polyfill 垫片时,是既可以按需也可以不按需,取决于使用者怎么配置 useBuiltIns 参数及是否 import 了垫片),简单推荐一下:@babel/preset-env 可以搞定你的所有事情,配置 useBuiltIns 并按规则导入 polyfill,不必使用 @babel/plugin-transform-runtime;如果是开发 js 库,才用 @babel/plugin-transform-runtime,同时使用 @babel/preset-env 去转译语法,但不用它的 polyfill(如这篇文章里推荐的那样去配置即可)
import { defineConfig } from 'vite'
import vue2 from '@vitejs/plugin-vue2'
import { getBabelOutputPlugin } from '@rollup/plugin-babel'
// https://vitejs.dev/config/
export default defineConfig(() => ({
resolve: {
extensions: ['.vue', '.js', '.jsx', '.ts', '.tsx', '.cjs', '.mjs']
},
plugins: [
vue2()
],
build: {
rollupOptions: {
external: [
// 要将@babel/runtime-core的依赖包排除掉
// 并将@babel/runtime-corejs3声明到dependencies中
/@babel\/runtime-core/
],
plugins: [
getBabelOutputPlugin({
babelrc: false,
configFile: false, // 不加载外部的 babel 配置
presets: [
[
'@babel/preset-env',
{
targets: { browsers: ['last 2 versions', 'ie >= 11'] },
// 用了@babel/plugin-transform-runtime
// 就不要用preset-env来处理polyfill
useBuiltIns: false, // 此选项配置 @babel/preset-env 如何处理 polyfill
// 不用转
modules: false // 启用将 ES 模块语法转换为另一种模块类型
}
]
],
plugins: [
[
'@babel/plugin-transform-runtime',
{
corejs: {
version: 3,
proposals: true // 是否加入polyfill提案
},
helpers: true, // 切换内联 Babel 助手(classCallCheck、extends 等)是否替换为对 moduleName 的调用。
// 切换生成器函数是否转换为使用不污染全局作用域的再生器运行时。
regenerator: true // defaults to true
}
]
]
})
]
}
}
}))
{
"dependencies": {
"@babel/runtime-corejs3": "^7.24.0"
},
"devDependencies": {
"@babel/plugin-transform-runtime": "^7.24.0",
"@babel/preset-env": "^7.24.0",
"@rollup/plugin-babel": "^6.0.4"
}
}
防止手机中网页放大和缩小
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" />
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" />
同源:两个文档同源需满足
跨域通信:js进行DOM操作、通信时如果目标与当前窗口不满足同源条件,浏览器为了安全会阻止跨域操作。跨域通信通常有以下方法
如果是log之类的简单单项通信,新建,<script>,,<iframe>元素,通过src,href属性设置为目标url。实现跨域请求
如果请求json数据,使用<script>进行jsonp请求
现代浏览器中多窗口通信使用HTML5规范的targetWindow.postMessage(data, origin);其中data是需要发送的对象,origin是目标窗口的origin。window.addEventListener('message', handler, false);handler的event.data是postMessage发送来的数据,event.origin是发送窗口的origin,event.source是发送消息的窗口引用
内部服务器代理请求跨域url,然后返回数据
跨域请求数据,现代浏览器可使用HTML5规范的CORS功能,只要目标服务器返回HTTP头部**Access-Control-Allow-Origin: ***即可像普通ajax一样访问跨域资源
// 写一个 machine 函数达到如下效果
function machine() {}
machine('ygy').execute();
// start ygy
machine('ygy')
.do('eat')
.execute();
// start ygy
// ygy eat
machine('ygy')
.wait(5)
.do('eat')
.execute();
// start ygy
// wait 5s(这里等待了5s)
// ygy eat
machine('ygy')
.waitFirst(5)
.do('eat')
.execute();
// wait 5s
// start ygy
// ygy eat
// 基于首次答案有微调
const defer = sec => new Promise(resolve => setTimeout(resolve, sec * 1000));
function machine(name) {
const tasks = [];
const initTask = () => {
console.log(`start ${name}`);
};
tasks.push(initTask);
function _do(str) {
const task = () => {
console.log(`${name} ${str}`);
};
tasks.push(task);
return this;
}
function wait(sec) {
const task = async () => {
console.log(`wait ${sec}s`);
await defer(sec);
};
tasks.push(task);
return this;
}
function waitFirst(sec) {
const task = async () => {
console.log(`wait ${sec}s`);
await defer(sec);
};
tasks.unshift(task);
return this;
}
function execute() {
tasks.reduce(async (promise, task) => {
await promise;
await task();
}, undefined);
}
return {
do: _do,
wait,
waitFirst,
execute,
};
}
const defer = sec => new Promise(resolve => setTimeout(resolve, sec * 1000));
function machine(name) {
const context = {};
const tasks = [];
const initTask = () => {
console.log(`start ${name}`);
};
tasks.push(initTask);
function _do(str) {
const task = () => {
console.log(`${name} ${str}`);
};
tasks.push(task);
return context;
}
function wait(sec) {
const task = async () => {
console.log(`wait ${sec}s`);
await defer(sec);
};
tasks.push(task);
return context;
}
function waitFirst(sec) {
const task = async () => {
console.log(`wait ${sec}s`);
await defer(sec);
};
tasks.unshift(task);
return context;
}
function execute() {
tasks.reduce(async (promise, task) => {
await promise;
await task();
}, undefined);
}
// 用 Object.freeze 来防止调用者修改内部函数,保障安全
return Object.freeze(
Object.assign(context, {
do: _do,
wait,
waitFirst,
execute,
})
);
}
作者:serialcoder
链接:https://juejin.im/post/5c92dfe7f265da60d428f119
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
创建文件夹【mkdir】
一、mkdir命令使用权限
所有用户都可以在终端使用 mkdir 命令在拥有权限的文件夹创建文件夹或目录。
二、mkdir命令使用格式
格式:mkdir [选项] DirName
三、mkdir命令功能
通过 mkdir 命令可以实现在指定位置创建以 DirName(指定的文件名)命名的文件夹或目录。要创建文件夹或目录的用户必须对所创建的文件夹的父文件夹具有写权限(了解Linux文件-文件夹权限请点击这里)。并且,所创建的文件夹(目录)不能与其父目录(即父文件夹)中的文件名重名,即同一个目录下不能有同名的(区分大小写)。
四、mkdir命令选项说明
命令中的[选项]一般有以下两种:
-m 用于对新建目录设置存取权限,也可以用 chmod 命令进行设置。
-p 需要时创建上层文件夹(或目录),如果文件夹(或目录)已经存在,则不视为错误。
五、mkdir命令使用举例
例一:在桌面下面创建以“demo”命名的文件夹。
使用以下命令即可。
mkdir 桌面/demo
例二:在桌面下面创建以“demo”命名的文件夹,并且给文件夹赋权限,权限为123。
mkdir 123 桌面/demo
删除文件夹【rm】
一、rm命令使用权限
所有用户都可以在终端使用 rm命令删除目录。
二、rm命令使用格式
格式:rm [选项] DirName
三、rm命令功能
删除档案及目录。
四、rm命令选项说明
命令中的[选项]一般有以下几种:
-i 删除前逐一询问确认。
-f 即使原档案属性设为唯读,亦直接删除,无需逐一确认。
-r 将目录及以下之档案亦逐一删除,递归所有的子目录,逐一询问。
五、rm命令使用举例
例一:删除所有C语言程序文档;删除前逐一询问确认。
rm -i *.c
例二:将 Finished 子目录及子目录中所有档案删除。
rm -r Finished
rm -f abc.txt的意思是说强制删除文件。如果文件不存在,也不要提示。这是因为如果直接使用rm abc.txt那么如果文件不存在,rm 会提示你。这在某些情况下,比如我们写一些小脚本,可能不需要他这样做。
rm -r abc 的意思是说递归所有的子目录。其中要求abc是一个目录名。这条rm运行后,abc目录下的所有子目录里的东西也会一同被删除。通常我们在删除一个目录时会使用rm -rf abc这样的形式,这就是说明删除目录abc,同时要求命令不要产生任何提示。
注:在linux没有回收站,在试用rm命令的时候,一定要小心些,删除之后就无法再恢复了。
创建文件【vi】
一、进入vi的命令
vi filename :打开或新建文件,并将光标置于第一行首
vi +n filename :打开文件,并将光标置于第n行首
vi + filename :打开文件,并将光标置于最后一行首
vi +/pattern filename:打开文件,并将光标置于第一个与pattern匹配的串处
vi -r filename :在上次正用vi编辑时发生系统崩溃,恢复filename
vi filename....filename :打开多个文件,依次进行编辑
二、移动光标类命令
h :光标左移一个字符
l :光标右移一个字符
space:光标右移一个字符
Backspace:光标左移一个字符
k或Ctrl+p:光标上移一行
j或Ctrl+n :光标下移一行
Enter :光标下移一行
w或W :光标右移一个字至字首
b或B :光标左移一个字至字首
e或E :光标右移一个字至字尾
) :光标移至句尾
( :光标移至句首
}:光标移至段落开头
{:光标移至段落结尾
nG:光标移至第n行首
n+:光标下移n行
n-:光标上移n行
n$:光标移至第n行尾
H :光标移至屏幕顶行
M :光标移至屏幕中间行
L :光标移至屏幕最后行
0:(注意是数字零)光标移至当前行首
$:光标移至当前行尾
三、屏幕翻滚类命令
Ctrl+u:向文件首翻半屏
Ctrl+d:向文件尾翻半屏
Ctrl+f:向文件尾翻一屏
Ctrl+b;向文件首翻一屏
nz:将第n行滚至屏幕顶部,不指定n时将当前行滚至屏幕顶部。
四、插入文本类命令
i :在光标前
I :在当前行首
a:光标后
A:在当前行尾
o:在当前行之下新开一行
O:在当前行之上新开一行
r:替换当前字符
R:替换当前字符及其后的字符,直至按ESC键
s:从当前光标位置处开始,以输入的文本替代指定数目的字符
S:删除指定数目的行,并以所输入文本代替之
ncw或nCW:修改指定数目的字
nCC:修改指定数目的行
五、删除命令
ndw或ndW:删除光标处开始及其后的n-1个字
do:删至行首
d$:删至行尾
ndd:删除当前行及其后n-1行
x或X:删除一个字符,x删除光标后的,而X删除光标前的
Ctrl+u:删除输入方式下所输入的文本
六、搜索及替换命令
/pattern:从光标开始处向文件尾搜索pattern
?pattern:从光标开始处向文件首搜索pattern
n:在同一方向重复上一次搜索命令
N:在反方向上重复上一次搜索命令
:s/p1/p2/g:将当前行中所有p1均用p2替代
:n1,n2s/p1/p2/g:将第n1至n2行中所有p1均用p2替代
:g/p1/s//p2/g:将文件中所有p1均用p2替换
七、vi命令使用举例
例一:创建文件a.txt。
vi a.txt
Hello everyone!
:wq //在退出时,直接输入:wq会发现退不出去,退出方法是:编辑完成后按ESC,然后输入:q就是退出;还有:wq是保存后退出,加感叹号是表示强制
修改档案时间【touch】
一、touch命令使用权限
所有用户都可以在终端使用 touch命令。
二、touch命令使用格式
格式:touch [-acfm][-d <日期时间>][-r <参考文件或目录>][-t <日期时间>][--help] [--version][文件或目录...] 或 touch [-acfm][--help][--version][日期时间][文件或目录...]
(touch [-acfm][-r reference-file] [--file=reference-file][-t MMDDhhmm[[CC]YY][.ss]][-d time] [--date=time][--time={atime,access,use,mtime,modify}][--no-create][--help] [--version]file1 [file2 ...])
三、touch命令功能
touch fileA,如果fileA存在,使用touch命令可更改这个文件或目录的日期时间,包括存取时间和更改时间;如果fileA不存在,touch命令会在当前目录下新建一个空白文件fileA。
注:使用touch指令可更改文件或目录的日期和时间,包括存取时间和更改时间。文件的时间属性包括文件的最后访问时间,最后修改时间以及最后在磁盘上修改的时间,命令stat显示结果显示了三个时间属性。
四、touch命令选项说明
a 改变档案的读取时间记录。
m 改变档案的修改时间记录。
c 假如目的档案不存在,不会建立新的档案。与 --no-create 的效果一样。
f 不使用,是为了与其他 unix 系统的相容性而保留。
r 使用参考档的时间记录,与 --file 的效果一样。
d 设定时间与日期,可以使用各种不同的格式。
t 设定档案的时间记录,格式与 date 指令相同。[[CC]YY]MMDDhhmm[.SS],CC为年数中的前两位,即”世纪数”;YY为年数的后两位,即某世纪中的年数.如果不给出CC的值,则linux中touch命令参数将把年数CCYY限定在1969--2068之内.MM为月数,DD为天将把年数CCYY限定在1969--2068之内.MM为月数,DD为天数,hh 为小时数(几点),mm为分钟数,SS为秒数.此处秒的设定范围是0--61,这样可以处理闰秒.这些数字组成的时间是环境变量TZ指定的时区中的一个时间.由于系统的限制,早于1970年1月1日的时间是错误的.
--no-create 不会建立新档案。
--help 列出指令格式。
--version 列出版本讯息。
五、touch命令使用举例
例一:更新file1.txt的存取和修改时间。
touch file1.txt
例二:如果file1.txt不存在,不创建文件
touch -c file1.txt
例三:更新file1.txt的时间戳和ref+file相同
touch -r ref+file file1.txt
例四:设置文件的时间戳为2011年5月18日9点45分10秒
ls -l file1.txt
touch -t 1105190945.10 file1.txt
在新建文件时用touch命令可以建立一个空文件,而vi命令则可以直接编辑文件的内容并保存。touch命令在linux中很少用到,我个人还是比较喜欢vi命令,可以直接对文档进行编辑。
function timeFormat (date) {
if (!date || typeof (date) === 'string') {
throw Error('参数异常,请检查...')
}
var y = date.getFullYear() //年
var m = date.getMonth() + 1 //月
var d = date.getDate() //日
return y + '-' + m + '-' + d
}
function getMonthFirstDay () {
var date = new Date()
date.setDate(1)
return timeFormat(date)
}
function getMonthLastDay () {
var curDate = new Date()
var curMonth = curDate.getMonth()
curDate.setMonth(curMonth + 1)
curDate.setDate(0)
return timeFormat(curDate)
}
css.loli.net 推荐
https://ajax.loli.net https://ajax.google.net/
https://fonts.loli.net https://fonts.google.net
中科大
fonts.gstatic.com fonts-gstatic.proxy.ustclug.org
fonts.googleapis.com fonts.proxy.ustclug.org
ajax.googleapis.com ajax.proxy.ustclug.org
浏览器缓存分为强缓存和协商缓存:
1 强缓存:浏览器在加载资源时,先根据这个资源的一些http header判断它是否命中强缓存,强缓存如果命中,浏览器直接从自己的缓存中读取资源,不会发请求到服务器。比如某个css文件,如果浏览器在加载它所在的网页时,这个css文件的缓存配置命中了强缓存,浏览器就直接从缓存中加载这个css,连请求都不会发送到网页所在服务器;
2 协商缓存:当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,通过服务器端依据资源的另外一些http header验证这个资源是否命中协商缓存,如果协商缓存命中,服务器会将这个请求返回(304),但是不会返回这个资源的数据,而是告诉客户端可以直接从缓存中加载这个资源,于是浏览器就又会从自己的缓存中去加载这个资源;若未命中请求,则将资源返回客户端,并更新本地缓存数据(200)。
强缓存与协商缓存区别:强缓存不发请求到服务器,协商缓存会发请求到服务器。
浏览器缓存分为:强缓存和协商缓存。
浏览器加载资源时,第一步先判断它是否是强缓存,如果是,浏览器将直接从自己的缓存中读取,不会向服务器发送请求。Alt text上图,status200,Size是from memory cache就是走的强缓存。那么什么是强缓存呢?浏览器又是咋判断的呢?
1、浏览器第一次向服务器请求,服务器返回资源并在response header加上Expires字段,是客户端缓存有效期,是绝对时间。2、浏览器接收资源,把资源和相应头缓存起来。3、待到再次请求这个资源时,先在缓存中找,找到了看Expires字段,判断是否过期。若没过期直接从缓存加载。若过期了,再向服务器请求。
但是绝对时间有时会有偏差,所以引出了Cache-Control。
1、浏览器第一次向服务器请求,服务器返回资源并在response header加上Cache-Control字段,也是缓存的有效期,但是是相对时间,比如:Cache-Control:max-age=56700000。2、浏览器接收资源,把资源和相应头缓存下来。3、待到浏览器再次请求这个资源时,先在缓存找,根据第一次的请求时间和Cache-Control相对时间算出过期时间。若没过期,直接从缓存加载。若过期了,再向服务器请求。
Cache-Control弥补了Expires的不足,更安全有效。
当浏览器判断不是强缓存,就会发向服务器发请求,判断是否是协商缓存。如果是,服务器会返回304Not Modified,浏览器从缓存中加载。那什么又是协商缓存呢?
1、浏览器第一次向服务器发请求,服务器返回资源并在response header加上Last-Modified字段,表示资源最后修改的时间。2、浏览器再次请求这个资源时,请求头会加上If-Modified-Since字段。若这两个字段一样,说明资源没有修改过,返回304Not Modified,浏览器从缓存中获取资源。若这两个字段不一样,说明资源修改过,服务器正常返回资源。
但有时候服务器上资源有变化,单最后修改时间没更新,则引出下面两个字段。
1、浏览器第一次向服务器请求,服务器返回资源并在response header上加ETag字段。表示资源本身,资源有变化,则该字段有变化。2、浏览器再次向服务器请求这个资源时,请求头携带If-None-Match字段。若这两个字段相同,则代表资源没有变化,服务器返回304Not Modified,浏览器从缓存中加载。若两个字段不同,证明资源有变动,服务器正常返回资源。
String.prototype.gblen = function() {
var len = 0;
for (var i=0; i<this.length; i++) {
if (this.charCodeAt(i)>127 || this.charCodeAt(i)==94) {
len += 2;
} else {
len ++;
}
}
return len;
}
function strlen(str){
var len = 0;
for (var i=0; i<str.length; i++) {
var c = str.charCodeAt(i);
//单字节加1
if ((c >= 0x0001 && c <= 0x007e) || (0xff60<=c && c<=0xff9f)) {
len++;
}
else {
len+=2;
}
}
return len;
}
var jmz = {};
jmz.GetLength = function(str) {
///<summary>获得字符串实际长度,中文2,英文1</summary>
///<param name="str">要获得长度的字符串</param>
var realLength = 0, len = str.length, charCode = -1;
for (var i = 0; i < len; i++) {
charCode = str.charCodeAt(i);
if (charCode >= 0 && charCode <= 128) realLength += 1;
else realLength += 2;
}
return realLength;
};
var l = str.length;
var blen = 0;
for(i=0; i<l; i++) {
if ((str.charCodeAt(i) & 0xff00) != 0) {
blen ++;
}
blen ++;
}
getBLen = function(str) {
if (str == null) return 0;
if (typeof str != "string"){
str += "";
}
return str.replace(/[^\x00-\xff]/g,"01").length;
}
本脚本适用环境
系统支持:CentOS 6+,Debian 7+,Ubuntu 12+
内存要求:≥128M
日期 :2018 年 06 月 01 日
关于本脚本
1、一键安装 Shadowsocks-Python, ShadowsocksR, Shadowsocks-Go, Shadowsocks-libev 版(四选一)服务端;
2、各版本的启动脚本及配置文件名不再重合;
3、每次运行可安装一种版本;
4、支持以多次运行来安装多个版本,且各个版本可以共存(注意端口号需设成不同);
5、若已安装多个版本,则卸载时也需多次运行(每次卸载一种);
友情提示:如果你有问题,请先阅读这篇《Shadowsocks Troubleshooting》之后再询问。
默认配置
服务器端口:自己设定(如不设定,默认从 9000-19999 之间随机生成)
密码:自己设定(如不设定,默认为 teddysun.com)
加密方式:自己设定(如不设定,Python 和 libev 版默认为 aes-256-gcm,R 和 Go 版默认为 aes-256-cfb)
协议(protocol):自己设定(如不设定,默认为 origin)(仅限 ShadowsocksR 版)
混淆(obfs):自己设定(如不设定,默认为 plain)(仅限 ShadowsocksR 版)
备注:脚本默认创建单用户配置文件,如需配置多用户,请手动修改相应的配置文件后重启即可。
客户端下载
常规版 Windows 客户端
https://github.com/shadowsocks/shadowsocks-windows/releases
ShadowsocksR 版 Windows 客户端
https://github.com/shadowsocksrr/shadowsocksr-csharp/releases
使用方法
使用root用户登录,运行以下命令:
wget --no-check-certificate -O shadowsocks-all.sh https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocks-all.sh
chmod +x shadowsocks-all.sh
./shadowsocks-all.sh 2>&1 | tee shadowsocks-all.log
安装完成后,脚本提示如下
Congratulations, your_shadowsocks_version install completed!
Your Server IP :your_server_ip
Your Server Port :your_server_port
Your Password :your_password
Your Encryption Method:your_encryption_method
Your QR Code: (For Shadowsocks Windows, OSX, Android and iOS clients)
ss://your_encryption_method:your_password@your_server_ip:your_server_port
Your QR Code has been saved as a PNG file path:
your_path.png
Welcome to visit:https://teddysun.com/486.html
Enjoy it!
卸载方法
若已安装多个版本,则卸载时也需多次运行(每次卸载一种)
使用root用户登录,运行以下命令:
./shadowsocks-all.sh uninstall
启动脚本
启动脚本后面的参数含义,从左至右依次为:启动,停止,重启,查看状态。
Shadowsocks-Python 版:
/etc/init.d/shadowsocks-python start | stop | restart | status
ShadowsocksR 版:
/etc/init.d/shadowsocks-r start | stop | restart | status
Shadowsocks-Go 版:
/etc/init.d/shadowsocks-go start | stop | restart | status
Shadowsocks-libev 版:
/etc/init.d/shadowsocks-libev start | stop | restart | status
各版本默认配置文件
Shadowsocks-Python 版:
/etc/shadowsocks-python/config.json
ShadowsocksR 版:
/etc/shadowsocks-r/config.json
Shadowsocks-Go 版:
/etc/shadowsocks-go/config.json
Shadowsocks-libev 版:
/etc/shadowsocks-libev/config.json
更新日志
2018 年 06 月 01 日:
1、修正:在启用了插件 simple-obfs 的情况下,libev 版启动失败的问题;
2、修正:在使用 /etc/init.d/shadowsocks-libev restart 命令重启 libev 版服务端时,偶尔出现的 “bind: Address already in use” 问题;
3、修正:移除 libev 版配置文件中的 local_address 字段;
4、修改:不再默认使用 root 用户启动,改为使用 nobody 用户启动 libev 版服务端 ss-server;
5、升级:mbedtls 到版本 2.9.0;
6、修改:libev 版启动脚本中的 -u 参数(即同时启用 TCP 和 UDP 模式),改到配置文件里配置为 “mode”: “tcp_and_udp”;
7、修改:libev 版配置文件的内置 NameServers 为 8.8.8.8,默认是从 /etc/resolv.conf 中取得。
2018 年 02 月 07 日:
1、修改:将默认端口从 8989 改为从 9000-19999 之间随机生成。
2018 年 02 月 06 日:
1、修改:ShadowsocksR 版为 ShadowsocksRR 最新版;
2、新增:ShadowsocksR 版的协议(protocol)增加了 4 个,分别为:
auth_chain_c
auth_chain_d
auth_chain_e
auth_chain_f
2017 年 12 月 29 日:
1、升级:libsodium 到 1.0.16。
2017 年 11 月 25 日:
1、如果 Linux 内核版本大于 3.7.0,则配置文件默认支持 TCP fast open;
2、新增:libev 版启动时支持 verbose mode,也就是默认写 log 到 /var/log/messages 方便查看。
2017 年 11 月 12 日:
1、新增生成 ss:// 或 ssr:// 链接,以及其二维码图片。
※ 脚本会根据当前安装的版本以及输入的各项配置,自动生成 ss:// 或 ssr:// 的链接并在安装成功后显示,直接复制即可被客户端识别。同时生成其二维码图片,并保存在当前目录下,下载后用看图软件打开,也能被客户端识别。
复制二维码链接后 Shadowsocks 客户端识别示例:
Shadowsocks 客户端示例
复制二维码链接后 ShadowsocksR 客户端识别示例:
ShadowsocksR 客户端示例
二维码(QR Code)参考链接:
https://github.com/shadowsocks/shadowsocks/wiki/Generate-QR-Code-for-Android-or-iOS-Clients
https://github.com/shadowsocksr-backup/shadowsocks-rss/wiki/SSR-QRcode-scheme
2017 年 10 月 22 日:
1、升级:libsodium 到 1.0.15。
2017 年 10 月 14 日:
1、新增:在安装 Shadowsocks-libev 版时可选安装 simple-obfs 服务端。
※ 脚本通过判断 autoconf 版本是否大于或等于 2.67 来一键安装 simple-obfs 服务端。并且,支持在安装过程中选择 obfs 为 http 或 tls。
※ 使用方法参考:https://teddysun.com/511.html
2017 年 09 月 16 日:
1、修正:Shadowsocks-libev 版 v3.1.0 使用 libc-ares 替换 libudns 依赖包,解决了依赖问题;
2、升级:mbedtls 到版本 2.6.0。
2017 年 07 月 27 日:
1、新增:ShadowsocksR 版可选协议(protocol)auth_chain_b 。使用该协议需更新到最新(4.7.0) ShadowsocksR 版客户端;
2、修改:更新 ShadowsocksR 源码下载地址。
2017 年 07 月 23 日:
1、修正:卸载时可自行选择某个版本卸载,若该版本不存在则报错退出。
2017 年 07 月 22 日:
1、修正:默认加密方式从 aes-256-cfb 改为 aes-256-gcm(Python 和 libev 版);
2、新增:安装时可选 16 种加密方式的其中之一(Python 和 libev 版)。如下所示:
aes-256-gcm
aes-192-gcm
aes-128-gcm
aes-256-ctr
aes-192-ctr
aes-128-ctr
aes-256-cfb
aes-192-cfb
aes-128-cfb
camellia-128-cfb
camellia-192-cfb
camellia-256-cfb
chacha20-ietf-poly1305
chacha20-ietf
chacha20
rc4-md5
3、新增:安装时可选 9 种加密方式的其中之一(Go 版)。如下所示:
aes-256-cfb
aes-192-cfb
aes-128-cfb
aes-256-ctr
aes-192-ctr
aes-128-ctr
chacha20-ietf
chacha20
rc4-md5
4、新增:安装时可选 15 种加密方式的其中之一(none 是不加密,ShadowsocksR 版)。如下所示:
none
aes-256-cfb
aes-192-cfb
aes-128-cfb
aes-256-cfb8
aes-192-cfb8
aes-128-cfb8
aes-256-ctr
aes-192-ctr
aes-128-ctr
chacha20-ietf
chacha20
salsa20
xchacha20
xsalsa20
rc4-md5
5、新增:安装时可选 7 种协议(protocol)的其中之一(仅限 ShadowsocksR 版)。如下所示:
origin
verify_deflate
auth_sha1_v4
auth_sha1_v4_compatible
auth_aes128_md5
auth_aes128_sha1
auth_chain_a
auth_chain_b
6、新增:安装时可选 9 种混淆(obfs)的其中之一(仅限 ShadowsocksR 版)。如下所示:
plain
http_simple
http_simple_compatible
http_post
http_post_compatible
tls1.2_ticket_auth
tls1.2_ticket_auth_compatible
tls1.2_ticket_fastauth
tls1.2_ticket_fastauth_compatible
2017 年 02 月 24 日:
1、恢复: 通过 Github API 自动获取 Shadowsocks-libev 的最新 release 版本的功能(v3.0.3)。
2017 年 02 月 13 日:
1、升级: Shadowsocks-libev 版到版本 3.0.2;
2、升级: Shadowsocks-go 版到版本 1.2.1(基于 Github 最新代码,用 go 1.8 编译完成的 x86 和 x86_64 二进制文件);
3、修复:在 Debian 7 下默认没有 libudns-dev 依赖包的问题。
2017 年 02 月 12 日:
1、升级: Shadowsocks-libev 版到版本 3.0.1。
2017 年 01 月 27 日:
1、升级: Shadowsocks-go 版到版本 1.2.1 (仅适用于 x86_64 系统)
更多单版本 Shadowsocks 服务端一键安装脚本
Shadowsocks Python 版一键安装脚本(CentOS,Debian,Ubuntu)
ShadowsocksR 版一键安装脚本(CentOS,Debian,Ubuntu)
CentOS 下 Shadowsocks-libev 一键安装脚本
Debian 下 Shadowsocks-libev 一键安装脚本
Shadowsocks-go 一键安装脚本(CentOS,Debian,Ubuntu)
注意:以上单版本不可与该四合一版本混用。
转载请注明:秋水逸冰 » Shadowsocks 一键安装脚本(四合一)
每个函数都包括两个非继承而来的方法:apply和call。
这两个方法的用途的都是在特定的作用域中调用函数,实际上等于设置函数体内的this对象的值。
apply接收两个参数,一个是其中运行函数的作用域,也就是this的指向,或者说该函数将在哪个对象上执行。另一个参数是参数的数组。
第二个参数可以是array对象,或者直接传入arguments对象。
call和apply的作用相同,区别只在于接受的参数不同,对于call方法而言,第一个参数是this的值,这个和apply是一样的,不同的是,call的其余参数全都直接直接传递给函数。
Function.apply(obj, args)
obj:这个对象将代替Function类里this对象
args:这个是数组,它将作为参数传给Function(args-->arguments)
Function.call(obj, [param1[,param2[,…[,paramN]]]])
obj:这个对象将代替Function类里this对象
params:这个是一个参数列表
常用的做法就是对类数组对象做循环,例如想在dom列表上用foreach。
var domList= document.querySelector(".box");
Array.prototype.forEach.call(domList, () =>{
//do something
})
这里顺便摘抄一个大神的文章,关于apply的考点。
log('hello world')
//定义log,然后它可以代理console.log的方法
//这是简单的问题
function log(msg) {
console.log(msg)
}
//我要传多个参数
log('hello', 'world')
//更加6的直接使用 apply
function log() {
console.log.apply(this, arguments)
}
log('hello', 'world')
// 输入
'(foo) hello world'
// 输出这样的结果
// arugments 是一个伪数组,这又要用到call或者apply了
// 这是大佬的答案
function log(){
const args = Array.prototype.slice.call(arguments);
args.unshift('(foo)');
console.log.apply(console, args);
}
//我觉得能不能干脆就这样,不用转换成数组对象,直接unshift
function log(){
const args = arguments
Array.prototype.unshift.call(args , '(foo)')
console.log.apply(this, args)
}
//ok,这样是可以的
补充下bind的用法,bind的作用和call已经apply也类似,都能绑定指定this的指向。
bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
意思就是bind函数会创建一个函数,这个函数的this指向会指向传入bind函数的参数
bind返回一个更改了this指向的函数,并不会像call和apply那样直接执行
上一个call的例子,如果用bind来写就是这样
function log(){
const args = arguments
Array.prototype.unshift.bind(args , '(foo)')()
console.log.apply(this, args)
}
页眉(网页(部分区域)的头部 顶部 导航区域等等),闭合标签;块元素;默认的宽是:100%;高: 内容的高度;实质上,跟DIV标签,可以说是完全一样的特性;
导航链接部分;闭合标签;块元素;默认的宽是:100%;高: 内容的高度;实质上,跟 DIV标签,可以说是完全一样的特性。
标签定义网页中的区域(部分)。比如章节、页眉、页脚或文档中的其他部分。闭合 标签;块元素;默认的宽是:100%;高: 内容的高度;实质上,跟DIV标签,可以说是完全一样的 特性;
页脚(网页(部分区域)的底部|版权区域等等),闭合标签;块元素;默认的宽是:100%;高: 内容的高度;实质上,跟DIV标签,可以说是完全一样的特性;
内容是引用其他地方的。一个区域中的,另外一部分内容;闭合标签;块元素;默认的宽是:100%;高: 内容的高度;实质上,跟DIV标签,可以说是完全一样的特性
跟 article 是一起使用;是辅助 article 区域的内容。也可以理解为整个网页的 辅助区域;(最常见的京东的右侧的工具栏)
给标题分组,为标题或者子标题进行分组,通常与h1-h6元素组合使用。如果文章中只有一个标题,则不使用hgroup。 闭合标签;块元素;默认的宽是:100%;高:内容的高度;实质上,跟DIV标签,可以说是完全一样的特性;
对多个元素进行组合。通常与figcaption联合使用。
闭合标签;块元素;默认的宽是:100%;高:内容的高度;实质上跟DIV标签,可以说是完全一样的特性;figcaption 定义figure元素组的标题,必须写在figure元素中。一个figure元素内最多只允许放置一个figcaption元素。闭合标签;块元素;默认的宽是:100%;高:内容的高度;实质上,跟DIV标签,可以说是完全一样的特性;
播放声音文件,比如音乐或其它音频流。可以在开始标签和结束标签之间放置文本内容,这样老的浏览器就可以显示出不支持该标签的信息。闭合标签;行内元素;默认的宽:controls的宽度300px;高:controls的高度32px;autoplay autoplay 如果出现该属性,则音频在就绪后马上播放。controls controls 如果出现该属性,则向用户显示控件,比如播放按钮。preload preload 如果出现该属性,则音频在页面加载时进行加载,并预备播放。如果使用 “autoplay”,则忽略该属性。src url 要播放的音频的 URL。
播放视频文件,比如电影或其它视频流。可以在开始标签和结束标签之间放置文本内容,这样老的浏览器就可以显示出不支持该标签的信息。
闭合标签;行内元素;默认的宽:300px 高:150px。autoplay autoplay 如果出现该属性,则视频在就绪后马上播放。controls controls 如果出现该属性,则向用户显示控件,比如播放按钮。height 设置视频播放器的高度。loop loop 如果出现该属性,则当媒介文件完成播放后再次开始播放。preload preload 如果出现该属性,则视频在页面加载时进行加载,并预备播放。如果使用 “autoplay”,则忽略该属性。src 要播放的视频的 URL。width 设置视频播放器的宽度。
为媒介元素(比如 video 和 audio)指定多个播放格式与编码,浏览器会自动选择第一个可以识别的格式。非闭合标签,只有开始标签,没有结束标签。source 行内元素,默认无宽度和高度。media 定义媒介资源的类型,供浏览器决定是否下载。src 媒介的 URL。type 定义播放器在音频流中的什么位置开始播放。默认,音频从开头播放。
定义图形,比如图表和其他图像。
闭合标签;行内元素;默认情况下,canvas创建的画布宽:300px;高:150px;
定义可选数据的列表。与 input 元素配合使用,就可以制作出输入值的下拉列表。
闭合标签;行内元素;默认无宽度和高度。
定义嵌入的内容,比如插件。用来插入各种多媒体,格式可以是MIDI、MP3等。
非闭合标签,只有开始标签,没有结束标签。行内元素;默认的宽:300px;高:150px。
定义日期或时间,或者两者。闭合标签;行内元素,默认情况下,宽:内容的宽度;高:内容的高度;
为文档或 section 定义联系信息,比如:电子邮箱、地址、电话、QQ、微信号等。
闭合标签;块元素;默认的宽是:100%;高: 内容的高度;实质上,跟DIV标签,可以说是完全一样的特性;
定义客户端的图像映射。图像映射是带有可点击区域的图像。
闭合标签;行内元素;默认情况下,无宽度和高度;
area 元素永远嵌套在 map 元素内部。area 元素可定义图像映射中的区域。
闭合标签,行内元素;只有结束标签,没有开始标签。默认情况下,无宽度和高度;
定义页面中需要突出显示或高亮显示的内容,通常在引用原文时,使用此元素,目的就是引起当前用户的注意。闭合标签;行内元素;默认情况下,宽:内容的宽度;高:内容的高度;
标签定义元素的细节,用户可进行查看,或通过点击进行隐藏。(备注信息), 块元素;默认的宽是:100%;高: 内容的高度;实质上,跟DIV标签,可以说是完全一样的特性;
但是有一个动态的效果,点击可以显示(展开)内容,再点击可以隐藏(收起)内容;
属性名 | 描述 |
---|---|
name(string) | 该Cookie的名称。Cookie一旦创建,名称便不可更改 |
value(string) | 该Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码 |
maxAge(number) | 该Cookie失效的时间,单位秒。如果为正数,则该Cookie在maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1 |
secure(booblean) | 该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false |
path(string) | 该Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/” |
domain(string) | 可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.” |
comment | 该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明 |
version(number) | 该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范 |
document.cookie看上去就像一个属性,可以赋不同的值。但它和一般的属性不一样,改变
它的赋值并不意味着丢失原来的值,例如连续执行下面两条语句:
document.cookie="userId=828"
document.cookie="userName=hulk"
这时浏览器将维护两个cookie,分别是userId和userName,因此给document.cookie赋值更像执行类似这样的语句:
document.addCookie("userId=828")
document.addCookie("userName=hulk")
事实上,浏览器就是按照这样的方式来设置cookie的,如果要改变一个cookie的值,只需重新赋值,例如:
document.cookie="userId=929"
这样就将名为userId的cookie值设置为了929。
下面介绍如何获取cookie的值。cookie的值可以由document.cookie直接获得:
var strCookie=document.cookie;
这将获得以分号隔开的多个名/值对所组成的字符串,这些名/值对包括了该域名下的所有cookie。
例如:
document.cookie="userId=828";
document.cookie="userName=hulk";
var strCookie=document.cookie;
alert(strCookie);
只能够一次获取所有的cookie值,而不能指定cookie名称来获得指定的值。
获取指定的cookie值,例如,要获取userId的值,可以这样实现:
function getCookies(cookiesName) {
const strCookie = document.cookie
const arrCookie = strCookie.split('; ')
let value
for (let i = 0; i < arrCookie.length; i++) {
const arr = arrCookie[i].split('=')
if (arr[0] === cookiesName) {
value = arr[1]
break
}
}
return value
}
const userId = getCookies('userId')
function throttle(method, context){
clearTimeout(method.tId);
method.tId = setTimeout(function(){
method.call(context);
}, 100)
}
// 例子
window.onresize = function(){
throttle(myFunc);
}
另一种
var throttle = function(fn, delay){
var timer = null
return function(){
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
fn.apply(context, args);
}, delay);
};
};
// 例子
window.onresize = throttle(myFunc, 100);
getQueryString(name) {
let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i')
let r = window.location.search.substr(1).match(reg)
if (r != null) return decodeURIComponent(r[2])
return null
}
var cloneObj = function(obj){
var str, newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== 'object'){
return;
} else if(window.JSON){
str = JSON.stringify(obj), //系列化对象
newobj = JSON.parse(str); //还原
} else {
for(var i in obj){
newobj[i] = typeof obj[i] === 'object' ?
cloneObj(obj[i]) : obj[i];
}
}
return newobj;
};
const flatten = [1, [2, [3, [4]], 5]].reduce( (a, b) => a.concat(b), [])
// => [1, 2, [3, [4]], 5]
const flattenDeep = (arr) => Array.isArray(arr)
? arr.reduce( (a, b) => [...flattenDeep(a), ...flattenDeep(b)] , [])
: [arr]
flattenDeep([1, [[2], [3, [4]], 5]])
// => [1, 2, 3, 4, 5]
path.resolve(__dirname).split(path.sep).pop()
<script>
import Table from 'element-ui/lib/table'
import 'element-ui/lib/theme-chalk/table.css'
import emptyImg from '../components/imgs/empty.jpg'
const emptyComp = (h, text) => {
const emptyTip = text || '暂无数据'
return h('div', {
slot: 'empty'
}, [
h('img', {
'attrs': {
class: 'empty_img',
src: emptyImg
}
}),
h('div', {
'attrs': {
class: 'empty_span'
}
}, emptyTip)
])
}
export default {
functional: true,
render: function (h, context) {
const childNode = [...context.children, emptyComp(h, context.props.emptyTip)]
return h(Table, context.data, childNode)
}
}
</script>
一、prototype和__proto__的区别
var a = {};
console.log(a.prototype); //undefined
console.log(a.__proto__); //Object {}
var b = function(){}
console.log(b.prototype); //b {}
console.log(b.__proto__); //function() {}
/*1、字面量方式*/
var a = {};
console.log(a.__proto__); //Object {}
console.log(a.__proto__ === a.constructor.prototype); //true
/*2、构造器方式*/
var A = function(){};
var a = new A();
console.log(a.__proto__); //A {}
console.log(a.__proto__ === a.constructor.prototype); //true
/*3、Object.create()方式*/
var a1 = {a:1}
var a2 = Object.create(a1);
console.log(a2.__proto__); //Object {a: 1}
console.log(a.__proto__ === a.constructor.prototype); //false(此处即为图1中的例外情况)
var A = function(){};
var a = new A();
console.log(a.__proto__); //A {}(即构造器function A 的原型对象)
console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象)
console.log(a.__proto__.__proto__.__proto__); //null
function Foo() {
getName = function () {
alert(1)
}
return this
}
Foo.getName = function () {
alert(2)
}
Foo.prototype.getName = function () {
alert(3)
}
var getName = function () {
alert(4)
}
function getName() {
alert(5)
}
//请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
Foo.getName();
这个不用多说,返回2.
执行的是Foo函数的静态属性getName方法
这里复习下一些定义
function User(name) {
var name = name //私有属性
this.name = name //公有属性
function getName() { //私有方法
return name
}
}
User.prototype.getName = function () { //公有方法
return this.name
}
User.name = 'Wscats' //静态属性
User.getName = function () { //静态方法
return this.name
}
var Wscat = new User('Wscats') //实例化
个人理解:
公有方法必须实例化才能访问,是因为查找对象的属性时,如果该对象没有这个属性,会在原型链上查找,也就是会在对象的__proto__上继续查找,但是不会查找自身的prototype,而__proto__指向的是这个对象的构造函数的prototype。
也就是说,通过构造函数实例化一个对象后,这个对象就可以通过__proto__访问到构造函数的prototype上的方法。
直接调用getName函数。
这个明显是只和4和5有关了
4是函数表达式,5是函数声明
这里有个陷阱
JavaScript 解释器中存在一种变量声明被提升的机制,也就是说函数声明会被提升到作用域的最前面,即使写代码的时候是写在最后面,也还是会被提升至最前面。
而用函数表达式创建的函数是在运行时进行赋值,且要等到表达式赋值完成后才能调用
getName() // Uncaught TypeError: getName is not a function
var getName = function () {
alert(4)
}
getName() // 4
函数表达式的值是在JS运行时确定,并且在表达式赋值完成后,该函数才能调用
getName() // 5 函数提升了
function getName() {
alert(5)
}
函数声明在JS解析时进行函数提升,因此在同一个作用域内,不管函数声明在哪里定义,该函数都可以进行调用
getName() // 5 函数提升了
var getName = function () {
alert(4)
}
getName() // 4 被覆盖了
function getName() {
alert(5)
}
getName() // 4
这题的考核就是在这个地方,变量提升
Foo().getName()
先执行Foo(),再调用Foo()的返回值调用getName()
function Foo() {
getName = function () {
alert(1)
}
return this
}
调用Foo(),先从函数作用域内寻找getName这个变量,没有找到,再向当前函数作用域上层,找到了,第四个函数定义的getName会被覆盖。
上面说的这个重复向上层作用域寻找函数变量的过程,如果到window对象都没有找到,就会直接创建一个全局的getName变量。
接下来返回this,这里直接调用Foo(),this直接指向window。
全局作用域或者普通函数中this指向全局对象window
方法调用中谁调用this指向谁
那么执行Foo().getName()
就相当于window.getName()
,直接执行第四个函数,但是第四个函数刚刚已经被覆盖了,所以返回的是1。
这道题考察的一个是变量作用域,一个是this指向。
直接调用getName(),也就是window.getName(), 第一问的Foo函数已经把第五个函数给覆盖了,所以返回的结果是1。
new Foo.getName()
这题考察的是JS的运算符优先级问题,这是我做这道题之前都没有去了解过的知识点。
下面是JS运算符的优先级表格,从高到低排列。可参考MDN运算符优先级
优先级 | 运算类型 | 关联性 | 运算符 |
---|---|---|---|
19 | 圆括号 | n/a | ( … ) |
18 | 成员访问 | 从左到右 | … . … |
需计算的成员访问 | 从左到右 | … [ … ] | |
new (带参数列表) | n/a new | … ( … ) | |
17 | 函数调用 | 从左到右 | … ( … ) |
new (无参数列表) | 从右到左 | new … | |
16 | 后置递增(运算符在后) | n/a | … ++ |
后置递减(运算符在后) | n/a | … -- | |
15 | 逻辑非 | 从右到左 | ! … |
按位非 | 从右到左 | ~ … | |
一元加法 | 从右到左 | + … | |
一元减法 | 从右到左 | - … | |
前置递增 | 从右到左 | ++ … | |
前置递减 | 从右到左 | -- … | |
typeof | 从右到左 | typeof … | |
void | 从右到左 | void … | |
delete | 从右到左 | delete … | |
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 | 逗号 | 从左到右 | … , … |
new (带参数列表)比new (无参数列表)高比函数调用高,跟成员访问同级
new Foo.getName()
(new (Foo.getName))() //相当于
点的优先级(18)比new无参数列表(17)优先级高
当点运算完后又因为有个括号(),此时就是变成new有参数列表(18),所以直接执行new,当然也可能有朋友会有疑问为什么遇到()不函数调用再new呢,那是因为函数调用(17)比new有参数列表(18)优先级低
最后结果就是2
new Foo().getName()
new有参数列表(18)跟点的优先级(18)是同级,同级的话按照从左向右的执行顺序
(new Foo()).getName()
构造函数的返回值
在传统语言中,构造函数不应该有返回值,实际执行的返回值就是此构造函数的实例化对象。
而在JS中构造函数可以有返回值也可以没有。
没有返回值则按照其他语言一样返回实例化对象。
function Foo (name) {
this.name = name
}
console.log(new Foo('wscats'))
若有返回值则检查其返回值是否为引用类型。如果是非引用类型,如基本类型(String,Number,Boolean,Null,Undefined)则与无返回值相同,实际返回其实例化对象。
function Foo (name) {
this.name = name
return 520
}
console.log(new Foo('wscats'))
若返回值是引用类型,则实际返回值为这个引用类型。
function Foo (name) {
this.name = name
return {
age: 16
}
}
console.log(new Foo('wscats'))
原题中,由于返回的是this,而this在构造函数中本来就代表当前实例化对象,最终Foo函数返回实例化对象。
之后调用实例化对象的getName函数,因为在Foo构造函数中没有为实例化对象添加任何属性,当前对象的原型对象(prototype)中寻找getName函数。
答案是3
參考地址
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS之类的
module.exports = factory(require('jquery'));
} else {
// 浏览器全局变量(root 即 window)
root.returnExports = factory(root.jQuery);
}
}(this, function ($) {
// 方法
function myFunc(){};
// 暴露公共方法
return myFunc;
}));
更多依赖的情况
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery', 'underscore'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS之类的
module.exports = factory(require('jquery'), require('underscore'));
} else {
// 浏览器全局变量(root 即 window)
root.returnExports = factory(root.jQuery, root._);
}
}(this, function ($, _) {
// 方法
function a(){}; // 私有方法,因为它没被返回 (见下面)
function b(){}; // 公共方法,因为被返回了
function c(){}; // 公共方法,因为被返回了
// 暴露公共方法
return {
b: b,
c: c
}
}));
Undefined是一种数据类型,只有一个值, 即特殊的undefined。
undefined是全局对象的一个属性。也就是说,它是全局作用域的一个变量。
undefined的最初值就是原始数据类型undefined。
一个没有被赋值的变量的类型是undefined。
如果方法或者是语句中操作的变量没有被赋值,则会返回undefined。
let x
x === undefined === true
typeof x === 'undefined' === true
Null类型,只有一个特殊的值null。
值 null 是一个字面量,它不像undefined 是全局对象的一个属性。null 是表示缺少的标识,指示变量未指向任何对象。
从逻辑角度来说,null值表示一个空对象指针,而这也正是typeof操作符检测null值是返回‘object’的原因
typeof null // object (因为一些以前的原因而不是'null')
typeof undefined // "undefined"
null === undefined // false
null == undefined // true
null === null // true
null == null // true
!null //true
isNaN(1 + null) // false
isNaN(1 + undefined) // true
function ajax(url, success, fail) {
// 1. 创建连接
const xhr = new XMLHttpRequest()
// 2. 连接服务器
// 规定请求的类型、URL 以及是否异步处理请求。
xhr.open('get', url, true)
// 发送信息至服务器时内容编码类型
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
// 3. 发送请求
xhr.send(null)
// 4. 接受服务器响应数据
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
success(xhr.responseText)
} else { // fail
fail && fail(xhr.status)
}
}
}
}
最近趁着优惠,入了阿里云服务一台,三年297,感觉还行。
在这大概记录下自己对linux,服务器基本的操作的笔记。
待续......
淘宝的样式初始化代码:
body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button,
input, textarea, th, td { margin:0; padding:0; }
body, button, input, select, textarea { font:12px/1.5tahoma, arial, \5b8b\4f53; }
h1, h2, h3, h4, h5, h6{ font-size:100%; }
address, cite, dfn, em, var { font-style:normal; }
code, kbd, pre, samp { font-family:couriernew, courier, monospace; }
small{ font-size:12px; }
ul, ol { list-style:none; }
a { text-decoration:none; }
a:hover { text-decoration:underline; }
sup { vertical-align:text-top; }
sub{ vertical-align:text-bottom; }
legend { color:#000; }
fieldset, img { border:0; }
button, input, select, textarea { font-size:100%; }
table { border-collapse:collapse; border-spacing:0; }
面试问了sort的相关问题,我完全答不出,真的很惭愧,所以做个笔记
sort() 方法用就地( in-place )的算法对数组的元素进行排序,并返回数组。 sort 排序不一定是稳定的。默认排序顺序是根据字符串Unicode码点。
排序算法的稳定性大家应该都知道,通俗地讲就是能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。在简单形式化一下,如果A[i]= A[j],A[i]原来在位置前,排序后A[i]还是要在A[j]位置前。
var fruit = ['cherries', 'apples', 'bananas'];
fruit.sort();
// ['apples', 'bananas', 'cherries']
var scores = [1, 10, 21, 2];
scores.sort();
// [1, 10, 2, 21]
// 注意10在2之前,
// 因为在 Unicode 指针顺序中"10"在"2"之前
var things = ['word', 'Word', '1 Word', '2 Words'];
things.sort();
// ['1 Word', '2 Words', 'Word', 'word']
// 在Unicode中, 数字在大写字母之前,
// 大写字母在小写字母之前.
arr.sort()
arr.sort(compareFunction)
compareFunction
可选。用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的各个字符的Unicode位点进行排序。
返回排序后的数组。原数组已经被排序后的数组代替。
如果没有指明 compareFunction ,那么元素会按照转换为的字符串的诸个字符的Unicode位点进行排序。例如 "Banana" 会被排列到 "cherry" 之前。当数字按由小到大排序时,9 出现在 80 之前,但因为(没有指明 compareFunction),比较的数字会先被转换为字符串,所以在Unicode顺序上 "80" 要比 "9" 要靠前。
如果指明了 compareFunction ,那么数组会按照调用该函数的返回值排序。即 a 和 b 是两个将要被比较的元素:
工厂模式是软件工程领域一种广为人知的设计模式,而由于在ECMAScript中无法创建类,因此用函数封装以特定接口创建对象。其实现方法非常简单,也就是在函数内创建一个对象,给对象赋予属性及方法再将对象返回即可。
function person(name, address) {
let obj = new Object()
obj.name = name
obj.address = address
obj.sayName = function () {
console.log(this.name)
}
return obj
}
const tom = person('tom', 'shenzhen')
可以看到工厂模式的实现方法非常简单,解决了创建多个相似对象的问题,但是工厂模式却无从识别对象的类型,因为全部都是Object,不像Date、Array等,因此出现了构造函数模式。
ECMAScript中构造函数可以创建特定类型的对象,类似于Array、Date等原生JS的对象。其实现方法如下:
function Blog(name, url) {
this.name = name;
this.url = url;
this.alertUrl = function() {
alert(this.url);
}
}
var blog = new Blog('wuyuchang', 'http://www.cnblogs.com/wuyuchang/');
console.log(blog instanceof Blog); // true, 判断blog是否是Blog的实例,即解决了工厂模式中不能识别是对象的类型的问题
这个例子与工厂模式中除了函数名不同以外,细心的童鞋应该发现许多不同之处:
函数名首写字母为大写(虽然标准没有严格规定首写字母为大写,但按照惯例,构造函数的首写字母用大写
没有显示的创建对象
直接将属性和方法赋值给了this对象
没有return语句
使用new创建对象
能够识别对象,这正是构造函数模式胜于工厂模式的地方
构造函数虽然好用,但也并非没有缺点,使用构造函数的最大的问题在于每次创建实例的时候都要重新创建一次方法(理论上每次创建对象的时候对象的属性均不同,而对象的方法是相同的),然而创建两次完全相同的方法是没有必要的,因此,我们可以将函数移到对象外面
这里我说下自己的理解
MDN对于instanceof 的定义这样的
instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
一般可以用来判断对象的类型
function Animal(name) {
this.name = name
}
const cat = new Animal('kitty')
const isAnimal = cat instanceof Animal // 返回 true
const isObject = cat instanceof Object // 返回 true
cat既属于Animal类型,又属于Object类型。
工厂函数都是new object(),类型都是object。
构造函数的new 函数是在实例化对象时调用的,那就能判断对象类型了。
(全文基本都是摘抄,如有雷同,请勿见怪)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.