JavaScript基本操作

这是一个目录

  • JavaScript基本操作
    • 最基本的基本操作
    • 变量作用域
    • 方法
      • 理解this关键字
      • Function.apply()
      • 装饰器
    • 高阶函数
      • Array.map()
      • Array.reduce()
      • Array.filter()
      • Array.sort()
      • etc
    • 闭包
    • 箭头函数
    • 生成器

JavaScript基本操作

更详细全面的 JavaScript 讲解

先立一个flag,如果不留校集训的话过年之前把那个三百多行的代码读透了。

最基本的基本操作

var name = zrd;
console.log(`Hello, ${
       name}!
这是
多行
字符串`)

//数组操作
a.unshift(); a.shift();		//在开头添加、删除元素
a.splice(x, k, args);		//从索引x开始删除k个元素,再在该位置添加args这些元素,返回删除的元素
a.concat(b);				//返回a, b合并的数组
[1, 2, 3, 'a'].join('-');	//'1-2-3-a'
var s = [1, 2, 3], t = [1, 2, 3];
s === t						//false

//对象
var student = {
     
	name: 'zhangruida',
	gender: 'female'		//最后一个键值对不在末尾加逗号
};
delete student.gender;
'gender' in student;		//false
'toString' in student;		//true(该属性是student继承得到的)
student.hasOwnProperty('toString');	//false
Map.has(key); Map.set(key, value); Map.delete(key); Map.get(key); Set.add(key)var a = ['a', 'b', 'c', 'd'];
for (var i in a) {
     
	console.log(i);			//'0', '1', '2', '3' (数组是对象,因此返回属性(不包括length,但是包括你添加的属性))
}
for (var i of a]) {
     
	console.log(i);			//'a', 'b', 'c', 'd' (只返回集合本身元素)
}
a.forEach(function(element, index, array) {
     	//每次迭代自动回调该函数
	console.log(element + ', index = ' + index);	//A, index = 0...
}

//函数
//以下两种声明方式等价
var abs = function (x) {
     ...};
function abs(x) {
     ...}
var test = abs(-1, undefined, 'whatever');	//传入参数可以比定义的参数多或少
function foo(a, b, ...rest) {
     
	console.log(rest);		//rest拿到其余所有参数
	console.log(arguments);	//arguments永远拿到所有参数
}	

注意: reverse(), sort(), splice() 都是直接修改原数组。

变量作用域

js中全局变量、函数默认被绑定到windows上。如果不同的js文件用了相同的全局变量或者顶层函数,会导致错误。

for (var i = 0; i < 100; i++) {
     ...}
i++;	//仍可以使用i,因为js局部作用域仅限于函数内部
for (let i = 0; i < 100; i++) {
     ...}
i++;	//SyntaxError (let声明作用域块级作用域的变量)
const PI = 3.1415927;	//const常量块级作用域

var [x, [y, z]] = [1, [2, 3]];
[, , z] = [1, 2, 3];

var zrd = {
     name: 'ksj', gender: 'male', school: 'No.2 middle school', hobbies: {
     first: 'eating', second: 'sleeping'}};
var {
     name, school} = zrd;	//name = 'ksj', school = 'No.2 middle school'
var {
     gender, hobbies: {
     second}} = zrd;	//gender = 'male', second = 'sleeping'
({
     gender, hobbies: {
     second: sec}} = zrd;)	//second存到sec里;大括号位于开头会被认为是代码块,因此要用小括号括起来{
     name, single=true} = zrd)

方法

理解this关键字

var zrd = {
     
	name: 'super little da da',
	birth: 2020,
	age: function () {
     
		var y = new Date().getFullYear();
		return y - this.birth;	//这里的this就是zrd这个变量
	}
};

但如果这样就会有问题:

function getAge() {
     
	var y = new Date().getFullYear();
	return y - this.birth;	//这里的this指向window,因此this.birth是undefined,在strict模式下这里的this会指向undefined,会报错
}
var zrd = {
     
	name: 'super little da da',
	birth: 2020,
	age: getAge()
};
getAge();

Function.apply()

函数自带的apply方法,有两个参数,第一个参数是需要绑定的this变量,第二个参数是一个数组表示传入函数的参数。

getAge.apply(zrd, []);
Math.max.call(null, 12, 14, 19);	//类似的call,参数分别传入

装饰器

比如我们想要知道程序调用了多少次Math.max(),我们可以这样做:

var oldMax = window.max, count = 0;
window.max = function () {
     
	count++;
	return oldMax.apply(null, arguments);
}

好处是arguments可以看做一个数组,可以直接放在apply里面而不能直接传入max函数。

高阶函数

Array.map()

var a = [1, 2, 3];
var b = a.map(function (x) {
     
	return x * x;
});	// b = [1, 4, 9]
var c = a.map(String);	// c = ['1', '2', '3']

注意:map() 的回调函数传入三个参数,分别是 currentValue, index, array(老三样)。一般来说我们传入的函数只需要一个参数,比如 abs,但是比如 parseInt(string, radix) 没有忽略第二个参数,因此下面的例子:

