[].slice.call(arguments) 是如何工作的

首先 .slice 这个方法在不接受任何参数的时候会返回 this 本身,这是一个 Array.prototype 下的方法,因此 this 就是指向调用 .slice 方法的数组本身。

arguments 是什么? arguments 是属于函数内部的变量,其值是函数参数列表,一个类数组对象:

https://codepan.net/gist/edb0a855276de09d24ac0e5621957974

类数组对象可以像真正的数组对象一样操作,除了没有 length 属性,但这足以让 .slice 方法识别了。

你不可能用 arguments.slice() 这样的形式调用,因为 arguments 本身还是一个非数组对象,只是像数组。这个时候你想到了 .call 方法,这个方法让你可以自定义调用函数的内部 this 指向哪里,之前说过,默认是指向调用这个函数的对象。

1
2
3
Array.prototype.slice.call(arguments)
// output:
['hello', 'world']

这样你就得到了一个真正的参数数组了,而 .slice 除了通过 Array.prototype 访问当然还可以通过对象直接量访问:

1
[].slice.call(arguments)

wifiPineapple救砖记

去年对渗透测试很有兴趣的时候买了一个wifipineapple然后就开始了吃灰,昨晚拿出来玩了一会儿,发现二道子卖家同步更新到了官方2.4.2的版本,所以就想着升级一下,也是手贱,升级前想着用编程器把之前的固件保存下来,结果第二次用编程器,想偷懒没拆下flash就直接上了编程器读取固件,结果噩梦开始了。

不拆下flash直接上编程器,编程器上电的时候也带着soc一起工作了,结果就是编程器始终无法正确读取到flash的内容,想着既然没办法保存那就算了,然后就把主控又放了回去,结果就开不开机了,开机串口没打印了,顿时就慌了。

没办法只能把flash拆下来,用编程器重新读取了下,这次就能正常读取数据了,
下次一定注意 使用编程器的时候一定要把flash拆下来

现在重新保存编程器的固件,dump出16M的文件,用winhex读取,预计前面的uboot出现了问题,导致无法成功引导,在刷了几个固件再焊到主控上的过程中,因为烙铁操作太暴力还把焊盘弄掉了,看来买风枪需要提上日程了。

焊盘掉了两个

查了下winbond的flash的datasheet,发现其中一个是wp接口,路由器上肯定是接个下拉或者直接接地的,另外一个写的接口,这个口肯定不能少,用万用表打了一下,在板子反面找到了对应的过口,飞线接上,也不敢再这么瞎搞了,找到一片能兼容sop8的焊盘飞线搞定,热熔胶还正好用完了,只好双面胶固定焊点。

双面胶大法

查了主控是ar9331,原来跟我的wr720n是一个主控,以前啥都不知道就瞎买,现在终于懂了些,以后这些玩意儿应该不会被坑太多了。。

