函数
- 函数定义
- 函数声明与表达式
- this与调用方式
- 函数属性与arguments
- 闭包和作用域
- ES3执行上下文
//函数 作用域
/**
* JS中的函数比较特殊,既是函数也是对象,所以JS函数可以像其他对象那样操作和传递,所以JS中的函数也叫做函数对象
*/
function foo (x, y) {
if (typeof x==='number' && typeof y==='number') {
return x + y;
} else {
return 0;
}
}
console.log(foo(1,2));//3
/**
* 不同的调动方式
* foo();//直接调用
* o.method();//对象方法
* new Foo();//构造器
* func.call(o);//call、apply、bind
*/
//函数声明与表达式
//函数声明 (完整的语句 function开头 不加括号 不加叹号 也不会作为赋值语句)
function add(a,b) {
a= +a;
b= +b;
if(isNaN(a)||isNaN(b)){
return;
}
return a + b;
}
//函数表达式
/*
//将一个函数赋值给一个变量
var add = function (a,b){
//do sth
};
//将匿名函数用括号括起来 直接调用 叫做立即执行函数表达式
(function(){
//do sth
})();
//将函数对象作为一个返回值
return function(){
//do sth
}
//命名式函数表达式 和第一种类似但是函数不是匿名的 不常用 调试的时候会有用
var add = function foo (a,b) {
//do sth
}
*/
//函数声明和函数表达式的区别:
//函数声明会被前置
var num = add1(1,2);
console.log(num);// 调用成功结果是 3
function add1(a,b){
a= +a;
b= +b;
if(isNaN(a)||isNaN(b)){
return 0;
}
return a + b;
}
/*
var num1 = add2(1,2);//报错 add2 is not a function
console.log(num1);
var add2 = function (a,b){
a= +a;
b= +b;
if(isNaN(a)||isNaN(b)){
return 0;
}
return a + b;
}
*/
//function add(a,b) 和 var add 会被前置 但是函数声明前置后调用时会起作用 变量被声明后调用时值是undefined
//Function 构造器 不常用 用字符串可能会带来安全隐患
var func = new Function('a','b','console.log(a + b);');
func(1,2);//3
var func = Function('a','b','console.log(a + b);');
func(2,3);//5
//Function构造器中创建的变量仍然是局部变量 localVal扔为局部变量
Function('var localVal = "local"; console.log(localVal);')();
console.log(typeof localVal);//local, undefined
//localVal不可访问 全局变量globalVal可以访问
var globalVal = "global";
(function(){
var localVal = 'local';
Function('console.log(typeof localVal, typeof globalVal);')();
})();//undefined Number 但是实际上是undefined undefined 原因暂时未知
//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;
}
console.log(f1() === window);//true, global object
function f2(){
"user strict";//严格模式
return this;
}
console.log(f2()===undefined);//true
*/
//作为对象方法的函数的this
var o = {
prop:37,
f:function(){
return this.prop;
}
};
console.log(o.f());//37
var o = {prop:37};
function independent(){
return this.prop;
}
o.f = independent;
console.log(o.f());//37
//对象原型链上的this
var o = {f:function(){
return this.a + this.b;
}};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f());//5
//get set 方法与this
function modulus(){
return Math.sqrt(this.re * this.re *this.rm);
}
var o = {
re:1,
im:-1,
get phase(){
return Math.atan2(this.im,this.re);
}
};
Object.defineProperty(o,'modulus',{
get:modulus,enumerable:true,configurable:true
});
console.log(p.phase,o.modulus);// undefined NaN 视频中结果是 -0.78 1.4142
//构造器中的this
function MyClass(){
this.a = 37;
}
var o = new MyClass();
console.log(o.a);//37
function C2(){
this.a = 39;
return {a:38};
}
o = new C2();
console.log(o.a);//38
//方法中没有写return或者return为基本类型的话会将this作为返回值 如果return是对象的话会将对象作为返回值
//call/apply方法 与this
function add(c,d){
return this.a + this.b + c +d;
}
var o = {a:1,b:3};
console.log(add.call(o,5,7));//16
console.log(add.apply(o,[10,20]));//34
function bar(){
console.log(Object.prototype.toString.call(this));
}
bar.call(7);//[object Number]
//bind方法 与this
function f(){
return this.a;
}
var g = f.bind({a:"test"});
console.log(g());//test
var o = {a:37,f:f,g:g};
console.log(o.f(),o.g());//37 'test'
//函数属性和方法 arguments
function foo(x,y,z){
console.log(arguments.length);//2 实际传参的个数
console.log(arguments[0]);//1
arguments[0] = 10;
console.log(x);//变成 10 如果是严格模式 不会变依然是1
arguments[2] = 100;
console.log(z);//依然是 undefined
console.log(arguments.callee === foo);//true 严格模式下禁止使用
}
foo(1,2);
console.log(foo.length);//3 形参的个数
console.log(foo.name);//foo
// apply/call 方法(浏览器)
function foo (x,y){
console.log(x,y,this);
}
foo.call(100,1,2);//1 2 [Number:100]
foo.apply(true,[3,4]);//3 4 [Boolean:true]
foo.apply(null);//undefined,undefined,window 严格模式下 window变为null
foo.apply(undefined);//undefined,undefined,window 严格模式下window变为undefined
//bind方法
/*
this.x = 9; //this代表全局对象window
var module = {
x:81,
getX:function(){
return this.x;
}
};
console.log(module.getX());//81
var getX = module.getX;
console.log(getX());//9
var boundGetX = getX.bind(module);
console.log(boundGetX());//81
*/
//bind 与currying
function add(a,b,c){
return a + b + c;
}
var func = add.bind(undefined,100);
func(1,2);//103
var func2 = func.bind(undefined,200);
func2(10);//310
/*
function getConfig(colors,size,otherOptions){
console.log(color + size + otherOptions);
}
var defaultConfig = getConfig.bind(null,"#CC0000","1024 * 768");
defaultConfig("123");//#CC0000 1024*768 123
defaultConfig("456");//#CC0000 1024*768 456
*/
//bind 与new
function foo (){
this.b = 100;
return this.a;
}
var func = foo.bind({a:1});
console.log(func());//1
console.log(new func());//foo {b:100}
//bind 是ES5提供的方法 IE9以上才有生效 能实现两个功能 1.绑定this 2.科里化 实现把函数拆成不同的子函数
在计算机科学中,闭包(也称词法闭包或函数闭包)是指一个函数或函数的引用,与一个引用环境绑定在一起,这个引用环境是一个存储该函数每个非局部变量(也叫自由变量)的表。
闭包,不同于一般的函数,它允许一个函数在立即词法作用域外调用时,扔可访问非本地变量
//闭包
//普通函数
function outer1(){
var localVal = 20; //函数调用返回后 localVal会被释放
return localVal;
}
var a = outer1();
console.log(a);//20
function outer2(){
var localVal = 30;// localVal不会被释放 因为 outer2()结束后 func()仍然需要访问localVal
return function(){
return localVal;
}
}
var func = outer2();
console.log(func());//30
//闭包无处不在
/*
!function(){
var localData = "localData here";
document.addEventListener('click',function(){
console.log(localData);
});
}();
!function(){
var localData = "localData here";
var url = "http://www.51zouchuqu.com/";
$.ajax({
url:url,
success:function(){
console.log(localData);
}
})
}();
*/
//常见错误之循环闭包
/*
document.body.innerHTML = "<div id = div1>aaa</div>" + "<div id = div2>bbb</div><div id = div3>ccc</div>";
for(var i = 1; i < 4; i++) {
document.getElementById('div' + i).addEventListener('click',function(){
alert(i);// all are 4 闭包执行时for循环已经走完
});
}
//正确版本
document.body.innerHTML = "<div id = div1>aaa</div>" + "<div id = div2>bbb</div><div id = div3>ccc</div>";
for(var i = 1; i < 4; i++) {
!function(i){
document.getElementById('div' + i).addEventListener('click',function(){
alert(i);// 1, 2, 3
});
}
}
*/
//闭包-封装
/*
(function(){
var _userId = 23492;
var _typeId = 'item';
var export = {};
function converter(userId){
return + userId;
}
export.getUserId = function(){
return converter(_userId);
}
export.getTypeId = function(){
return _typeId;
}
window.export = export;
}());
export.getUserId;//23492
export.getTypeId;//item
export._userId;//undefined
export._typeId;//undefined
export.converter;//undefined
*/
//作用域 全局、函数、eval
var abc = 10;//全局作用域中的变量
(function(){
var bac = 20; //函数作用域中的变量 函数外边拿不到
}());
console.log(abc);//10
//console.log(bac);//error bac is not defined
for(var item in {a:1,b:2}){
console.log(item);//a b
}
console.log(item);//b
eval("var a = 1;");//eval 作用域
//作用域链
function outer3(){
var local2 =1;
function outer1(){
var local1 = 1;
}
outer1();
}
var global3 = 1;
outer3();
function outer(){
var i = 1;
var func = new Function("console.log(typeof i);");
func();//undefined
}
console.log("---------------");
//利用函数作用域封装 防止产生大量的全局变量 产生冲突
(function(){
//do sth here
var a,b;
}());
!function(){
//do sth here
var a,b;
}();
OOP
概念
面向对象程序设计(Object-oriented prgramming,OOP)是一种程序设计范型,同时也是一种程序开发的方法。对象指定的事类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性,灵活性和扩展性 -维基百科
特性
- 继承
- 封装
- 多态
- 抽象
//基于原型链的继承
function Foo(){
this.y = 2;
}
console.log(typeof Foo.prototype);//object
Foo.prototype.x = 1;
var obj3 = new Foo();
//prototype 是一个对象
console.log(obj3.y);//2
console.log(obj3.x);//1
//实现继承
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.hi = function(){
console.log('Hi, my name is ' + this.name + ' I’m' + this.age + 'years old now');
};
Person.prototype.LEGS_NUM = 2;
Person.prototype.ARMS_NUM = 3;
Person.prototype.walk = function(){
console.log(this.name + ' is walking…');
};
function Student(name, age, className){
Person.call(this,name,age);
this.className = className;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.hi = function(){
console.log('Hi, my name is ' + this.name + ' I’m ' + this.age + ' years old now, and from' + this.className + '.');
};
Student.prototype.learn = function(subject){
console.log(this.name + ' is learning ' + subject + 'at ' + this.className + '.');
};
//test
var bosn = new Student('Bosn', 27,'Class 3, Greade 2');
bosn.hi();//Hi, my name is Bosn I’m 27 years old now, and fromClass 3, Greade 2.
console.log(bosn.LEGS_NUM);//2
bosn.walk();//Bosn is walking…
bosn.learn('JavaScript');//Bosn is learning JavaScriptat Class 3, Greade 2.
//prototype属性
Student.prototype.x = 101;
console.log(bosn.x);//11
Student.prototype = {y:2};//重新给prototype对象赋值 对已经创建的实例不会起作用
console.log(bosn.y);//undefined
console.log(bosn.x);//101
var nunnly = new Student('Nunnly',3,'Class LOL KengB');//对后续创建的实例会起作用
console.log(nunnly.x);//undefined
console.log(nunnly.y);//2
//内置构造器的prototype
Object.prototype.x = 1;
var obj = {};
for(var key in obj){
console.log('result:' + key);
}
//result:x
Object.defineProperty(Object.prototype,'x',{writable:true,value:1});
var obj1 = {};
console.log(obj1.x);//1
for(var key in obj1){
console.log('result:' + key);//nothing output here
}
//创建对象 - new/原型链
function foo(){};
foo.prototype.z = 3;
var obj = new foo();
obj.y = 2;
obj.x = 1;
console.log(obj.x +" "+ obj.y+" "+ obj.z);//1 2 3
console.log(typeof obj.toString);//function
console.log('z' in obj);//true
console.log(obj.hasOwnProperty('z'));//false
//instanceof
console.log([1,2] instanceof Array === true);//true
console.log(new Object() instanceof Array === false);//true
//实现继承的方式
function Person(){
}
function student(){
}
Student.prototype = Person.prototype;//不可以
Student.prototype = new Person();//不可以
Student.prototype = Object.create(Person.prototype);//可以 ES5只后才有
//ES3之前
if(!Object.create){
Object.create = function(proto){
function F(){};
F.prototype = proto;
return new F;
};
}
//模拟重载、链式调用、模块化
//模拟重载
function Person(){
var args = arguments;
if (typeof args[0] === 'object' && args[0]){
if(args[0].name){
this.name = args[0].name;
}
if(args[0].age){
this.age = args[0].age;
}
} else {
if(args[0]){
this.name = args[0];
}
if(args[1]){
this.age = args[1];
}
}
}
Person.prototype.toString = function(){
return 'name=' + this.name + ',age='+this.age;
}
var bosn = new Person('Bosn',27);
console.log(bosn.toString());//name=Bosn,age=27
var nunn = new Person({name:'Nunn',age:38});
console.log(nunn.toString());//name=Nunn,age=38
//调用子类方法
function Person1 (name){
this.name = name
};
function Student1(name, className){
this.className = className;
Person1.call(this,name);
}
var bosn1 = new Student1('Bosn','Network064');
console.log(bosn1);//Student1 { className: 'Network064', name: 'Bosn' }
Person1.prototype.init = function(){};
Student1.prototype.init = function(){
Person1.prototype.init.apply(this,arguments);
};
//链式调用
function ClassManager(){};
ClassManager.prototype.addClass = function(str){
console.log('Class:' + str + ' added');
return this;
}
var manager = new ClassManager();
manager.addClass('classA').addClass('classB').addClass('classC');
// Class:classA added
// Class:classB added
// Class:classC added
//抽象类
function DetectorBase(){
throw new Error('Abstract class can not be invoked directly!');
}
DetectorBase.detect = function (){
console.log('Detection starting');
};
DetectorBase.stop = function(){
console.log('Detector stopped');
};
DetectorBase.init = function(){
throw new Error('Error');
};
function LinkDetector (){};
LinkDetector.prototype = Object.create(Detector.prototype);
LinkDetector.prototype.constructor = LinkDetector;
//defineProperty(ES5)
function Person(name){
Object.defineProperty(this,'name',{value:name,enumerable:true});
}
Object.defineProperty(Person,'ARMS_NUM',{value:2,enumerable:true});
Object.seal(Person.prototype);
Object.seal(Person);
function Student (name, className){
this.className = className;
Person.call(this,name);
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
//模块化
var moduleA;
moduleA = function(){
var prop = 1;
function func (){}
return{
func:func,
prop:prop
}
}();
var moduleA;
moduleA = new function(){
var prop = 1;
function func (){}
this.func = func;
this.prop = prop;
};
正则表达式
概念
在常见的字符串检索或替换中,我们需要提供一种模式表示检索或替换的规则。正则表达式使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。
console.log(/\d\d\d/.test('123'));//true
console.log(/\d\d\d/.test('abc'));//false
var a = new RegExp("Bosn").test("Hi, Bosn");
console.log(a);//true
//特殊字符转义
console.log(/\^abc/.test('^abc'));//true
// global(查询所有) ignoreCase(忽略大小写) multiline(跨行)
console.log(/abc/gim.test("ABC"));//true
RegExp("abc","mgi");
//RegExp对象属性
console.log(/abc/g.global);//true
console.log(/abc/g.ignoreCase);//false
console.log(/abc/g.multiline);//false
console.log(/abc/g.source);//abc
//RegExp对象方法
console.log(/abc/.exec("abcdef"));//abc
console.log(/abc/.test("abcde"));//true
console.log(/abc/.toString());//"/abc/"
var reg = /abc/; reg.compile("def");
console.log(reg.test("def"));//true