liuxsen / blog Goto Github PK
View Code? Open in Web Editor NEWblog
Home Page: https://liuxsen.github.io/
blog
Home Page: https://liuxsen.github.io/
在日常工作中经常使用npm,下面的npm技巧会对你很有用哦~
我们通常会 npm init,然后开始添加npm请求的信息。但是,如果我们并不真正关心所有这些信息并且我们想要保留默认值,那么我们只需要连续按下回车。或者,您只需输入 npm init -y
。
不用使用 npm install
可以简写 npm i
不用为每个模块键入 npm i
eg:
npm i gulp-pug
npm i gulp-debug
npm i gulp-sass
可以一次安装所有packege
npm i gulp-pug gulp-debug gulp-sass
使用一些安装快捷方式
如果要安装软件包并将其另存为生产依赖项,通常会这样做
npm i gulp --save-prod
可以简写
npm i gulp -P
对于开发依赖项是相同的,而不是键入--save-dev您可以使用的完整标志,-D如下所示:
npm i gulp -D
这将显示vue包的相关信息,如下所示:
npm view vue
or npm v vue
如果您只想获得最新版本的软件包,可以试试
npm v vue version
如果您想获得npm包的完整版本列表,可以使用
npm v vue versions
如果要安装版本不是最新版本的软件包,可以键入
npm i [email protected]
由于名字比数字更容易(至少对我而言),你可以使用运行 npm v 命令 后列出的dist-tags,如上所示,如下所示:
npm i vue@beta
如果不知道package的确切名称,可以使用npm search 直接从终端搜索
npm search gulp debug
or
npm s gulp debug
这将打印包含描述,作者和一些其他信息的包列表
卸载包
如果您不想把包信息保存在 package.json
文件而且不想手动删除依赖项,则可以使用
npm uninstall vue
这将从node_modules文件夹和package.json文件中删除package。当然,您可以使用 rm
,un 或
r`
npm rm vue
如果由于某种原因您只想从node_modules文件夹中删除包文件,但将其保存为package.json文件中的依赖项,则可以使用no-save标志
npm rm vue --no-save
如果要查看项目依赖项列表,可以使用
npm ls
这将列出package.json文件中列出的所有依赖项以及它们的所有依赖项。如果您只想列出您的依赖项,您可以这样做
npm ls --depth = 0
如果要查看所有全局安装的软件包的列表,可以使用参数 -g
npm ls -g -depth 0
大多数情况下,需要更新本地依赖项,可以执行
npm outdate
这将为您提供您可能想要更新的所有过时软件包的列表,它看起来像这样:
你可以使用你的测试命令,npm run test
还可以使用 npm test
npm t
有时,我们希望查看 package.json
文件中包含的脚本。我们当然可以打开package.json文件,但我们也可以这样做
npm run
如果我在package.json文件中有这样的配置,如下所示:
"scripts": {
"test": "jest",
"build": "gulp build"
}
npm run
命令将显示的内容:
Lifecycle scripts included in npm:
test
jest
available via `npm run-script`:
build
gulp-build
你可以直接从像这样的Github仓库安装一个包
npm i https://github.com/sindresorhus/gulp-debug
或者可以省略完整的域名部分
npm i sindresorhus/gulp-debug
您当然可以进行Google搜索,然后查找该页面,或者您可以执行以下操作:
npm repo create-react-app
无需安装软件包即可执行上述命令。
可以通过 run env 查看可供我们使用的NPM变量的完整列表:
npm run env | grep npm_
上面的命令将打印如下:
npm_config_fetch_retry_maxtimeout = 60000
npm_config_tag_version_prefix = v
npm_config_strict_ssl = true
npm_config_sso_type = oauth
.
.
.
这些变量的好处是它们可以在你的脚本中使用,你甚至可以创建自己的
您可以通过向package.json文件添加新 key
来添加自己的NPM变量。它可以是任何key
,但我更喜欢将所有NPM变量保存在 config key
中以保持有序。像这样:
"config":{
"build_folder”:"./ dist"
}
现在,如果您使用上面讨论的命令列出变量 npm run env | grep npm_
,您将看到您的新变量存在:
npm_package_config_build_folder =./ dist
npm_config_fetch_retry_maxtimeout = 60000
npm_config_tag_version_prefix = v
npm_config_strict_ssl = true
npm_config_sso_type = oauth
。
。
默认情况下,npm 会将变量命名加前缀 npm_package
这意代表值
config_build_folder。
一旦你看到完整的变量列表,并且你想在脚本中使用任何这些变量的值,你可以在package.json中执行此操作(请参阅上一节中变量npm_package_config_build_folder的值)
"scripts": {
"build":"gulp build --dist $npm_package_config_build_folder"
}
一旦你运行这个命令,npm run build它将被执行为
gulp build --dist ./dist
在我的日常工作流程中,这些是我最喜欢的快捷方式和命令,你有没有在这里列出的那个吗?我很想知道它!
思索数月,仍无法想出可将JavaScript闭包通俗易懂解释出的例子。
在去年的一篇解释JavaScript原型链的文章里,我试图借助遗传与进化🧬这一生物学的概念,收效甚好,所以用已知的概念学习未知的概念是有帮助的,可以称为类比学习法。
一年后的突发奇想,受16年我的毕业设计影响与启发,打算用一敏感话题类比JavaScript闭包——不同国家(即不同作用域内)在法律条文上(活动上下文)的差异性与人口流动对这种差异性的改变。
想要理解闭包,需要先理解作用域和作用域链。
大到国家,小至个人,皆可看作一个又一个作用域。
作用域有大小之分,却无贵贱之分;小与大是相对的;大作用域容纳小作用域;作用域可包含也可对峙。
一般情况下,小作用域可访问包含该作用域的大作用域中的信息;换句话说,小作用域会受到大作用域的影响。
一般情况下,大作用域不可访问其中小作用域内的信息;换句话说,大作用域不会受到小作用域的影响。
结合上图,我们看这样的一段代码:
function funA(){
var funA_age = 28
return function funB(){
var funB_age = 20
return function funC(){
var funC_age = 18
return function funD(){
var funD_age = 12
}
}
}
}
//将函数funA的属性输出
console.dir(funA)
执行上面代码,看看控制台输出了什么。
在Scopes内有1个元素,展开他发现,他就是所有全局变量。所以我们才可以在funA函数内直接访问window中的各种方法和属性,比如window.setInterval()等。
接着,我将输出改一下。
function funA(){
var funA_age = 28
return function funB(){
var funB_age = 20
return function funC(){
var funC_age = 18
return function funD(){
var funD_age = 12
}
}`
}
}
//将funA()的返回值(也就是函数funB)的属性输出
console.dir(funA())
同样能在控制台看到函数funB内可以访问window中的所有方法和属性。
以此类推,结果都一样,不管函数嵌套多深,好像window这个全局变量的方法和属性在哪里都能访问到,这难道就是作用域链起到的神奇作用么。好戏还在后头。
function funA(){
var funA_age = 28
return function funB(){
var funB_age = 20
//在函数funB中访问funA中定义的funA_age,能获取到么?
console.log(funA_age)
return function funC(){
var funC_age = 18
return function funD(){
var funD_age = 12
}
}
}
}
//将funA()的返回值(也就是函数funB)的属性输出
console.dir(funA())
而且你有沒有发现,js很聪明,因为在第一次没有console.dir()来输出funA_age而只是输出函数funA的时候,我们并没有在控制台的[[Scopes]]中找到被定义的funA_age变量,所以说,作用域链上每个函数作用域内用到了其父级什么变量就存什么变量,没有用到的就不存。
比如说,我们改写函数funD。
function funA(){
var funA_age = 28
return function funB(){
var funB_age = 20
return function funC(){
var funC_age = 18
return function funD(){
var funD_age = 12
console.log(funA_age)
console.log(funB_age)
console.log(funC_age)
console.log(funD_age)
}
}
}
}
//执行funD(),将其属性输出
console.dir(funA()()())
这下明白了,
funD中需要输出非funD作用域中的funA_age、funB_age、funC_age变量,所以我们在[[Scopes]]中发现了funA作用域中的funA_age;funB作用域中的funB_age;funC作用域中的funC_age… …
这就是作用域链!
闭包一个用处就是在内存中永久存储数据。
执行Ajax请求很耗时间,如果直接将Ajax写入for循环中,你会的到最后一次循环的异步请求 结果。这里我用延时模拟一下这种糟糕的情况。
for(var i=0; i<3; i++){
setTimeout(function(){
console.log(i)
},1000)
}
最后输出了3次3,并不是我们希望的0,1,2,难道我写了一个假循环!
for(var i=0; i<3; i++){
print(i)
}
function print(num){
console.log(num)
}
也许你会问,print怎么算闭包,闭包不是应该签到在函数里的么,白眼.jpg。请把全局作用域也考虑在内,全局作用域内的函数都是闭包,所以print函数也是啊。
也许你还会问,参数也可以被保存进内存?白眼.jpg。是的!如果没有传进来实参,那么在该函数作用域内访问才参数会返回undefined。如果你觉得不舒服,可以将传入的参数重新赋值给你自己定义的变量,后续就用这个变量,当然我就经常喜欢重新赋值一下。
function A(){
var _age = 0
return function(){
console.log(_age++)
}
}
var a = A()
a()
a()
a()
a()
猜猜,控制台输出什么,4个0么?
当然不是啦,每次执行一次函数a,都相当于在当前私有变量_age的基础上加1。注意我喜欢私有变量前边加上一个下划线(JS里变量首字母可以是字母、美刀符号和下划线),不然容易和全局变量同名引起副作用。
我再用另一种写法写出相同的功能。这种写法就不存在同名冲突的问题。
function Person(){
this.age = 0
}
Person.prototype.add = function(){
console.log(this.age++)
}
var csh = new Person()
csh.add()
csh.add()
csh.add()
csh.add()
这就是我理解的作用域、作用域链和闭包,希望你也理解了,甚至比我更好的理解了。
技术的目的是为了解决实际问题,不是炫耀,就像闭包,他不是内置函数,只是一个概念,以前不认识它,只要写过函数就一定在用它。多像老子口中的哪位智者呐,不见行踪又无处不在,好像无用实则有大用。
import apis from '@/api';
import OSS from 'ali-oss';
const uuidv1 = require('uuid/v1');
/**
* @param {string} path 图片路径
*/
const getSize = (path) => {
return new Promise((resolve, reject) => {
let image = new Image();
image.onload = function () {
const width = image.width;
const height = image.height;
const fileSize = image.fileSize;
return resolve({
imgWith: width,
imgHeight: height,
size: fileSize,
url: path,
imageUrl: path
});
};
image.src = path;
});
};
/**
*
* @param {File} file 文件 or Buffer
*/
export default async function uploadFile (file) {
const {accessKeyId, accessKeySecret, securityToken} = await apis.commonHttp.getUploadFileToken();
const options = {
region: 'oss-cn-beijing',
accessKeyId,
accessKeySecret,
stsToken: securityToken,
bucket: 'gk-dev-image'
};
let client = new OSS(options);
try {
const objName = 'gkcms/' + uuidv1();
let result = await client.put(objName, file);
const res = await getSize(result.url);
return {
...result,
...res
};
} catch (e) {
}
}
export {
uploadFile
};
问题原因
没有配置上传支持方法
// router/index.js
const router = new Router({
mode: 'history',
base: '/fe/', // 配置子目录部署
routes: routerMap
});
// config/index.js
build: {
...,
assetsPublicPath: '/fe/',
}
解决问题
是否正确配置nginx路由
location /fe {
root /Users/liujianhui/lexue/moban-h5/dist/;
index index.html index.htm;
try_files $uri $uri/ /fe/index.html;
}
注意nginx语法问题,也会导致页面错误
我们已经使用NPM很长一段时间了,尽管它非常有用,它也可能有时会有点恼人,特别是当你想尝试一些新包但必须全局安装它们,才可以使用,并且你不想这样做
比如说,您想要测试Angular框架。它有一个名为 angular-cli
的强大工具,可以帮助您加快工作流程并完成各种任务。以下是为了使用它而必须采取的步骤:
如果您注意到,第一行 npm install -g @angular/cli
意味着您将全局安装 @angular/cli
包,这使得ng命令在您的机器中可用。这可能不是什么大问题,但如果你只是测试包,那么全局安装它,可能是不值得的,因为在之后你会忘记它。
NPM 在node_modules中添加一个 .bin
文件夹,其中包含已安装模块的二进制文件。例如,运行 npm install @angular/cli
后,将在项目的node_modules文件夹中看到:
我们可以使用这些本地项目二进制文件执行ng命令来创建一个新的Angular应用程序,如下所示:
./node_modules/.bin/ng new my-app。
如果您不喜欢键入二进制文件的所有路径,如上例所示,您可以始终使用旧的npm脚本,只需在package.json文件中添加我们要执行的命令,如下所示:
在上图中,你可以看到,我们加入的键/值对 "angular":"ng"
的脚本对象。这是告诉NPM,。在 npm run angular
情况下,npm 将查找本地依赖项中安装的 ng
模块并使用execute it
。因此,为了创建我们的 Angular
应用程序
npm run angular new my-app。
这两个选项都运行得很好,但它们感觉像是一个非常简单的任务的解决方法; 老实说,没有人喜欢一直打字那些“长”的命令。为了规避这一点并做更有趣/有用的事情,我们可以使用NPX。
如果您的NPM≥5.2.0,您应该已经在计算机中安装了NPX,因为默认情况下它是NPM附带的。要检查是否有,请在控制台中输入,npx -v然后您应该获得已安装的版本,在我的情况下,我有版本6.4.1。
如果由于某种原因你得到类似的错误 command not found
,请安装全局, 就像你使用任何其他NPM模块一样
npm i -g npx
一旦确定它已安装在您的计算机中,您就可以开始使用它了。
为什么NPX有用?
好吧,它可以帮助您在本地项目中或全局执行计算机中已安装的二进制文件。这是官方文件说的:
默认情况下,npx将检查是否存在于$PATH本地项目二进制文件中,并执行该操作。如果未找到,则会在执行之前安装。
因此,它将首先执行它发现的任何内容:
我们来看一些例子。
让我们回到angular-cli包。如果您想测试它但不想全局安装它或将其包含在您的项目中,您可以执行以下操作:
npx @angular/cli new my-app
你会看到这样的消息
**Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/*
到目前为止,您已经注意到NPX命令的语法是什么:
npx <command> <command-options>
从本地项目执行二进制文件
现在我们已经创建了项目,您可以打开my-app文件夹,然后使用以下命令:
npx @angular/cli serve
这将开始运行本地服务器,您将能够看到项目正在运行。但是,我们可以在这里获得效率。上一个命令可以工作,但它首先从NPM注册表下载 @angular/cli,然后 run serve command,但是如果你打开my-app里面的.bin文件夹,你会注意到有一个二进制调用 ng
匹配 Angular CLI 文档中显示的命令。所以你可以改为运行那个二进制文件,如下所示:
npx ng serve
上面的命令将执行已安装在项目中的本地二进制文件。
NPX的另一个好处是你可以执行一个全局可用但不在本地项目中的命令。
例如,我在全局安装了一个名为 localtunnel 的npm模块,它为您提供了一种在特定端口**享您在localhost中运行的内容的方法。在这种情况下,我可以像这样运行它:
npx lt --port 4200
如果你想用非常特定的版本执行二进制文件,可能是因为你已经安装了较新版本的软件包,但是你被要求帮助的项目使用了旧版本,你可以这样做:
npx [email protected] my-react-app
如果二进制文件是 Node JS
脚本,则可以将额外的参数传递给Node,以便它使用这些参数执行二进制文件。例如,您可以使用Node的inspect参数调试vue-cli二进制文件
npx --node-arg=--inspect vue-cli
这将打印出这样的东西
npx: installed 239 in 9.533s
Debugger listening on ws://127.0.0.1:9229/ffcb736c-4847-4b7f-9c35-1c49b9573c65
For help, see: https://nodejs.org/en/docs/inspector
Usage: vue <command> [options]
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
init generate a new project from a template
list list available official templates
build prototype a new project
create (for v3 warning only)
help [cmd] display help for [cmd]
使用类似环境的npm-run执行命令
所以如果你有这样的脚本:
"scripts": {
"custom": "echo $npm_package_version"
}
当你运行它时,它将打印你的包的版本。输出看起来像这样:
> npm run custom
> 1.0.0
但是,这些变量不能直接在终端中获得。因此,如果您从终端运行该脚本的内容,您将获得如下输出:
echo $npm_package_version
这是NPX可以提供帮助的地方。上面的命令可以使用-c标志运行,以便能够访问npm变量,如下所示:
> npx -c'echo $ npm_package_version'
> 1.0.0
请注意我们如何将命令的内容作为字符串传递。
我最近参与了一个必须运行Node版本6(我目前使用的是版本10)的项目,所以我安装了nvm,这很棒,但在Windows上不起作用,所以我们不得不为它们寻找其他解决方案。但后来我们发现NPX,使用NPX我们能够使用此命令运行节点版本6的脚本:
npx -p node@6 node index.js
我们也像这样运行npm脚本构建
npx -p node@6 npm run build
当然,您可以根据需要具体
npx -p [email protected] node index.js
您可以直接从git仓库执行命令。例如,有个git repo
https://github.com/jaireina/presentation
。要运行它,您可以使用:
npx jaireina/presentation
这将运行代码打印我放在那里的信息,就像这样
您还可以从分支运行代码。在下面的命令中,我正在运行多彩分支中的代码
你应该看到这样的东西
在h5 或者 原生app中(div,span,p等)元素点击事件不管用,button可以
解决:
给 div
span
p
元素添加 class (cursor: pointer)
或者加样式 style="cursor: pointer"
input 输入框在ios中会出现输入文字,但是不显示文字的情况
解决:
input,
textarea {
transform: translateZ(0px); // 解决问题
-webkit-transform: translateZ(0px);
position: relative;
outline: none; // 去除focus高亮
border: 0; // 去除border
}
input 框如果在底部fixed定位,因为键盘弹起收起的影响,input框的定位会错乱;
解决:
将body 或者最外侧的元素 设置 style="height: 100vh"
;
如何用rem布局移动端
解决:
/*
* 视口 rem 计算
* @Author: [email protected]
* @Date: 2019-08-28 15:07:00
* @Last Modified by: jianhui
* @Last Modified time: 2019-08-28 15:07:00
*/
(function(document, window) {
var sResizeEventName = 'orientationchange' in window ? 'orientationchange' : 'resize';
function fnPureResetRemValue() {
var clientWidth = window.innerWidth;
if (!clientWidth) return;
if (clientWidth >= 750) {
document.documentElement.style.fontSize = '100px';
} else {
document.documentElement.style.fontSize = 100 * (clientWidth / 750) + 'px';
}
}
fnPureResetRemValue();
window.addEventListener(sResizeEventName, fnPureResetRemValue, false);
})(document, window);
下图是帅华君用Illustrator制作的可视化信息图,希望能帮你理清Javascript对象与__proto__、prototype和原型链之间的关系。如果暂时看不懂也没关系,这篇文章让你从0变成1。
如果你打开浏览器的控制面板,随便输入一个JS内置的构造器函数,比如Array,控制台输出的是一个名为Array的函数体,这好像并没有什么稀奇的,但是,当你接着输入Array.prototype,控制面板输出了一堆我们经常用到的Array构造器的方法,把目光转移到最下方,有一个叫__proto__的属性,好奇的点开。
咦~?列表列出的不是Object构造器的方法么,里边有我们非常熟悉的hasOwnProperty还有toString等方法。我们常说的一切皆对象,一切对象皆null这么玄妙的编程界哲理和这种嵌套会不会有什么关系呢?更神奇的在下边。
继续深入思考,Array是构造器,那么控制台输出的Array.prototype的所有属性中的constructor(翻译:构造器)又是指向什么?点开看看,之后就像身处德罗斯特效应中一样,__proto__和constructor,还有Array构造器中常用的方法名不断的出现,一层套一层,一层层展开,没有尽头。
一、满满一堂证明题课
当你也发现了JS里这种循环往复、不断嵌套的规律后,仍然不相信自己的眼睛,于是决定亲自证明一下,哦不,是好几下。(对于初学者只靠空想太烧脑,于是帅华君录制GIF演示帮助读者理解。)
怎么证明你就是你?
这个问题可难不倒JS中的构造器们,一个证明秒秒钟证明“我就是我”,是颜色不一样的烟火。
拿Array举例,Array.prototype中有一个constructor属性,这个属性的值就是Array构造器自己。
所有的JS内置构造器都本是对象,这要从long long ago说起。可是从什么线索开始向过去前进呢,原型链(我给他起了一个名字叫遗传进化链)就是突破口。所有JS构造器(当然不止构造器有)都有一个__proto__属性,这是原型链指针,指向进化成它的“那个”。(就像我的__proto__指针指向我父母,我父母各自的__proto__指向他们的父母… …鬼知道最尽头的Ta经历了什么!?(手动黑人问号脸)。在进化的过程中,父母的遗传物质(属性、方法)被我的__proto__指针引用着,同时我也变异出了自己的能力(属性、方法),然后我的子代的__proto__指针又引用我的遗传物质。额!为毛突然莫名脸红~)
从上图中发现,JS内置构造器其中之一的Array原本就是一个函数,而这个函数就是Function的prototype,所以Function.prototype有的方法,JS内置构造器都有,比如call()、apply()、bind()等(其实我们自定义的函数也是继承自Function.prototype,所以我们自己也可以定义构造器,创造属于自己的小小王国)。(所以在编程的世界里模拟一个宇宙系统是有可能的,说不定我们本来就生活在被设定好的编程世界里哦。)
而Function.prototype的进化链指针又指向了Object.prototype。
证明到头来一切都是空???
不管你从那个属性开始,连续引用__proto__的指针,最后输出的那个值就是null。
万物都是从无生出来的???Hey boy 老聃的道德经han庄子读多了吧
证明所有JS内置构造器和自定义函数都是Function构造器的原型(prototype)
不断强化这一认知,实践出真知。
①、String构造器的进化链指针__proto__指向Function构造器的原型
//String构造器
String.Proto === Function.prototype
②、Number构造器的进化链指针__proto__指向Function构造器的原型
//Number构造器
Number.Proto === Function.prototype
③、Boolean构造器的进化链指针__proto__指向Function构造器的原型
//Boolean构造器
Boolean.Proto === Function.prototype
④、Array构造器的进化链指针__proto__指向Function构造器的原型
//Array构造器
Array.Proto === Function.prototype
⑤、没错,Function构造器的进化链指针__proto__也指向自己的原型
//Function构造器
Function.Proto === Function.prototype
⑥、Date构造器的进化链指针__proto__指向Function构造器的原型
//Date构造器
Date.Proto === Function.prototype
⑦;、Error构造器的进化链指针__proto__指向Function构造器的原型
//Error构造器
Error.Proto === Function.prototype
⑧、Object构造器的进化链指针__proto__指向Function构造器的原型
//Object构造器
Object.Proto === Function.prototype
⑨、RegExp构造器的进化链指针__proto__指向Function构造器的原型
//RegExp构造器
RegExp.Proto === Function.prototype
⑩、Event构造器的进化链指针__proto__指向Function构造器的原型
//Event构造器
Event.Proto === Function.prototype
这里需要注意所有构造器的prototype都是对象(object)类型,只有Function.prototype是函数(function)类型,这是为了保证函数构造器们的__proto__指向的都是函数。
二、咦???JSON和Math哪去啦
JS内置的构造器函数都可以使用new关键字实例化一个对象,我们称实例化后的这个对象就是某某构造器的一个实例。就像我们每一个“人”都是“人类”这个构造器函数的一个实例
//实例化一个String构造函数
var str = new String("Hi, today! ");
既然上边10个构造器函数都能这样实例化对象,那么JSON和Math是不是也可以用new 关键字实例化呢?试试看!
//尝试实例化JSON和Math两个构造器函数
var json = new JSON();
var Math = new Math();
OH NO!!! JSON和Math不是构造器函数,他们是普通的对象。
上边提到过,只有构造器函数才能使用new 关键字实例化一个对象,而JSON和Math已经是对象了,所以我们可以不用实例化直接使用JSON和Math中的属性和方法(我们实例化的目就是想用实例化后的对象里的属性和方法,那么既然JSON和Math已经是对象了,就省去实例化的操作喽。当然,能实例化有能实例化的好处~)
所以JSON和Math不属于10个构造器函数,但他们12个共同属于Javascript的内置对象。
三、__proto__进化链指针设计为什么如此重要!!
javascript中为什么会有__proto__原型链的设计,不防做一个小实验先。
//实例化一个String对象
var str = new String("Hi!")
我们先实例化一个String对象并将其赋值给str这个变量,然后我们输出这个str
从str输出的内容来看,str有四个属性,分别是0、1、2、length
//我们一个个输出这些属性
console.log(str[0]) //H
console.log(str[1]) //i
console.log(str[2]) //!
console.log(str['length']) //3
这毋庸置疑,但是接着往下看。
//charAt()是str对象中不存在的属性方法,但是没有报错,依然可以输出!
str.charAt(0) // 输出'H'
charAt()是str对象中不存在的属性方法,但是没有报错,依然可以输出!
这是为什么?这就是进化链__proto__的用处。
str这个对象本身的确没有charAt()这个方法,但是str的进化链上存在这个属性方法,那么charAt()这个方法在进化链的那个节点上呢?
哦~,原来String.prototype拥有charAt这个方法,而str的__proto__指针指向String.prototype
有小伙伴就问了,“那为什么我爷爷写得一手好毛笔字,可我却没遗传这一点呢?”“呵呵”
这么说的话,str.proto.__proto__指向的对象所拥有的属性str也都可以直接用喽?答案是肯定的!
看到str.proto.__proto__指向的对象所拥有的属性中有一个hasOwnProperty属性方法了么,str可以直接使用这个属性方法。
在验证之前先说下str.proto.__proto__指向了谁?指向的是Object的prototype属性。
str.proto.proto === Object.prototype // true
Object.prototype.hasOwnProperty()属性方法用来检验一个对象是否自己拥有一个属性而非通过进化链__proto__继承来的属性。
好的,实验开始:
//检查str是否拥有length属性
str.hasOwnProperty('length') //true
//检查str是否拥有0属性(str.charAt(0)的输出是'H')
str.hasOwnProperty(0) //true
//检查str是否拥有1属性
str.hasOwnProperty(1) //true
//检查str是否拥有2属性
str.hasOwnProperty(2) //true
//检查str是否拥有3属性(str的length是3,所以索引值从0开始,所以索引最大是2,所以没有3这个属性)
str.hasOwnProperty(3) //false
//str是否拥有hasOwnProperty这个属性呢?答案是否定的。
str.hasOwnProperty('hasOwnProperty') //false
当你弄清楚了原型链(我喜欢叫他进化链)proto,prototype之间的关系,还有Javascript中12个内置对象,其中10个函数类型,2个对象类型。再来学习这12个内置对象的属性和属性方法是不是如鱼得水,心里跟明镜似的。
对于Javascrip初学者,一时半会肯定还是搞不清楚,唯一的办法就是多观察、多思考、多模仿、多创新、多总结、多分享,学习的本质无非就是学会了这些,教育的本质无非就是教会你用学习的本质,学习你所感兴趣的。
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.