高级函数
- sort函数
var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
if (x < y) {
return 1; // 返回1代表需要位置互换
}
if (x > y) {
return -1; // 返回-1代表不需要互换
}
return 0;
}); // [20, 10, 2, 1]
- filter函数
var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
console.log(element); // 依次打印'A', 'B', 'C'
console.log(index); // 依次打印0, 1, 2
console.log(self); // self就是变量arr
return true;
});
var arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
var r = arr.filter(function (element, index, self) {
return self.indexOf(element) === index; // indexOf函数获取array中某个元素的下标
});
作用域
在JavaScript中,我们可以将作用域定义为一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套的子作用域中根据标识符名称进行变量查找。
这里的标识符,指的是变量名或者函数名。
作用域与执行上下文是完全不同的两个概念。
JavaScript代码的整个执行过程,分为两个阶段:
代码编译阶段与代码执行阶段
编译阶段由编译器完成,将代码翻译成可执行代码,这个阶段作用域规则会确定,对于函数,是函数的定义过程。
执行阶段由引擎完成,主要任务是执行可执行代码,执行上下文在这个阶段创建,是函数的调用过程。
function a(){ //函数定义
console.log(1);
}
a() //函数调用
执行上下文
执行上下文(Execution Context)。
每次当控制器转到可执行代码的时候,就会进入一个执行上下文。执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。
全局环境:JavaScript代码运行起来会首先进入该环境
函数环境:当函数被调用执行时,会进入当前函数中执行代码
var color = 'blue';
function changeColor() {
var anotherColor = 'red';
function swapColors() {
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
}
swapColors();
}
changeColor();
函数定义阶段——闭包
作用域链:是由当前环境与上层环境的一系列变量对象组成,它保证了当前执行环境对符合访问权限的变量和函数的有序访问。
var a = 20;
function test() { // 执行上下文A
var b = a + 10;
function innerTest() { // 函数B
var c = 10;
return b + c;
}
return innerTest();
}
test();
闭包:设有函数B是在执行上下文A内定义的。如果B内部访问了A内的变量对象,则产生闭包。
闭包的重要特点是,执行上下文A出栈后不会被内存回收,也就是说B依然可以访问到原来定义时的数据。�
var fn = null;
function foo() {
var a = 2;
var c = 100;
function innnerFoo() {
// console.log(c); // 在这里,试图访问函数bar中的c变量,会抛出错误
console.log(a);
}
fn = innnerFoo; // 将 innnerFoo的引用,赋值给全局变量中的fn
}
function bar() {
var c = 100;
fn(); // 此处的保留的innerFoo的引用
}
foo();
bar();
函数执行阶段——变量对象
变量对象的创建过程:
变量对象的创建,依次经历了以下几个过程。
- 建立arguments对象。检查当前上下文中的参数,建立该对象下的属性与属性值。
function test(x,y){
console.log(arguments);
console.log(x);
console.log(y);
}
test(1,2);
检查当前上下文的函数声明,也就是使用function关键字声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在内存地址的引用。如果函数名的属性已经存在,那么该属性将会被新的引用所覆盖。
检查当前上下文中的变量声明,每找到一个变量声明,就在变量对象中以变量名建立一个属性,属性值为undefined。如果该变量名的属性已经存在,为了防止同名的函数被修改为undefined,则会直接跳过,原属性值不会被修改。
// demo1
function foo() { console.log('function foo') }
var foo = 20;
console.log(foo); // 20
console.log(foo); // function foo
function foo() { console.log('function foo') }
var foo = 20;
// demo2
function test() {
console.log(a);
console.log(foo());
var a = 1;
function foo() {
return 2;
}
}
test();
// demo3
function test() {
console.log(foo);
console.log(bar);
var foo = 'Hello';
console.log(foo);
var bar = function () { // 函数的赋值
return 'world';
}
function foo() { // 函数的声明
return 'hello';
}
}
test();
var/let/const
var 声明的变量在当前函数内一直存在。
function (){
...生效...
}
let / const 声明的变量只在当前代码块
({}包裹起来的为一个代码块,但不是只有{}产生代码块,如if后可以没有{}的情形)
中存在,前者为变量,后者为常量(ES6)。
function test(){
{
let a = 1;
var b = 1
}
console.log(b)
console.log(a)
}
延时执行,定时执行
- setTimeout
for(var i = 0; i<5; i++){
setTimeout(function(){
console.log(i)
}, i*1000)
}
// 5 5 5 5 5
for (var i=1; i<=5; i++) {
setTimeout((function(i) {
return function() {
console.log(i);
}
})(i), i*1000 );
}
// 0 1 2 3 4
for(let i = 0; i<5;i++){
setTimeout(function(){
console.log(i)
}, i*1000)
}
// 0 1 2 3 4
- setTimeInterval
- clearTimeInterval
操作DOM
- innerHTML
- innerText
- style
- appendChild
<p id="js">JavaScript</p>
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
</div>
var js = document.getElementById('js'),
list = document.getElementById('list');
list.appendChild(js);
- document.createElement
- insertBefore(newElement, referenceElement)
- removeChild
作业
- 写出“函数执行阶段——变量对象”这一节的demo3的执行顺序。
-
使用原生javascript实现一个to-do list