var a = ['1', '2', '3'];
var b = a.map(parseInt);	// b = [1, NaN, NaN]

因为上述代码相当于分别调用了 parseInt('1', 0), parseInt('2', 1), parseInt('3', 2)

Array.reduce()

[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4),其中 f 必须要接受两个参数。

var a = [1, 2, 3];
var b = a.reduce(function (x, y) {
     
	return x + y;
});	// b = 6
var c = a.reduce(function (x, y) {
     
	return x * 10 + y;
});	// c = 123

Array.filter()

var a = ['A', '', 'B', null, undefined, 'C', '  '];
var b = a.filter(function (s, index, array) {
     
	return s && s.trim();
});	// b = ['A', 'B', 'C']

去除重复元素:

var a = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
var b = a.filter(function (s, index, self) {
     
	return self.indexOf(s) === index;	//注意 ===
});	//b = ['apple', 'strawberry', 'banana', 'pear', 'orange']

Array.sort()

Array.sort() 默认把数字转化为字符串比较。所幸,它也是个高阶函数。自定义函数中,x < y, x == y, x > y 分别返回 -1, 0, 1

注意: Array.sort() 是原地排序。

etc

  • every() 方法可以判断数组的所有元素是否满足测试条件。

  • find() 方法用于查找符合条件的第一个元素,如果找到了,返回这个元素,否则,返回 undefined.

  • findIndex()find() 类似,也是查找符合条件的第一个元素,不同之处在于 findIndex() 会返回这个元素的索引,如果没有找到,返回 -1.

  • forEach()map() 类似,它也把每个元素依次作用于传入的函数,但不会返回新的数组。比如依次打印每个元素:arr.forEach(console.log);

闭包

一句话来说,闭包就是存储状态(变量)的函数,并且它的状态(变量)可以完全对外隐藏起来。

function lazy_counter(a) {
     
	var temp = function () {
     
		return a.reduce(function (x, y) {
     
			return x + y;
		});
	};
	return temp;
}
ksj = lazy_counter([1, 2, 3]);

这样,ksj 得到的是一个并没有被执行的函数,调用 ksj() 的时候才会执行并返回 6。可以发现,lazy_sum 中的 temp 可以调用其 a 参数,但在函数外面无法对其进行修改。

如果像下面这样写:

function foo() {
     
	temp = [];
	for (var i = 1; i <= 3; i++) {
     
		temp.push(function () {
     
			return i * i;
		});
	}
	return temp;
}
var funcList = foo();
var [f1, f2, f3] = funcList;
f1(), f2(), f3();	// 16, 16, 16

因为调用 f1 的时候才会执行 function () {return i * i;},而此时 i 已经变成 4 了。所以返回函数不要引用后续会发生变化的变量

但是如果 for 中用 let 声明循环变量而不是 var,就不会有问题,因为此时不同函数中的就不是一个 i 了。

如果需要引用循环变量,还有方法是在创建一层函数,把循环变量作为参数传进去。

function foo() {
     
	temp = [];
	for (var i = 1; i <= 3; i++) {
     
		temp.push((function (n) {
     
			return function () {
     
				return n * n;
			};
		})(i));
	}
	return temp;
}

上面“创建一个匿名函数并立刻执行”的效果就是让每次循环传入的参数独立。

开一下脑洞,不用数字和运算符实现加法:

// 定义数字0:
var zero = function (f) {
     
    return function (x) {
     
        return x;
    }
};
// 定义数字1:
var one = function (f) {
     
    return function (x) {
     
        return f(x);
    }
};
// 定义加法:
function add(n, m) {
     
    return function (f) {
     
        return function (x) {
     
            return m(f)(n(f)(x));
        }
    }
}
var three = add(add(one, one), one);
(three(function () {
     console.log('zrd');}))();	// 会打印三次
...

这个脑洞实际上做了这么一回事:

zero(f)(x) = x;
one(f)(x) = f(x);
two(f)(x) = one(f)(one(f)(x)) = one(f)(f(x)) = f(f(x));
three(f)(x) = two(f)(one(f)(x)) = two(f)(f(x)) = f(f(f(x)));
...
five(f)(x) = f(f(f(f(f(x)))));

箭头函数

(x, y) => x * x + y;
(x, ...rest) => {
     
	var sum = x;
	for (let i = 0; i < rest.length; i++) {
     
		sum += rest[i];
	}
	return sum;
}
x => ({
     foo: x})	// 返回对象

生成器

function* fib(n) {
     
	var a = 0, b = 1;
	for (let i = 1; i <= n; i++) {
     
		yield a;
		[a, b] = [b, a + b];
	}
	return 'hahaha';
}

直接调用返回一个 generator 对象。想要获得里面的元素,一种方法是 next

var f = fib(3);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 'hahaha', done: true}	// done为true时value为return的返回值

还有一种方法是用 for ... of ...

for (let x of fib(5)) {
     
	console.log(x);
}

你可能感兴趣的:(javascript)