JS高级语法十个重点和难点
一、立即执行函数
函数在进行定义的时候就立即执行
// 定义函数
function getName(){
console.log('你的名字')
}
// 调用函数
getName()
(function(){
console.log('立即执行函数')
})()
二、闭包
闭包是函数内部可以使用函数外部的变量
function f1(){
var n = 1;
function f2(){
n+1;
console.log(n)
}
return f2
}
var result = f1();
result()//2
result()//3
result()//4
三、使用闭包定义私有变量
使用闭包定义私有变量,只能在函数内部进行使用
function f1(){
var name = '彦祖';
this.GetName = function(){
return name
}
this.SetName = function(value){
name = value
}
}
var s1 = new f1();
console.log(s1.name)//undefined
console.log(s1.GetName())//彦祖
四、原型和原型链
JavaScript所有的构造函数都有一个原型对象prototype,用于设置所有实例对象需要共享的属性和方法
function Rectangle(x,y){
this._length = x;
this._breadth = y
}
Rectangle.prototype.getDimensions = function(){
return {
length:this._length,
breadth:this.breadth
}
}
var x = new Rectangle(3,4);
var y = new Rectangle(4,3);
console.log(x.getDimensions());
console.log(y.getDimensions());
五、模块化
JavaScript并非模块化编程语言,至少在ES6之前不是这样的,但是对于一个复杂的应用来讲,模块化是最基本的一个要求。
var module = (function(){
var N = 5;
function print(x){
console.log("The result is :"+x);
}
function add(a){
var x = a+N;
print(x)
}
return {
description:'this is description';
add:add
}
})()
六、变量提升
JavaScript会将所有变量和函数声明移动到他作用域的最前面,这就是变量提升
console.log(y);
var y = 2;
等价于
var y;
console.log(y);
y = 2
七、柯里化
柯里化,可以使函数变得更加灵活,我们可以一次性传入多个参数调用他,也可以只传入一个参数调用它,让他返回一个函数去处理剩下的参数。
var add = function(x){
return function(y){
return x+y;
}
}
console.log(add(1)(1));
var add1 = add(1);
console.log(add1(1));
var add10 = add(10);
console.log(add10(1));
八、apply,call,bind的用法
这三个方法都是改变函数内部this的指向
- 三个方法的第一个参数都是this的指向
- 第二个参数是传递的参数
- call和apply都会执行函数,bind是返回一个函数
①:函数.call(对象,arg1,arg2....)
②:函数.apply(对象,[arg1,arg2,...])
③:var ss=函数.bind(对象,arg1,arg2,....)
九、Memoization
Memoization
的原理就是把函数的每次执行结果都放入一个对象中,在接下来的执行中,在对象中查找是否已经有相应执行过的值,如果有,直接返回该值,没有才真正执行函数体的求值部分。在对象里找值是要比执行函数的速度要快的。
let memoize = function(func) {
let cache = {};
return function(key) {
if (!cache[key])
cache[key] = func.apply(this, arguments);
return cache[key];
}
}
underscore 的源码中有 Memoization 方法的封装,它支持传入一个 hasher 用来计算缓存对象 key 的计算方式。
_.memoize = function(func, hasher) {
var memoize = function(key) {
// 把存储对象的引用拿出来,便于后面代码使用
var cache = memoize.cache;
// hasher 是计算 key 值的方法函数。
// 如果传入了 hasher,则用 hasher 函数来计算 key
// 否则用 参数 key(即 memoize 方法传入的第一个参数)当 key
var address = '' + (hasher ? hasher.apply(this, arguments) : key);
// 如果 key 还没有对应的 hash 值(意味着没有缓存值,没有计算过该输入)
// 就执行回调函数,并缓存结果值
if (!_.has(cache, address))
cache[address] = func.apply(this, arguments);
// 从缓存对象中取结果值
return cache[address];
};
// cache 对象被当做 key-value 键值对缓存中间运算结果
memoize.cache = {};
// 返回 momoize 函数, 由于返回函数内部引用了 memoize.cache, 构成了闭包,变量保存在了内存中。
return memoize;
};
质数为在大于 1 的自然数中,除了 1 和它本身以外不再有其他因数。
function isPrime(value) {
console.log("isPrime 被执行了!");
var prime = value != 1; // 1 不是素数,其他数字默认是素数。
for (var i = 2; i < value; i++) {
if (value % i == 0) {
prime = false;
break;
}
}
return prime
}
let momoizedIsPrime = memoize(isPrime);
momoizedIsPrime(5) // isPrime 被执行了!
momoizedIsPrime(5) // 第二次执行,没有打印日志!
斐波那契数列的特点是后一个数等于前面两个数的和
指的是这样一个数列:1、1、2、3、5、8、13、21、……在数学上,斐波那契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=Fn-1+Fn-2
fibonacci = memoize(fibonacci);
for(var i = 0; i<= 10; i++) {
console.log(`i: ${i}, ` + fibonacci(i));
}
console.log(count); // 12
十、函数重载
function comeon() {
document.writeln("无参一身轻");
document.write("<br>");
}
function comeon(i) {
document.writeln("一参是为"+i);
document.write("<br>");
}
function comeon(i,j){
document.writeln("二参数更有"+i+"和"+j);
document.write("<br>");
}
comeon();
comeon(1);
comeon(1,2);
- 问题:后面的函数会覆盖之前的函数
function add(){
if(arguments.length==0){
document.writeln("没有参数,你让我加什么?");
document.write("<br>");
}
else if(arguments.length==1){
document.writeln(arguments[0]);
document.write("<br>");
}
else
{
var n = 0;
len = arguments.length;
for (var i = 0; i < len; i++) {
n+=arguments[i];
}
document.writeln(n);
document.write("<br>");
}
}
add();
add(1);
add(1,2);
add(1,2,3);