反正就是刷了很多ar9331的uboot,但是都没办法成功引导板子,最后想到了breed,breed 是支持ar9331的,在下载ar9331的通用引导文件,随后在winhex中新建一个16m的空白文件,先把所有的block都填充为FF(CTRL+A –> CTRAL+L),从00000000地址开始写写入breed,写128kb,随后在20000的偏移量地址开始写wifipineaplle的升级包(http://zy-link.xyz:8001/nano/fw/),升级包是一开始路由器还能正常工作的时候用路由器连接360wifi然后wireshark抓包抓到的,最后到偏移量`FF0000`地址

*4M固件应写在偏移量3F0000 
*8M固件应写在偏移量7F0000 
*16M固件应写在偏移量FF0000

然后用一开始提取出的art文件写入最后64k文件,最后保存这个16M的固件文件,保存后使用编程器写入到flash中,把flash重新连接主控,插上串口,上电,开机,看到窗口又在走字,就知道应该是救砖成功了。

串口打印

至此,wifipineapple救砖成功。

接下来想到既然是ar9331主控,那我的wr720n是不是也可以使用wifipineapple的固件?
不过目前有个问题就是这个固件是16m的但是我的wr720n只有8m的内置存储,需要一个16m的flash也应该容易,淘宝2块钱,但是周末就快到了,是时候再去一趟花鸟市场捡捡垃圾了,说不定能捡到一个呢。

解决新版本 Chrome 提示 DOMException: The play() request was interrupted

解决新版本 Chrome 提示 DOMException: The play() request was interrupted

大概在一些新版本的浏览器中,我们是用 audio 或者 video 进行媒体资源播放的时候,可能会在控制台看到这个输出:

Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().

OR

Uncaught (in promise) DOMException: The play() request was interrupted by a new load request.

触发方式:

1
2
3
4
5
6
<video id="video" preload="none" src="https://example.com/file.mp4"></video>

<script>
video.play(); // <-- This is asynchronous!
video.pause();
</script>

上面的代码会造成下面的异常错误:

Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().

上面的 video 的 设置了 preload = 'none',视频并没有提前加载,因此在触发 video.play() 并不能立即播放。

从 Chrome 50 的版本后 触发 video.play() 会返回一个 Promise 对象 ,如果播放成功,则 Promise 会触发,然后 playing 事件同时也会触发。如果播放失败,则会触发 Promise 的 reject,参数会带有错误的信息。

现在触发的顺序:

1
2
3
1. video.play() 异步的去加载 video 内容,
2. video.pause() 中断视频的加载,因为视频并没有就绪
3. video.play() 异步的 rejects

因为我们并没有处理 video.play 的 Promise ,然后一个错误的信息会暴露出来。

video.pause() 不光会打断一个视频的播放,而且会完全重置一个视频的播放的状态,包括 buffer 和 video.load

修复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<video id="video" preload="none" src="https://example.com/file.mp4"></video>

<script>
// Show loading animation.
var playPromise = video.play();

if (playPromise !== undefined) {
playPromise.then(_ => {
// 这个时候可以安全的暂停
video.pause();
})
.catch(error => {

});
}
</script>

如今现在 HTMLMediaElement.play() 支持返回 Promise 已经在 Chrome, Firefox, Opera, 以及 Safari Edge 实现了。

Stylus两分钟入坑

下面中规中矩的CSS代码是否看得眼睛生茧了?

1
2
3
4
5
6
7
8
body {
font: 12px Helvetica, Arial, sans-serif;
}
a.button {
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}

好,去掉花括号

1
2
3
4
5
6
7
body
font: 12px Helvetica, Arial, sans-serif;

a.button
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;

去掉分号

1
2
3
4
5
6
7
body
font: 12px Helvetica, Arial, sans-serif

a.button
-webkit-border-radius: 5px
-moz-border-radius: 5px
border-radius: 5px

还有你冒号

1
2
3
4
5
6
7
body
font 12px Helvetica, Arial, sans-serif

a.button
-webkit-border-radius 5px
-moz-border-radius 5px
border-radius 5px

来点函数

1
2
3
4
5
6
7
8
9
10
border-radius()
-webkit-border-radius arguments
-moz-border-radius arguments
border-radius arguments

body
font 12px Helvetica, Arial, sans-serif

a.button
border-radius(5px)

加点混合书写

1
2
3
4
5
6
7
8
9
10
border-radius()
-webkit-border-radius arguments
-moz-border-radius arguments
border-radius arguments

body
font 12px Helvetica, Arial, sans-serif

a.button
border-radius 5px

加点模块化

1
2
3
4
5
6
7
@import 'vendor'

body
font 12px Helvetica, Arial, sans-serif

a.button
border-radius 5px

甚至是语言函数

1
2
3
4
5
6
sum(nums...)
sum = 0
sum += n for n in nums

sum(1 2 3 4)
// => 10

好了,你得到了Stylus

Gulp学习笔记

个人理解gulp是前端开发过程中对代码进行构建的工具,是自动化项目的构建利器,可以方便我们进行项目开发的工具。

她能自动化地完成
javascript/coffee/sass/less/html/image/css 等文件的的测试、检查、合并、压缩、格式化、浏览器自动刷新、部署文件生成,并监听文件在改动后重复指定的这些步骤。

  1. 安装
    1
    npm install -g gulp

一般除了安装gulp外还会安装一些gulp的其他插件比如gulp-uglify,gulp-contact

  1. gulpfile.js

gulpfile.js是gulp的配置文件,gulp根据gulpfile.js来执行任务

在项目根目录创建一个gulpfile.js

1
2
3
4
5
6
7
8
9
var gulp = require('gulp');
var uglify = require('gulp-uglify');

gulp.task('uglify', function () {
console.log('start job!')
gulp.src('js/app.js')
.pipe(uglify())
.pipe(gulp.dest('build'))
});

上面代码中,gulpfile.js加载gulp和gulp-uglify模块之后,使用gulp模块的task方法指定任务minify。task方法有两个参数,第一个是任务名,第二个是任务函数。在任务函数中,使用gulp模块的src方法,指定所要处理的文件,然后使用pipe方法,将上一步的输出转为当前的输入,进行链式处理。

task方法的回调函数使用了两次pipe方法,也就是说做了两种处理。第一种处理是使用gulp-uglify模块,压缩源码;第二种处理是使用gulp模块的dest方法,将上一步的输出写入本地文件,这里是build.js(代码中省略了后缀名js)。

执行minify任务时,就在项目目录中执行gulp uglify

  1. task()

gulp新建任务的格式

1
gulp.task(name[, deps], fn)

name 任务名字,类型:字符串;

deps 当前任务依赖的任务,这些任务会在你当前任务运行之前完成,类型:Array;例如

1
2
3
gulp.task('mytask', ['array', 'of', 'task'], function() {
// do something
});

上面指定的mytask任务由三个指定的任务组成执行mytask任务时会并发执行array,of,task三个任务,所以是异步调用

此外

1
2
3
gulp.task('default', function() {
// do default job
});

是执行默认任务,在项目目录中输入gulp就会执行

  1. wacth()

watch方法用于指定需要监视的文件。一旦这些文件发生变动,就运行指定任务。

1
2
3
gulp.task('watch', function () {
gulp.watch('templates/*.tmpl.html', ['build']);
});

上面代码指定,一旦templates目录中的模板文件发生变化,就运行build任务。

1
2
3
4
watch方法也可以用回调函数,代替指定的任务。
gulp.watch('templates/*.tmpl.html', function (event) {
console.log('file changed')
});
  1. gulp-load-plugins模块
    一般情况下,gulpfile.js中的模块需要一个个加载。
1
2
3
4
5
6
7
8
9
10
11
12
13
var gulp = require('gulp'),
jshint = require('gulp-jshint'),
uglify = require('gulp-uglify'),
concat = require('gulp-concat');

gulp.task('js', function () {
return gulp.src('js/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(uglify())
.pipe(concat('app.js'))
.pipe(gulp.dest('build'));
});

上面代码中,除了gulp模块以外,还加载另外三个模块。

这种一一加载的写法,比较麻烦。使用gulp-load-plugins模块,可以加载package.json文件中所有的gulp模块。上面的代码用gulp-load-plugins模块改写,就是下面这样。

1
2
3
4
5
6
7
8
9
10
11
12
var gulp = require('gulp'),
gulpLoadPlugins = require('gulp-load-plugins'),
plugins = gulpLoadPlugins();

gulp.task('js', function () {
return gulp.src('js/*.js')
.pipe(plugins.jshint())
.pipe(plugins.jshint.reporter('default'))
.pipe(plugins.uglify())
.pipe(plugins.concat('app.js'))
.pipe(gulp.dest('build'));
});

当然,这么做的前提是node_modules里要先安装依赖

背景图片虚化css

#记录一下css的背景图片虚化模糊的样式

1
2
3
4
5
6
<body>
<div class="cover">
你好
</div>
</body>
<
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.cover{
width:400px;
height:400px;
border:1px solid red;
position:relative;
}
.cover::after{
content:'';
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
background: transparent url(http://p1.music.126.net/_ZIyHUML8sXBvJXqLdQDOg==/105553116278617.jpg?imageView&thumbnail=360x0&quality=75&tostatic=0) no-repeat center;
filter:blur(5px)
}

DOM学习总结

总结 + 我认为的重点

  1. 搜索归纳,以掌握 DOM 基本思想

  2. DOM 的作用 === 表示 HTML 文档

  3. DOM提供的 API === 查询,修改 HTML 文档内容

  4. 输入document.documentElement来获得 html 节点

  5. 只有Node.querySelectorAll()返回的数组不是动态的

  6. scrollHeight返回的是高度

  7. scrollTop返回的是滚动高度

对 DOM 的一些理解

  1. DOM === 想象的树型结构模型.

  2. DOM提供的API的作用就是修改或者查看 HTML 代码

  3. DOM中的O指的是Object,他是在内存中,按照树型结构,通过构造函数(如Node,Element(翻译为标签比较好),Document三个构造函数),构造出对象,将 DOM 展现到内存中

  4. DOM的D指的是Document,可以认为是 HTML 文档

  5. DOM的M指的是Model,因为在 HTML结构 在内存中不好用笔表示,所以用一个模型来表示,这个模型就是树型结构

  6. DOM 树型结构

    未命名文件 (4).png

    1. 上图就是DOM,其中的每个节点(包括矩形节点和椭圆形节点)都是Node类型

    2. document节点是Document构造函数的一个实例对象,document节点代表了整个文档(整个树型结构

      ,我们可以通过直接输入document来获取document节点

    3. html节点是Element构造函数的一个实例对象,html节点又叫根节点

      我们可以通过输入document.documentElement来获得html节点

    4. 椭圆形的文本节点:”你好,我叫饶家俊” 是Text构造函数的一个实例对象(文本节点是Text构造函数的一个实例对象)

    5. Node,Element,Text的关系

      未命名文件 (5).png

DOM的归纳和总结

  1. JavaScript将 HTML 文档渲染成 DOM 的树型结构.

  2. 有了树形结构, 第一件事情是什么?当然是获取DOM的节点啦!

  3. 获得节点的方法:

    1. 直接在DOM寻找: document.querySelector(AAAA)document.querySelectorAll(AAAA)
    2. 通过节点关系获得节点
      1. 兄弟关系
      2. 儿子关系
      3. 父关系
  4. 获得节点后,首先你要了解获得的节点是什么吧(比如你要知道节点是什么类型)?

    了解节点:

    1. Node.nodeName
    2. Node.nodeType
    3. Node.textContent
  5. 既然节点可以对应 HTML 文档的标签,那么我可不可以通过 DOM 来处理标签的属性?搜索处理标签属性知道所有属性的处理方法.

  6. 我可以通过 DOM 的 API 修改 DOM 的结构吗?

    1. 创建节点

      document.createElement("div")生成Element节点

      document.createTextNode("你好,我叫饶家俊")生成Text节点

    2. 通过Node方法将创建的节点拼接到 DOM 中,搜索Node方法

Node类型的一些属性和方法

Node属性

  1. 节点本身某些特征的属性:
    • Node.nodeName:
      • 看着DOM,如果你不确定某个Node节点是什么类型(不确定某个Node节点是矩形还是椭圆形)
        • 返回节点类型,重要的返回的值有大写的HTML元素名, #text ,#document
    • Node.nodeType:
      • 根据Node类型返回某些数字
      • Element类型,返回的数字是1
      • Text类型,返回的数字是3
      • Document类型,返回的数字的9
    • Node.textContent
      • 返回的当前节点及其所有后代的文本内容
      • 值得注意的是,因为Node.textContent是Node属性,所以文本节点也是有textContent的
      • innerHTMLinnerText是Element的属性,所以TextNode.innerHTML返回的是undefined,注意,并不是返回null
  2. 节点结构关系属性
    • 兄弟关系
      • Node.nextSibling
      • Node.previousSibling
    • 儿子关系
      • Node.childNodes
      • Node.firstChild
      • Node.lastChild
    • 父关系
      • Node.parentNode
    • 上面的所有关系属性都可以获取到Text节点(除了父关系)
    • Node.childNodes是最特殊的,它返回的是一个伪数组,里面是Node节点,并且伪数组内的值是动态变化的

Node方法

  • Node.appendChild()
  • Node.hasChildNodes()
  • Node.cloneNode()
  • Node.insertBefore()
  • Node.removeChild()
  • Node.replaceChild()
  • Node.contains()
  • Node.isEqualNode()
  • Node.isSameNode()
  • Node.normalize()

document节点的一些属性和方法

document属性

  1. 用于指向其他节点(快捷获取某些特殊节点)的属性

    • document.documentElement指向 DOM 的 html节点
    • document.activeElement指向获得焦点的那个节点
  2. 返回文档特定元素的伪数组集合的属性

    • document.links
    • document.forms
    • document.images
    • document.embeds
    • 等等
  3. 返回文档信息的属性

    • document.location
    • document.readyState返回的是当前文档的状态,
    • 等等

document获取节点方法

  1. 方法:document.querySelector(AAAA)document.querySelectorAll(AAAA)

  2. 注意点:

    • 如果获取标签,那么直接AAAA === “div” 即可
    • 第一个返回的是第一个符合CSS选择器AAAA条件的节点
    • 第二个返回的是伪数组,里面包含了所有符合选择器的节点
    • 第二个返回的结果不是动态的,不会实时反映元素节点的变化
    • 这两个方法除了是 document ,还可以是某个 Node 节点
    • 其他查找方法不学,没有必要

document生成节点的方法

  1. document.createElement("div")生成Element节点
  2. document.createTextNode("你好,我叫饶家俊")生成Text节点

document事件相关的方法

待续

document写入方法

待续

Element节点的一些属性和方法

属性

  1. Element节点的属性处理

    搜索处理标签属性

  2. 盒模型相关属性

    1. 获得整个页面高度:document.documentElement.scrollHeight

    2. 获得整个浏览器视口的高度document.documentElement.clientHeight // 不包括滚动条

    3. 某个Element距离浏览器视口左上角的坐标

      • Element.getBoundingClientRect().left
      • Element.getBoundingClientRect().top
    4. 某个Element距离整个网页左上角的坐标(,注意和上一个区别)

      • Element.getBoundingClientRect().left + document.documentElement.scrollLeft
      • Element.getBoundingClientRect().top + document.documentElement.scrollTop
    5. 下面的可以不看了,等到遇到问题的时候再看

    6. 容器 === 浏览器的可视区域

    7. Node.clientHeight,Node.clientWidth

      • 某个 Element节点: 经过浏览器视口变化,返回节点所占据整个页面的高度和宽度(只有padding,margin和border不是)
      • html节点: 返回浏览器视口宽度和高度
    8. Node.clientTop,Node.clientLeft

      • 返回节点的左边框(border)和上边框(border)的边框宽度
    9. Noe.scrollHeight, Node.scrollWidth

      • 某个Element节点: 经过浏览器视口变化,返回节点所占据整个页面的高度和宽度(只有padding,margin和border不是)
      • html节点: 经过浏览器视口变化,返回整个页面的高度和宽度
    10. Node.scrollLeft, Node.scrollTop

    • 返回向下的滚动条和向右的滚动条滚动的像素
    1. Node.offsetHeight, Node.offsetWidth
    • 某个 Element节点: 经过浏览器视口变化,返回节点所占据整个页面左上角距离右下角的宽度和高度,并且左上角是包括padding和border
    • html节点: 经过浏览器视口变化,返回整个页面的高度和宽度
    1. Node.offsetLeft,Node.offsetTop
    • 与父节点之间的宽度和高度???

处理标签属性

  1. 最正常,也最麻烦的写法

    1. 增:Node.setAttribute("属性名", "属性值")
    2. 删: Node.removeAttribute("属性名")
    3. 改: Node.setAttribute("已经存在属性名", "新属性值")
    4. 查:Node.getAttribute("属性名")
  2. 但是,对于标准属性来说,可以写的简单一点

    1. 增:Node.style = "border: 10xp solid black"
    2. 删: 无法简写
    3. 改: Node.style = "border: 10px solid red"
    4. 查:Node.style
  3. 对于标准属性的 class 属性来说,因为它实在是太重要了,所以对于class属性也有一套方法:

    1. 首先获得包含所有属性的伪数组Node.classList

    2. 伪数组有以下方法:

      1
      2
      3
      4
      5
      6
      add():追加一个class。
      remove():移除一个class。
      contains():检查当前元素是否包含某个class。
      toggle():将某个class移入或移出当前元素。
      item():返回指定索引位置的class。其实用divTag.classList[1]这样更好
      toString():将class的列表转为字符串。

题目

  1. HTML 代码
1
<div id=parent></div>

​ 问: parent的值是多少?

  1. HTMLCollection与NodeList的区别有 答案: AC

    A. HTMLCollection实例对象的成员只能是Element节点,NodeList实例对象的成员可以包含其他节点。

    B. HTMLCollection实例对象都是动态集合,节点的变化会实时反映在集合中。NodeList实例对象都是静态集合。

    C. HTMLCollection实例对象可以用id属性或name属性引用节点元素,NodeList只能使用数字索引引用。

  2. 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var parent1 = document.getElementById('parent1');
    parent1.childNodes.length // 2
    parent1.appendChild(document.createElement('div'));
    parent1.childNodes.length // 请问现在 length 是多少 答案是3

    var allDiv = document.querySelectorAll('div')
    allDiv.length // 假设是 2
    document.body.appendChild( document.createElement('div') )
    allDiv.length // 请问现在 length 的值是多少??? 答案是2

    答案的原因不是什么动态集合与静态集合,而是第一次的代码重新进行一次查询,而第二次的代码并没有重新进行查询,如果想让第二次的答案是3,那么把第二次的最后一句代码删去,并加上allDiv = document.querySelectorAll('div');allDiv.length就行了

JavaScript中call(),apply(),bind()用法的理解

其实做题时并不了解这三个方法的用法,但是稍微学习了一下,网上的资料很丰富,马上就知道了,记录下,做个备忘.

例1
1
2
3
4
5
6
7
8
9
10
11
var name = '张三',age=20;
var obj={
name:"李四",
objAge:this.age,
myfun:function(){
console.log(this.name+"年龄"+this.age);
}
}

obj.objAge //20
obj.myFun() //李四年龄undefined
例2
1
2
3
4
5
6
var name = "张三";
function getName(){
consol.log(this.name);
}

getName() //张三

比较一下这两者this 的差别,第一个打印里面的this 指向obj,第二个全局声明的getName()函数this 是window ;

  1. call()、apply()、bind() 都是用来重定义 this 这个对象的!
如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var name = "张三",age= 20;
var obj={
name:"李四",
objAge:this.age,
myfun:function(){
console.log(this.name+"年龄"+this.age);
}
}
var obj2={
name:"王二",
age:40
}

obj.myFun.call(obj2);    //王二年龄40
obj.myFun.apply(obj2);    //王二年龄40
obj.myFun.bind(obj2)();   //王二年龄40

以上出了bind 方法后面多了个()外 ,结果返回都一致!由此得出结论,bind() 返回的是一个新的函数,你必须调用它才会被执行

  1. 对比call(),apply(),bind()传参的情况下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    var name = "张三",age= 20;
    var obj={
    name:"李四",
    objAge:this.age,
    myfun:function(fm,t){
    console.log(this.name+"年龄"+this.age,"来自"+fm+"去往"+t);
    }
    }
    var obj2={
    name:"王二",
    age:40
    }

      obj.myFun.call(obj2,'成都','上海');     //王二 年龄 40 来自 成都去往上海
      obj.myFun.apply(obj2,['成都','上海']); //王二 年龄 40 来自 成都去往上海
      obj.myFun.bind(obj2,'成都','上海')(); //王二 年龄 40 来自 成都去往上海
      obj.myFun.bind(obj2,['成都','上海'])();   //王二 年龄 40 来自 成都,上海去往undefined
从上面四个结果不难看出
  • call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象,第二个参数差别就来了:
  • call的参数是直接放进去的,第二第三第n个参数全都用逗号分隔,直接放到后面 obj.myFun.call(db,’成都’, … ,’string’ );
  • apply的所有参数都必须放在一个数组里面传进去 obj.myFun.apply(obj2,[‘成都’, …, ‘string’ ]);
  • bind除了返回是函数以外,它的参数和call 一样。
        
      当然,三者的参数不限定是string类型,允许是各种类型,包括函数 , object 等等!

jQuery不过如此

从DOM原生API开始说起,
想要获取页面上的一个节点,对它做一些为所欲为的事情我需要:

1
var 这个节点 = document.getElementById('这个节点的id')

接下来,要是我想点击它,让他藏起来我需要:

1
2
3
这个节点.onclick = function(){
这个节点.style.display = 'none'
}

我想看看这个节点有哪些兄弟元素:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function getSiblings(node){
var allChildren = node.parentNode.children

//这只是一个哈希,伪数组
var array = {
length: 0
}
for(let i =0;i < allChildren.length;i++){
if(allChildren[i] !== node){
array[array.length] = allChildren[i]
array.length +=1
}
}
return array
}

或者想给这个节点添加多个Class

1
2
3
4
5
6
7
8
9
10
function addClass(node,classes){
for(let key in classes){
var value = classes[key]
if(value){
node.classList.add(key)
}else{
node.classList.remove(key)
}
}
}

Read More

js里的对象

什么是标准库?
  • js的内存里面有两种东西,一个是stack(栈内存),一个是heap(堆内存),stack里面有个特别重要的变量叫做global,在浏览器里面叫做window,他们是一样的都是同一个对象。window是一个对象,window就对应heap里面一块内存,window是一个哈希表,哈希表里面的东西分两部分,一部分就叫做标准库,另一部分叫做非标准库。

  • 标准库包括哪些呢?比如Object()函数,这个函数也是个对象,它有一个key()属性,create()方法;还有String()函数,Nubmer()函数,Array()函数,Boolean()、Function()。

    图示:

简单类型跟复杂类型加new与不加的区别
  • 给Object传什么它就会把它包装成一个什么对象,传给它一个1就把1包装成Number对象,给它一个字符串就包装成一个字符串对象,如果什么都不给就会生成一个空对象;对于Object来说加不加new都一样。如下图:

  • String是将给的东西变成一个字符串常量(非对象,基本类型),如果加new就会生成String对象如下图:

  • Number与String同理,给Number一个不能变成数字的东西变成NaN,给一个可以变的变成number常量,如果加了new就会返回一个number对象。如下图:

  • Boolean会把提供的任何东西变成一个布尔值,另外记住5个falsy值(0、NaN、’’、null、undefined),new Boolean则会返回一个Boolean 对象如下图:

  • 所以除了Object加或者不加new没区别,其余的类型加new都会返回一个相应的对象。

  • 总结,全局变量分两种,一种是对应的原本是七种数据类型中的基本类型(number、string、boolean)(null、undefined没有构造函数);另一种跟对象相关的obejct(包括两种特殊的obejct,array和function);如果是基本类型对应的构造函数,加new与不加new的区别就是,不加new的时候返回一个基本类型,如果加了new返回一个复杂类型(对象);如果是object复杂类型,加new不加new是一样的。都返回一个对象。
新的API Array

Array是一个构造数组的全局对象(七种数据类型Nubmer、String、Boolean、Symbol、null、undefined、Object[Array、Function])

创建数组:

1
2
let f = ['a','b']
let f = new Array('a','b') //两种写法等价

Array构造函数的两种用法:一个或者多个参数

1
2
3
4
var a = Array(3)
//生成一个长度为给的数字(3)的数组,不含0,1,2,有三个undefined,第一个参数是长度
var a = Array(3,3)
//当是一个参数的时候,第一个参数是长度,当有两个参数的时候,第一个参数不是长度,它是第一项

首先第一种用法var a = Array(3),它会生成一个长度为3,每一个都是undefined的数组a[0]是undefined,a[1]是undefined,a[2]也是undefined;但是又不在a里面,也就是说a没有012,这时候最好画内存图,在研究数据的时候最好的方式就是画内存图。

console图如下:

内存图演示,当写var a = Array(3)的时候到底做了什么,在stack里面声明了一个地址,a指向这个地址(ADR99),heap对应的ADR99里面存了一个length:3以及一个__proto__指向Array.prototype(Array的公有属性);也就是说当写var a = Array(3)的时候它生成了一个对象,这个对象里面写了一个length:3以及--proto指向公有属性(Array.prototype),公用属性里面还包括一些pushshift之类的函数。0,1,2,3并没有存到heap对应的ADR99中。内存图解如下:

再来重新看代码a.length // 3对应上图中的length:3,a.push函数也是存在的,因为可以在公用属性__poroto__找到,可以通过console.dir(a)把a打印出来。a的第一层只有length: 3以及__poroto__:Array(0)指向的一个哈希函数(a.__proto__等于等于Array.prototype(Array构造它的函数))


第二种用法var a = Array(3,3),当有两个参数的时候,第一个参数不是长度,它是第一项

如图:


所以var a = Array(3)var a = Array(3,3)对应的东西并不相同,同样是3,同样的位置,同一个函数却因为参数个数不同而不相同,这叫做JS的不一致性,这也是JS的缺点所在如图:


由于Array也属于Object,所以Array加不加new并没有区别。

Function

类比array的var a = new Array(1,2,3)var a = [1,2,3]写法function也有可有有下面两种写法。

1
2
3
4
5
var f = function(a,b){
return a+b
} // f(1,2) 返回3
//上面可以用它的构造函数构造出来
var f = new Founction('a','b','return a+b') //f(1,2)同样返回3

函数有参数,必须有返回值return a+b 同时可以用它的构造函数构造出来。先传一个字符串表示第一个参数 名字,再传一个字符串表示第二个参数名字,最后传一个字符串表示函数体'return a+b'

new Function的用法就是把所有东西变成字符串依次排开

1
var f = new Function('a','b','return a+b')

MDN语法

1
2
new Function ([arg1[, arg2[, ...argN]],] functionBody)
//用[]标的叫做可选,意思是可以只传一个参数,两个参数或者N个参数,也可以不传参数只传函数体,另外加不加new没区别。
Function与function的区别
  • function是关键字,是函数的意思,没有任何意义,同样的关键字还有(var、if、else等等),下面举例

    1
    2
    3
    4
    var  //声明一个变量
    var a = 1 //声明一个a,a不一定是函数
    function //声明一个函数
    function f(){} //声明一个f,f一定是个函数
  • Function是一个全局对象

    1
    2
    window.Function
    window.Object
  • 七种基本类型(number、string、boolean、symbol、null、undefined、object)的大小写无所谓,因为它们只是一个字符串,例如字符串它的英文是string用大写String表示也可以仅此而已。举例声明一个string

    1
    var s = new String()   //因为没有小写string这个关键字,所以用String,

    同理function就是表示函数的意思关键字,跟代码没有任何关系。声明函数必须用function f

  • 声明一个函数的两种方法,function跟Function都可以,记住分别怎么用就行了。

    1
    2
    function f(){}
    var f = new Function('x','y','x+y') //用一个变量去引用一个对象,另外new可以省略。
  • 声明函数的几种方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    具名函数 
    function f(x,y){ //x,y是参数,可以没有
    return undefined //一定要有return,就算不写也会自动加一个undefined
    }
    匿名函数
    function (){
    return
    }
    Funtion //一般不用这个方法
    new Function('x','y','x+y')
    //前两种用关键字声明函数,最后面的是用全局对象在声明一个对象函数.
  • 拆解

    1
    2
    3
    4
    5
    6
    7
    var a = 1 //变形成成下面
    var a
    a = 1

    var f = function(){}//变形成下面,所以这是两句话,声明函数只有上面两种方法(关键字和new Function)
    var f //先去声明一个f变量
    f = function(){} //然后让f等于一个匿名函数,内存图如下

    如果现在让f=1那么就会将stack里面的A88地址擦掉换成1,中间的联系就会断掉,但是函数function(){}还在,f跟function没有任何关系.var f = function(){}是两步,一步是弄一个变量f一步是弄一个对象function(){}然后将它们联系起来,所以var f = function(){}不是一个语法,声明函数只有上面两种方法(关键字和new Function)

  • 具名函数跟匿名函数的区别

    具名函数一步做到初始化然后赋值,匿名函数是先声明一个变量f,然后再弄一个匿名函数,然后把变量f指向function (){}分两步.


    数组&a.forEach