IMOOC
IMOOC copied to clipboard
JavaScript进阶学习总结与资料
前言
该份资料的来源为慕课网教程《JavaScript深入浅出》,内容几乎是全文摘抄下来,不喜勿喷啊。
数据类型
JavaScript被称为是一种弱类型的语言,原因就是数据类型居然能够随意转换而不报错,而且在定义变量的时候不用指定其类型,示例代码如下:
var num = 32;
num = "this is a string";
面试题常问的:JavaScript中原始类型有哪几种? 答:number、string、boolean、null、undefined。
隐式转换
1、加号(+)和减号(-) 在数字与字符串做运算的时候,加号做拼接,减号就做减法
"37" - 7 //30
"37"+7 //377
2、等于号(==) 等于号判断原始类型的时候会有自动类型转换的特点,在判断引用类型的时候会从引用地址上进行判断。
"1.23" == 1.23 //true
0 == false //true
null == undefined //true
new Object() == new Object() //false
[1, 2] == [1, 2] //false
new String('hi') == 'hi' //true
new String('456') == 456 //true
3、严格等于(===) 相比于等于号,严格等于不会进行类型转换,它会一开始判断两者之间的类型,如果类型不同,直接返回false。类型相同且内容相同才返回true。
"1.23" === 1.23 //false
0 === false //false
null === undefined //false
new Object() === new Object() //false
[1, 2] === [1, 2] //false
new String('hi') === 'hi' //false
new String('456') === 456 //false
包装对象
JavaScript是面向对象的语言,使用”.”操作符可以访问对象的属性和方法,而对于基本类型(null,undefined, bool, number, string)应该是值类型,没有属性和方法,然而
var str = "this is a string";
console.log(str.length); //16
console.log(str.indexOf("is")); //2
结果很简单,但是仔细想想还真奇怪,string不是值类型吗!怎么又有属性又有方法的!其实只要是引用了字符串的属性和方法,JavaScript就会将字符串值通过new String(s)的方式转为内置对象String,一旦引用结束,这个对象就会销毁。所以上面代码在使用的实际上是String对象的length属性和indexOf方法。
同样的道理,数字和布尔值的处理也类似。null和undefined没有对应对象。既然有对象生成,能不能这样
var str = "this is a string";
str.b = 10;
console.log(str.b); //undefined
结果并没有返回10,而是undefined!不是说好了是个对象吗!正如刚才提到第二行代码只是创建了一个临时的String对象,随即销毁,第三行代码又会创建一个新的临时对象(这就是低版本IE频繁处理字符串效率低的一个原因),自然没有b属性,这个创建的临时对象就成为包装对象。
类型检测
在JavaScript中,有很多种检测数据的类型,主要是有以下几种
1、typeof:一般用于检测原始数据类型,引用数据类型无法具体的检测出来
console.log(typeof ""); //string
console.log(typeof 1); //number
console.log(typeof true); //boolean
console.log(typeof null); //object
console.log(typeof undefined); //undefined
console.log(typeof []); //object
console.log(typeof function() {}); //function
console.log(typeof {}); //object
其实null是js设计的一个败笔,早期准备更改null的类型为null,由于当时已经有大量网站使用了null,如果更改,将导致很多网站的逻辑出现漏洞问题,就没有更改过来,于是一直遗留到现在。
2、instanceof:检测引用数据类型
console.log("1" instanceof String); //false
console.log(1 instanceof Number); //false
console.log(true instanceof Boolean); //false
console.log([] instanceof Array); //true
console.log(function() {} instanceof Function); //true
console.log({} instanceof Object); //true
可以看到前三个都是以对象字面量创建的基本数据类型,但是却不是所属类的实例,这个就有点怪了。后面三个是引用数据类型,可以得到正确的结果。如果我们通过new关键字去创建基本数据类型,你会发现,这时就会输出true,如下:
console.log(new String("1") instanceof String); //true
console.log(new Number(1) instanceof Number); //true
console.log(new Boolean(true) instanceof Boolean); //true
console.log([] instanceof Array); //true
console.log(function() {} instanceof Function); //true
console.log({} instanceof Object); //true
3、constructor:似乎完全可以应对基本数据类型和引用数据类型,都能检测出数据类型
console.log(("1").constructor === String); //true
console.log((1).constructor === Number); //true
console.log((true).constructor === Boolean); //true
console.log(([]).constructor === Array); //true
console.log((function() {}).constructor === Function); //true
console.log(({}).constructor === Object); //true
事实上并不是如此,来看看为什么:
function Fn(){};
Fn.prototype=new Array();
var f=new Fn();
console.log(f.constructor===Fn); //false
console.log(f.constructor===Array); //true
声明了一个构造函数,并且把他的原型指向了Array的原型,所以这种情况下,constructor也显得力不从心了。
4、Object.prototype.toString:终极数据检测方式
var a = Object.prototype.toString;
console.log(a.call("aaa")); //[object String]
console.log(a.call(1)); //[object Number]
console.log(a.call(true)); //[object Boolean]
console.log(a.call(null)); //[object Null]
console.log(a.call(undefined)); //[object Undefined]
console.log(a.call([])); //[object Array]
console.log(a.call(function() {})); //[object Function]
console.log(a.call({})); //[object Object]
表达式和运算符
表达式
概念 表达式是指能计算出值的任何可用程序单元,或者可以这么说:表达式是一种JavaScript短语,可以使JavaScript解释器用来产生一个值。
原始表达式
- 常量、直接量:比如3.14、“test”等这些;
- 关键字:比如null,this,true等这些;
- 变量:比如i,k,j等这些。
复合表达式 比如:10*20
数组和对象的初始化表达式 比如:[1,2]、{x:1,y:2}等这些。
函数表达式 比如:var fe = function(){}或者(functiong(){console.log('hello world');})()
属性访问表达式 比如:var o = {x:1},访问属性的方式有o.x或者o['x']
调用表达式 比如:funName()
对象创建表达式 比如:new Func(1,2)或者new Object
运算符
太多太基础啦,不多说,稍微提一下以下几个运算符
// 逗号运算符
var n = (1,2,3) //n=3
// 删除运算符
var obj = {x:1}
obj.x; //1
delete obj.x;
obj.x; //undefined
var obj = {};
Object.defineProperty(obj,'x',{
configurable:false,
value:1
});
delete obj.x; //false
obj.x; //1
// in运算符
window.x = 1;
'x' in window; //true
// new运算符
function Foo(){}
Foo.prototype.x = 1;
var obj = new Foo();
obj.x; // 1
obj.hasOwnProperty('x'); // false
obj.__proto__.hasOwnProperty('x'); // true
// this运算符
this;
var obj = {
func:function(){return this;}
};
obj.func(); //obj
语句
block语句和var语句
block语句 块语句常用于组合0~N个语句,往往用一对花括号定义。
{
var str = 'hi';
console.log(str);
}
if(true) {
console.log('hi');
}
在ES6出来之前,JavaScript是没有块级作用域的,具体看以下两段代码:
for (var i=0; i<10; i++) {
var str = 'hi';
console.log(str);
}
等同于
var i = 0;
for (; i<10; i++) {
var str = 'hi';
console.log(str);
}
{
var x = 1;
}
等同于
var x = 1;
{
}
function foo() {
var a = 1;
console.log(a); //1
}
foo();
console.log(typeof a); //undefined
声明语句var
function foo() {
//隐式的将b定义为全局变量
var a = b = 1;
}
foo();
console.log(typeof a); //undefined
console.log(typeof b); //number
function foo() {
//同时定义多个变量的正确方式
var a =1,b = 1;
}
foo();
console.log(typeof a); //undefined
console.log(typeof b); //undefined
try-catch语句
try跟catch搭配使用可以检测try里边的代码有没有抛出error,如果有error就会跳转到catch里执行catch里的程序。执行顺序为:先try捕获异常,执行catch里面的内容,最后执行finally里面的内容,当然也可以只写catch或者finally两个中的一个,但是必须写try语句块。
try {
throw 'test';
} catch(e) {
console.log(e); //test
} finally {
console.log('必須執行的');
}
嵌套使用
try {
try {
throw new Error('oops');
} finally {
console.log('finally');
}
} catch(e) {
console.error('outer', e.message);
}
由于在嵌套层中并没有catch语句,因此输出结果的顺序为:finally、outer、oops。下面请看含有catch语句的
try {
try {
throw new Error('oops');
} catch(ex) {
console.log('inner', ex.message);
} finally {
console.log('finally');
}
} catch(ex) {
console.error('outer', ex.message);
}
以上代码输出结果的顺序为:inner、oops、finally。原因是异常已经在内部处理过了,因此不会再到外部去处理。
更复杂的嵌套
try {
try {
throw new Error('oops');
} catch(ex) {
console.log('inner', ex.message);
throw ex;
} finally {
console.log('finally');
}
} catch(ex) {
console.error('outer', ex.message);
}
以上代码输出结果的顺序为:inner、oops、finally、outer、oops。原因在内部的catch语句重新向外抛出了ex这个异常。
for in语句
有以下的特点:1、顺序不确定;2、enumerable为false时不会出现;3、fon in对象属性时会受到原型链的影响
var p;
var obj = { x: 1, y: 2 }
for(p in obj) {
console.log(p); //x y
}
严格模式
这里有一篇非常好的总结,传送门
对象
概述
对象中包含一系列的属性,这些属性是无序的,每一个属性都有一个字符串key和对应的value
var obj = {x:1,y:2};
obj.x; //1
obj.y; //2
创建对象
创建对象方式1—字面量:
var obj1 = {x:1,y:2};
var obj2 = {
x:1,
y:2,
o:{
z:3,
n:4
}
};
创建对象方式2—通过构造函数
function foo() {}
foo.prototype.z = 3;
var obj = new foo();
obj.x = 1;
obj.y = 2;
console.log(obj.x); //1
console.log(obj.y); //2
console.log(obj.z); //3
console.log(typeof obj.toString()); //string
console.log(typeof obj.toString); //function
console.log('z' in obj); //true
console.log(obj.hasOwnProperty('z')); //false
创建对象方式3—Object.create
var obj = Object.create({ x: 1 });
console.log(obj.x); //1
console.log(obj.toString); //function
console.log(obj.hasOwnProperty('x')); //false
// null对象的原型链少了Object这一层
var obj1 = Object.create(null);
console.log(obj1.toString); //undefined
属性操作
属性读写
var obj = {x:1,y:2};
obj.x; //1
obj['y']; //2
//使用[]取得属性值一般场景
var obj = {x1:1,x2:2};
for(var i=1; i<=2; i++){
console.log(obj['x' + i];
}
属性删除
var person = {age:28,title:'test'};
delete person.age; //true
delete preson['title']; //true
person.age; //undefined
delete person.age; //true
//无法删除原型
delete Object.prototype; //false
//因为原型的configurable不可配置
var descriptor = Object.getOwnPropertyDescriptor(Object,'prototype');
descriptor.configurable; //false
属性检测
var cat = new Object();
cat.legs = 4;
cat.name = 'tom';
//for in检测
'legs' in cat; //true
'abc' in cat; //false
'toString' in cat; //true
//检测对象本身的属性
cat.hasOwnProperty('legs'); //true
cat.hasOwnProperty('toString'); //false
//检测对象的属性是否可枚举,包括原型上的
cat.propertyIsEnumerable('legs'); //true
cat.propertyIsEnumerable('toString'); //false
属性枚举
var o = { x: 1, y: 2, z: 3 };
'toString' in o; //true
o.propertyIsEnumerable('toString'); //false
var key;
for(key in o) {
console.log(key); //x,y,z
}
var obj = Object.create(o);
obj.a = 4;
var key;
for(key in obj) {
console.log(key); //a,x,y,z
}
var obj = Object.create(o);
obj.a = 4;
var key;
for(key in obj) {
if(obj.hasOwnProperty(key)) {
console.log(key); //a
}
}
getter()和setter()方法
var man = {
name: 'tom',
weibo: 'haha',
get age() {
return new Date().getFullYear() - 1988;
},
set age(val) {
console.log('你没有权限设置年龄为:' + val);
}
}
console.log(man.age); //30
man.age = 100; //你没有权限设置年龄为:100
console.log(man.age); //30
//修改一下,使上面的代码更复杂
var man = {
name: 'tom',
weibo: 'haha',
$age: null,
get age() {
if(this.$age == undefined) {
return new Date().getFullYear() - 1988;
} else {
return this.$age;
}
},
set age(val) {
val = +val;
if(!isNaN(val) && val > 0 && val < 150) {
this.$age = +val;
} else {
console.log('年龄无法设置为:' + val);
}
}
}
console.log(man.age); //30
man.age = 100;
console.log(man.age); //100
man.age = 'abc'; //年龄无法设置为:NaN
get/set与原型链
//get和set设置的值不会被直接更改
function foo() {}
Object.defineProperty(foo.prototype, 'z', {
get: function() {
return 1;
}
})
var obj = new foo();
console.log(obj.z); //1
obj.z = 10;
console.log(obj.z); //1
//defineProperty设置的值不会被直接更改
var o = {}
Object.defineProperty(o, 'x', { value: 5 });
var obj = Object.create(o);
console.log(obj.x); //5
obj.x = 200;
console.log(obj.x); //5
//更改defineProperty设置的值
var o = {}
Object.defineProperty(o, 'x', { writable: true, configurable: true, value: 5 });
var obj = Object.create(o);
console.log(obj.x); //5
obj.x = 200;
console.log(obj.x); //200
属性标签
var person = {};
Object.defineProperty(person, 'name', {
configurable: false,
writable: false,
enumerable: true,
value: 'tom'
})
console.log(person.name); //tom
person.name = 'jack';
console.log(person.name); //tom
console.log(delete person.name); //false
//获得属性的标签值
console.log(Object.getOwnPropertyDescriptor(person,'name'));
//属性标签的应用
var person = {};
Object.defineProperties(person, {
title: {
value: 'JavaScript',
enumerable: true
},
corp: {
value: 'BAT',
enumerable: true
},
salary: {
value: 50000,
enumerable: true,
writable: true
},
luck: {
get: function() {
return Math.random() > 0.5 ? 'good' : 'bad';
}
},
promote: {
set: function(level) {
this.salary *= 1 + level * 0.1;
}
}
});
console.log(Object.getOwnPropertyDescriptor(person, 'salary'));
console.log(person.salary); //50000
person.promote = 2;
console.log(person.salary); //60000
序列化
//将属性和值序列化为字符串
var obj = { x: 1, y: true, z: [1, 2, 3], nullVal: null };
//{"x":1,"y":true,"z":[1,2,3],"nullVal":null}
console.log(JSON.stringify(obj));
//有点小坑,得注意
var obj1 = { val: undefined, a: NaN, b: Infinity, c: new Date() };
//{"a":null,"b":null,"c":"2018-06-09T10:46:01.929Z"}
console.log(JSON.stringify(obj1));
//把字符串反序列化为属性和值
var obj2 = JSON.parse('{"x":2333}');
//2333
console.log(obj2.x);
数组
数组中的方法
将数组转为字符串
var arr = [1, 2, 3];
console.log(arr.join()); //1,2,3
console.log(arr.join('-')); //1-2-3
function repeatString(str, n) {
return new Array(n + 1).join(str);
}
console.log(repeatString('a', 3)); //aaa
console.log(repeatString('hi', 2)); //hihi
将数组逆序输出
var arr = [1, 2, 3];
console.log(arr.reverse()); //3,2,1
console.log(arr); //3,2,1
将数组进行排序
var arr = [13, 24, 52, 3];
//13,24,3,54
console.log(arr.sort());
//13,24,3,54
console.log(arr);
var arrSort = arr.sort(function(a, b) { return a - b; });
//3,13,24,52
console.log(arrSort);
var arr1 = [
{ age: 25 },
{ age: 39 },
{ age: 22 }
];
arr1.sort(function(a, b) {
return a.age - b.age;
})
arr1.forEach(function(item) {
console.log('age:', item.age);
})
将数组合并
var arr = [1, 2, 3];
//[1,2,3,4,5]
console.log(arr.concat(4, 5));
//[1,2,3]
console.log(arr);
//[1,2,3,10,11,13]
console.log(arr.concat([10, 11], 13));
//[1,2,3,1,[2,3]]
console.log(arr.concat([1, [2, 3]]));
返回部分数组
var arr = [1, 2, 3, 4, 5];
//[2,3]
console.log(arr.slice(1, 3));
//[2,3,4,5]
console.log(arr.slice(1));
//[2,3,4]
console.log(arr.slice(1, -1));
//[2]
console.log(arr.slice(-4, -3));
//[1,2,3,4,5]
console.log(arr);
将数组进行拼接
var arr = [1, 2, 3, 4, 5];
//[3,4,5],从下标为2开始删除
console.log(arr.splice(2));
//[1,2]
console.log(arr);
var arr1 = [1, 2, 3, 4, 5];
//[3,4],从下标为2开始删除,删除两个元素后停止
console.log(arr1.splice(2, 2));
//[1,2,5]
console.log(arr1);
var arr2 = [1, 2, 3, 4, 5];
//[2],从下标为1开始删除,删除一个元素后停止,并且添加a和b这两个元素
console.log(arr2.splice(1, 1, 'a', 'b'));
//[1,"a","b",3,4,5]
console.log(arr2);
将数组进行遍历
var arr = ['a', 'b', 'c', 'd', 'e'];
arr.forEach(function(x, index, a) {
console.log(x + '-' + index + '-' + (a === arr));
});
将数组进行映射
var arr = [1, 2, 3];
arr.map(function(x) {
//11,12,13
console.log(x + 10);
});
//[1,2,3]
console.log(arr);
将数组进行过滤
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr.filter(function(x, index) {
//1,2,3,4,5,6,7,8,9,10
console.log(x);
//0,1,2,3,4,5,6,7,8,9
console.log(index);
return index % 3 === 0 || x >= 8;
});
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(arr);
将数组进行判断
var arr = [1, 2, 3, 4, 5];
//判断每一个元素是否小于10
arr.every(function(x) {
return x < 10;
});
//判断是否有一个元素等于3
arr.some(function(x) {
return x === 3;
});
将数组元素进行累加操作
var arr = [1, 2, 3];
var sum = arr.reduce(function(x, y) {
return x + y;
});
//6
console.log(sum);
//[1,2,3]
console.log(arr);
var arr1 = [3, 9, 6];
var max = arr1.reduce(function(x, y) {
//3-9
//9-6
console.log(x + '-' + y);
return x > y ? x : y;
});
//9
console.log(max);
//[3,9,6]
console.log(arr1);
var arr2 = [3, 9, 6];
var max2 = arr2.reduceRight(function(x, y) {
//6-9
//9-3
console.log(x + '-' + y);
return x > y ? x : y;
});
//9
console.log(max2);
//[3,9,6]
console.log(arr2);
将数组进行检索
var arr = ['a', 'b', 'c', 'd', 'e', 'a'];
//2,在数组下标为2的位置找到
console.log(arr.indexOf('c'));
//-1,找不到该元素
console.log(arr.indexOf('f'));
//0,在数组下标为0的位置找到,默认是从左到右查找
console.log(arr.indexOf('a'));
//5,在数组下标为5的位置找到,设置是从数组下标为1的位置开始向右查找
console.log(arr.indexOf('a', 1));
//5,在数组下标为5的位置找到,-3表示在d的位置开始向右查找
console.log(arr.indexOf('a', -3));
//0,在数组下标为0的位置找到,-6表示在最左a的位置开始向右查找
console.log(arr.indexOf('a', -6));
//-1,找不到该元素,-3表示在d的位置开始向右查找
console.log(arr.indexOf('b', -3));
//3,在数组下标为3的位置找到
console.log(arr.lastIndexOf('d'));
//-1,找不到该元素,2表示的是在e的位置向右查找
console.log(arr.lastIndexOf('d', 2));
//3,在数组下标为3的位置找到,5表示的是在b的位置向右查找
console.log(arr.lastIndexOf('d', 5));
判断是否为数组
//true
console.log(Array.isArray([]));
//true
console.log(({}).toString.apply([]) === '[object Array]');
//true
console.log([] instanceof Array);
//true
console.log([].constructor === Array);
数组 VS 对象
- 相同点:都可以继承,数组是对象,对象不一定是数组,都可以当做对象一般添加删除属性
- 不同点:数组自动更新length,按索引访问数组常常比访问一般对象属性明显迅速,数组对象继承Array.prototype上的大量数组操作方法。
数组 VS 字符串
字符串是一种类数组
var str = 'hello world';
str.charAt(0); //h
str[1]; //e
Array.prototype.join.call(str,'-'); //h-e-l-l-o--w-o-r-l-d
函数和作用域
函数概念
函数是一块JavaScript代码,被定义一次,但可以执行和调用多次。JavaScript中的函数也是对象,所以函数可以像其他对象那样操作和传递,所以我们也常叫JavaScript中的函数为函数对象。
函数调用方式
- 直接调用
- 对象方法调用
- 构造器调用
- call/apply/bind调用
函数声音和函数表达式
函数声明
function add(a, b) {
var x = a;
var y = b;
return x + b;
}
函数表达式
//一般表达式
var add = function(a, b) {
}
//立即调用表达式
(function() {
})();
//返回表达式
return function() {
};
//命名函数表达式
var add = function foo(a, b) {
}
函数声明和函数表达式的区别 他们最重要的区别就是函数声明能够提前,而函数表达式不行
var num = add(1, 3);
//4
console.log(num);
function add(a, b) {
var x = a;
var y = b;
return x + b;
}
var num1 = add1(1, 3);
//add1 is not a function
console.log(num1);
var add1 = function(a, b) {
var x = a;
var y = b;
return x + b;
}
this的栗子
全局的this(浏览器)
console.log(this.document == document); //true
console.log(this === window); //true
this.a = 37;
console.log(window.a); //37
一般函数中的this
function f1(){
return this;
}
f1() === window; //true
function f2(){
'use strict';
return this;
}
f2() === undefined; //true
作为对象方法中函数的this
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); //37
var o = { prop: 37 };
function independent() {
console.log(this.prop); //37
return this.prop;
}
o.f = independent;
console.log(o.f()); //37
对象原型链上的this
var o = {
fn: function() {
return this.a + this.b;
}
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
//5
console.log(p.fn());
get/set方法与this
function modulus() {
//abs()返回数的绝对值
return Math.abs(this.re + this.im);
}
var o = {
re: 4,
im: -9,
get phase() {
//sqrt()返回数的平方根
return Math.sqrt(this.re);
}
};
Object.defineProperty(o, 'modulus', {
get: modulus,
enumerable: true,
configurable: true
});
console.log(o.phase); //2
console.log(o.modulus); //5
构造器中的this
function Abc() {
this.a = 33;
}
var oo = new Abc();
console.log(oo.a); //33
function Bcd() {
this.b = 55;
return { b: 66 };
}
var pp = new Bcd();
console.log(pp.b); //66
call/apply方法与this
function add(c, d) {
return this.a + this.b + c + d;
}
var o = { a: 1, b: 3 };
//16
console.log(add.call(o, 5, 7));
//34
console.log(add.apply(o, [10, 20]));
function bar() {
//[object Window]
console.log(Object.prototype.toString.call(this));
}
bar();
//[object Number]
console.log(bar.call(10));
bind方法与this
function bar() {
return this.a;
}
var ger = bar.bind({
a: 'test'
});
//f bar(){ return this.a; }
console.log(ger);
//test
console.log(ger());
var odr = {
a: 33,
bn: bar,
gn: ger
};
//33
console.log(odr.bn());
//test
console.log(odr.gn());
函数属性arguments
function foo(x, y, z) {
//2
console.log(arguments.length);
//3
console.log(arguments[0]);
arguments[0] = 100;
//100
console.log(x)
arguments[2] = 200;
//undefined
console.log(z);
//200
console.log(arguments[2]);
//true
console.log(arguments.callee === foo);
}
foo(3, 4);
//3
console.log(foo.length);
//foo
console.log(foo.name);
apply/call方法(浏览器)
function foo(x, y) {
console.log(x, y, this);
}
//1,2,Number(100)
foo.call(100, 1, 2);
//3,4,Boolean(true)
foo.apply(true, [3, 4]);
//undefined,undefined,window
foo.apply(null);
//undefined,undefined,window
foo.apply(undefined);
function foo(x, y) {
'use strict';
console.log(x, y, this);
}
//undefined,undefined,null
foo.apply(null);
//undefined,undefined,undefined
foo.apply(undefined);
bind方法
this.x = 9;
var module = {
x: 33,
getX: function() {
return this.x;
}
};
console.log(module.getX()); //33
var gn = module.getX;
console.log(gn()); //9
var gn1 = gn.bind(module);
console.log(gn1()); //33
bind与currying 函数有柯里化(currying)的特性,意思函数能拆分成多个单元。
function add(a, b, c) {
return a + b + c;
}
var fn = add.bind(undefined, 100);
console.log(fn(1, 2)); //103
var fn1 = fn.bind(undefined, 200);
console.log(fn1(10)); //310
柯里化的实际运用
function getConfig(colors, size, otherOptions) {
console.log(colors, size, otherOptions);
}
var defaultConfig = getConfig.bind(null, '#cc0000', '1024*768');
//#cc0000 1024*768 123
console.log(defaultConfig('123'));
//#cc0000 1024*768 456
console.log(defaultConfig('456'));
bind与new
function foo() {
this.b = 100;
return this.a;
}
var fn = foo.bind({ a: 1 });
//1
console.log(fn());
//{b:100}
console.log(new fn());
bind方法模拟
if(!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if(typeof this !== 'function') {
throw new TypeError('what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1);
var fToBind = this;
var fNOP = function() {};
var fBound = function() {
return fToBind.apply(this instanceof fNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
以上代码有做了些修改,原始代码以及分析请看下图:
理解闭包
闭包的栗子
function outer() {
var localVal = 30;
return localVal;
}
console.log(outer());
function outer1() {
var localVal2 = 33;
return function() {
return localVal2;
}
}
var fn = outer1();
console.log(fn())
闭包概念 在计算机科学中,闭包(也成为词法闭包或者函数闭包)是指一个函数或者函数的引用,与一个引用环境绑定在一起,这个引用环境是一个存储该函数每个非局部变量(也叫自由变量)的表。
闭包,不同于一般的函数,它允许一个函数在立即词法作用域外调用时,仍可访问非本地变量。
闭包特性
- 优点:灵活、方便、封装;
- 缺点:空间浪费、内存泄露、性能消耗。
作用域
全局作用域、函数作用域和eval
//全局变量
var a = 10;
(function() {
//局部变量
var b = 20;
})();
//10
console.log(a);
//undefined
console.log(b);
for(var item in { a: 1, b: 2 }) {
//a b
console.log(item);
}
//b
console.log(item);
eval('var c = 100');
//100
console.log(c);
作用域链
function outer1() {
var local1 = 11;
function inter() {
var local2 = 22;
//11
console.log(local1);
//22
console.log(local2);
//33
console.log(global1);
}
inter();
}
var global1 = 33;
outer1();
function outer2() {
var local3 = 44;
var fn = new Function('console.log(typeof local3);');
//undefined
fn();
}
outer2();
执行上下文
这个玩意太抽象了,看完视频对这个概念还是十分模糊,还是来这看一下比较容易理解的文章——王福朋深入理解JavaScript系列
OOP知识点
概念与继承
面向对象程序设计是一种程序设计规范,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。
看了课程的相关知识点,发现远远没有下面几篇博文说的这么简单易懂与透彻,在这就不整理课程的内容了,一起来看看以下三个博客中内容: 冴羽博客JavaScript系列 汤姆大叔深入理解JavaScript系列 王福朋深入理解JavaScript系列
JavaScript正则表达式
这节课的内容也不摘抄了,因为之前做过这方面的总结,再继续总结一次我就认为是得不偿失了。 JavaScript正则表达式
参考资料
1、博客园小火柴的前端学习之路 2、冴羽博客JavaScript系列 3、汤姆大叔深入理解JavaScript系列 4、JavaScript包装对象 5、JavaScript检测数据类型四种方法 6、JavaScript中的new到底做了些什么 7、王福朋深入理解JavaScript系列 8、JavaScript正则表达式