javaScripts(一)

一、基础语法

1、定义变量
  var a=54
2、输出变量
   console.log(a)
3、条件判断
 if (2 > 1) {
    x = 1;
    y = 2;
    z = 3;
    if (x < y) {
        z = 4;
    }
    if (x > y) {
        z = 5;
    }
}


4、注释  //   /*...*/

二、数据类型和字符串

1、number
JavaScript不区分整数和浮点数,统一用Number表示,以下都是Number类型
		123; // 整数123
		0.456; // 浮点数0.456
		1.2345e3; // 科学计数法表示1.2345x1000,等同于1234.5
		-99; // 负数
		NaN; // NaN表示Not a Number,当无法计算结果时用NaN表示
		Infinity; // Infinity表示无限大,当数值超过了JavaScript的Number所能表示的最大值时,就表示为Infinity
		
2、字符串 布尔值  比较运算符和python类似
例外:
第一种是==比较,它会自动转换数据类型再比较,很多时候,会得到非常诡异的结果;
第二种是===比较,它不会自动转换数据类型,如果数据类型不一致,返回false,如果一致,再比较。
由于JavaScript这个设计缺陷,不要使用==比较,始终坚持使用===比较。
 判断NaN的函数:isNaN(NaN)
 
3、未定义 undefined     null空

4、创建数组
   第一种方法:[1, 2, 3.14, 'Hello', null, true];
   第二种方法:new Array(1, 2, 3);//创建了[1,2,3]
   
5、对象
  由一组键值对组成的无序集合,键必须是字符串类型
var person = {
    name: 'Bob',
    age: 20,
    tags: ['js', 'web', 'mobile'],
    city: 'shenzhen',
    hasCar: true,
    zipcode: null
};
JavaScript对象的键都是字符串类型,值可以是任意数据类型。上述person对象一共定义了6个键值对,其中每个键又称为对象的属性,例如,person的name属性为'Bob',zipcode属性为null

获取对象的属性的方法
person.name

6、在JavaScript中,使用等号=对变量进行赋值。可以把任意数据类型赋值给变量,同一个变量可以反复赋值,而且可以是不同类型的变量,但是要注意只能用var申明一次例如:
var a = 123; // a的值是整数123
a = 'ABC'; // a变为字符串

7、模板字符串
		 var name = '小明';
		var age = 20;
		var message = `你好, ${name}, 你今年${age}岁了!`;#**注意字符串两端的字符  【返单引号】**
		alert(message);
8、操作字符串
	var s = 'Hello, world!';
	s.length; // 13
	
		var s = 'Hello, world!';
		
		s[0]; // 'H'
		s[6]; // ' '
		s[7]; // 'w'
		s[12]; // '!'
		s[13]; // undefined 超出范围的索引不会报错,但一律返回undefined

9、需要特别注意的是,字符串是不可变的,如果对字符串的某个索引赋值,不会有任何错误,但是,也没有任何效果:

var s = 'Test';
s[0] = 'X';
alert(s); // s仍然为'Test'

10、toUpperCase()全部大写
 
   var a='helloworld'
   a.toUpperCase()//HELLOWORLD
  
 11、toLowerCase()//全部小写
     var a='HELLOWORLD'
     a.LowerCase()//helloworld
 12、indexOf()//返回指定字符串出现的位置的索引
     var a='helloworld'
     a.indexOf('world')//5
13、substring()//返回指定索引区间的字串
  var a='helloworld'
  a.substring(0,5)//hello

三、数组

1、JavaScript的Array可以包含任意数据类型,并通过索引来访问每个元素
var arr = [1, 2, 3.14, 'Hello', null, true];
arr.length; // 6

请注意,直接给Array的length赋一个新的值会导致Array大小的变化

var arr = [1, 2, 3];
arr.length; // 3
arr.length = 6;
arr; // arr变为[1, 2, 3, undefined, undefined, undefined]
arr.length = 2;
arr; // arr变为[1, 2]

修改:
var arr = [1, 2, 3];
arr[5]=55
arr; // arr变为[1, 2, 3, undefined, undefined, 'x']

2、indexOf()  #搜索一个指定的元素的位置

var arr = [10, 20, '30', 'xyz'];
arr.indexOf(10); // 元素10的索引为0
arr.indexOf(20); // 元素20的索引为1
arr.indexOf(30); // 元素30没有找到,返回-1
arr.indexOf('30'); // 元素'30'的索引为2

3、slice() 截取部分元素

var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
arr.slice(0, 3); // 从索引0开始,到索引3结束,但不包括索引3: ['A', 'B', 'C']
arr.slice(3); // 从索引3开始到结束: ['D', 'E', 'F', 'G']

注意:如果不给slice()传递任何参数,它就会从头到尾截取所有元素。利用这一点,我们可以很容易地复制一个Array

4、push和pop
push()向Array的末尾添加若干元素,pop()则把Array的最后一个元素删除

var a=[1,2,3]
a.push(4,5)
a//[1,2,3,4,5]
a.pop()// 5
a.pop() a.pop() a.pop()
a//[]
a.pop()//不会报错而是会返回undefined

5、unshift和shift
unshirt//往头部增加元素      shirt删除头部第一个元素
var a=[1,2,3,4]
a.unshirt(55)//往头部增加元素 返回对象a的长度
a.shirt()//删除头部第一个元素,返回删除的元素
a.shift(); arr.shift(); arr.shift();arr.shift(); // 连续shift 4次
a//[]
a.shift(); // 空数组继续shift不会报错,而是返回undefined

6、sort排序
sort()可以对当前Array进行排序,它会直接修改当前Array的元素位置,直接调用时,按照默认顺序排序:

var arr = ['B', 'C', 'A'];
arr.sort();
arr; // ['A', 'B', 'C']

7、reverse反转
var a=[1,2,3]
a.reverse()
a//[3,2,1]

8、splice
splice()方法是修改Array的“万能方法”,它可以从指定的索引开始删除若干元素,然后再从该位置添加若干元素:
var s=[1,2,3]
#从索引1开始删除3个元素 并增加两个元素
s.splice(1,3,'hello','world')  //返回删除的元素3
s//[1,'hello','world']
#只增加不删除
s.splice(2,0,99,88)///[1,'hello','world',99,88]
#只删除不增加
ssplice(2,10)//返回删除的元素,超出索引范围不报错
9、concat
concat()方法把当前的Array和另一个Array连接起来,并返回一个新的Array
var a=[1,2,3]
var s=a.concat(10,20)//[1,2,3,10,20]
a//[1,2,3]
请注意,concat()方法并没有修改当前Array,而是返回了一个新的Array。
实际上,concat()方法可以接收任意个元素和Array,并且自动把Array拆开,然后全部添加到新的Array里:
var s=[1,2,3]
var b=s.concat([4,5],6)//[1,2,3,4,5,6]
10、join
var a=[1,2,3]
a.join('*')//返回 “1*2*3”,先自动转换成字符串在连接


四、对象

 1、定义对象的格式
		var xiaoming = {
		    name: '小明',
		    birth: 1990,
		    school: 'No.1 Middle School',
		    height: 1.70,
		    weight: 65,
		    score: null
				};
		获取对象:
		  xiaoming.name//小明
		
		 假设属性包含特殊字符:
		 var xiaohong = {
		    name: '小红',
		    'middle-school': 'No.1 Middle School'
				};
		必须在获取属性的字段加上‘’引号才可以获取
		xiaohong['middle-school']//因为middle-school不是有效的变量所以必须以这个格式访问, 'No.1 Middle School'

2、给对象添加或者删除属性
		  var xiaoming = {
		    name: '小明'
		};
		xiaoming.age; // undefined
		xiaoming.age = 18; // 新增一个age属性
		xiaoming.age; // 18
		delete xiaoming.age; // 删除age属性
		xiaoming.age; // undefined
		delete xiaoming['name']; // 删除name属性
		xiaoming.name; // undefined
		delete xiaoming.school; // 删除一个不存在的school属性也不会报错
 
     
       判断某一对象是否拥有此属性用 'in'
	        格式:
	        'name' in xiaoming; // true
		如果返回结果为true  则不一定是拥有的,有可能的继承的
判断是否自己本身拥有的属性 对象.hasOwnProperty('属性名')
		var xiaoming = {
		    name: '小明'
		};
		xiaoming.hasOwnProperty('name'); // true  本身拥有
		xiaoming.hasOwnProperty('toString'); // false


五、条件判断

   	```

1、条件判断格式:
		**if () { ... } else { ... }**
				var age = 20;
				if (age >= 18) { // 如果age >= 18为true,则执行if语句块
				    alert('adult');
				} else { // 否则执行else语句块
				    alert('teenager');
				}

  条件判断else后面不能省略{..} 否则会出现不可预料的问题 
				var age = 20;
				if (age >= 18)
				    alert('adult');
				else
				    console.log('age < 18'); // 添加一行日志
				    alert('teenager'); // <- 这行语句已经不在else的控制范围了
    相反地,有{}的语句就不会出错:

			var age = 20;
			if (age >= 18) {
			    alert('adult');
			} else {
			    console.log('age < 18');
			    alert('teenager');
			}
**2、多条件判断**  if ... else if....

			var age = 3;
			if (age >= 18) {
			    alert('adult');
			} else if (age >= 6) {
			    alert('teenager');
			} else {
			    alert('kid');
			}
  实际相当于嵌套了一层
		var age = 3;
		if (age >= 18) {
		    alert('adult');
		} else {
		    if (age >= 6) {
		        alert('teenager');
		    } else {
		        alert('kid');
		    }
		}

		javascripts把null、undefined、0、NaN和空字符串''视为false

六、循环

1、**格式(类似java的for循环)**
			var x = 1;
			var i;
			for (i=1;i<=10;i++){
			    x=x*i;
			}
      条件分析:
        i=1 这是初始条件,将变量i置为1;
		i<=10 这是判断条件,满足时就继续循环,不满足就退出循环;
		i++ 这是每次循环后的递增条件,由于每次循环后变量i都会加1,因此它终将在若干次循环后不满 足判断条件i<=10而退出循环。
 
  特别注意:每个变量后面必须以   ;号结尾

2、**循环的条件是可以省略的**
			     var x = 0;
			for (;;) { // 将无限循环下去
			    if (x > 100) {
			        break; // 通过if判断来退出循环
			    }
			    x ++;
			}
3、for......in
		  var o = {
		    name: 'Jack',
		    age: 20,
		    city: 'shenzhen'
		};
		for (var key in o) {
		   if (o.hasOwnProperty(key ))//如果属性不是继承的
		    	console.log(key); // 'name', 'age', 'city'
		}
请注意,for....in对Array循环得到的是string而不是number


由于Array也是对象,而它的每个元素的索引被视为对象的属性,因此,for ... in循环可以直接循环出Array的索引:

			var a = ['A', 'B', 'C'];
			for (var i in a) {
			    console.log(i); // '0', '1', '2'
			    console.log(a[i]); // 'A', 'B', 'C'
			}


   for... of...循环出的是元素:
			var a = ['A', 'B', 'C'];
			for (var i of a) {
			    console.log(i); // 'A', 'B', 'C'
			}


4、while循环
		 var x = 0;
		var n = 99;
		while (n > 0) {
		    x = x + n;
		    n = n - 2;
		}
		x; // 2500

5、do....while//循环结束判断条件
  **~~它和while循环的唯一区别在于,不是在每次循环开始的时候判断条件,而是在每次循环完成的时候判断条件~~ **
				var n = 0;
				do {
				    n = n + 1;
				} while (n < 100);
				n; // 100
				循环结束判断是否满足条件,满足继续执行,不满足退出

 


七、Map和Set

1、Map
 var m=new Map([['name','刘德华'],['age',12],['addr','深圳']])//键必须是字符串
 m.get('name')

  **初始化Map需要一个二维数组,或者直接初始化一个空Map** 
  Map的方法
		    var m = new Map(); // 初始化空Map
			m.set('Adam', 67); // 添加新的key-value
			m.set('Bob', 59);
			m.has('Adam'); // 是否存在key 'Adam': true
			m.get('Adam'); // 67
			m.delete('Adam'); // 删除key 'Adam'
			m.get('Adam'); // undefined
 由于一个key只能对应一个value,所以后面设置的value会覆盖前面设置的值
					 var m = new Map();
					m.set('Adam', 67);
					m.set('Adam', 88);//重复赋值,覆盖前面的值
					m.get('Adam'); // 88



2、Set  **对象.add(值) 添加**             **对象.delete(值)  删除**
 var s= new Set([1,2,3,4,5])
 s.add(9)
 s//{1,2,3,4,5,9}
 s.delete(4)
 s//{1,2,3,5,9}

八、iterable

1、Map  Set  Array都属于iterable类型
			var a = ['A', 'B', 'C'];
			var s = new Set(['A', 'B', 'C']);
			var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
			for (var x of a) { // 遍历Array
			    console.log(x);
			}
			for (var x of s) { // 遍历Set
			    console.log(x);
			}
			for (var x of m) { // 遍历Map
			    console.log(x[0] + '=' + x[1]);
			}
2、for...in循环的是Array的属性
			var a = ['A', 'B', 'C'];
			a.name = 'Hello';
			for (var x in a) {
			    console.log(x); // '0', '1', '2', 'name'
			}
  而for....of修复了这写bug,循环元素本身
			 var a = ['A', 'B', 'C'];
			a.name = 'Hello';
			for (var x of a) {
			    console.log(x); // 'A', 'B', 'C'
			}

3、iterable内置的forEach函数  
  Array:
		 var n=[1,2,3,4]
		 n.forEach(function(element,index,array){
		      // element: 指向当前元素的值
		    // index: 指向当前索引
		    // array: 指向Array对象本身
		       console.log(element,'index=',index)})

Set::Set与Array类似,但Set没有索引,因此回调函数的前两个参数都是元素本身
      var s = new Set(['A', 'B', 'C']);
	 s.forEach(function (element, sameElement, set) {
   		 console.log(element);
		});



Map:  Map的回调函数参数依次为value、key和map本身
		var c=new Map([['name','boady'],['age',12],['addr','深圳']])
		c.forEach(function(value,key,map){
		   console.log(value,key)})


如果不需要某些参数,可以省略掉
		  var a = ['A', 'B', 'C'];
		a.forEach(function (element) {
		    console.log(element);
		});

九、函数

[一、函数的定义和调用]

1、定义函数的格式:
		function abs(x) {
		    if (x >= 0) {
		        return x;
		    } else {
		        return -x;
		    }
		}
		
		解析:
		function指出这是一个函数定义;
		abs是函数的名称;
		(x)括号内列出函数的参数,多个参数以,分隔;
		{ ... }之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。
   函数遇到return返回,如果没有return也会返回只不过是undefined


由于JavaScript的函数也是一个对象,上述定义的abs()函数实际上是一个函数对象,而函数名abs可以视为指向该函数的变量。因此还有一种方法:
 var abs =function(x){
	    if (x >= 0) {
		        return x;
		    } else {
		        return -x;
		    }
}
   这种方式下的function(x){....}是个匿名函数,没有函数名,但是这个函数赋值给了abs,因此通过变量名abs就可以调用该函数,这种语法需要在函数体末尾加一个 ; 表示赋值语句结束。


函数的调用:
      abs(10, 'blablabla'); // 返回10
      abs(-9, 20,'haha', 'hehe', null); // 返回9
      abs(); // 返回NaN
      abs( 'blablabla',10);//NaN


2、arguments,只在函数内部起作用,指向调用者传入的所以参数

		function foo(x) {
		    console.log('x = ' + x); // 获取传入的第一个元素10
		    for (var i=0; i<arguments.length; i++) {    //对调用者传入的所有参数进行遍历  10, 20, 30
		        console.log('arg ' + i + ' = ' + arguments[i]); 
		    }
		}
		foo(10, 20, 30);
		
执行结果:
					  x = 10
					arg 0 = 10
					arg 1 = 20
					arg 2 = 30
   


3、利用arguments,获得调用者传入的所有参数。也就是说,即使函数不定义任何参数,还是可以拿到参数的值:
		function abs() {
		    if (arguments.length === 0) {
		        return 0;
		    }
		    var x = arguments[0];
		    return x >= 0 ? x : -x;
		}
		
		abs(); // 0
		abs(10); // 10
		abs(-9); // 9



4、rest参数
  由于JavaScript函数允许接收任意个参数,于是我们就不得不用arguments来获取所有参数
      function foo(a, b) {
    var i, rest = [];//i表示接收的2个参数ab,rest定义一个空列表用来接收多余的参数
    if (arguments.length > 2) {//判断如果传入参数的个数大于2个
        for (i = 2; i<arguments.length; i++) {
            rest.push(arguments[i]);//把传入多余的参数添加进入rest
        }
    }
    console.log('a = ' + a);
    console.log('b = ' + b);
    console.log(rest);
}



标准写法:
			 function foo(a, b, ...rest) {
			    console.log('a = ' + a);
			    console.log('b = ' + b);
			    console.log(rest);
			}
			
			foo(1, 2, 3, 4, 5);
			// 结果:
			// a = 1
			// b = 2
			// Array [ 3, 4, 5 ]
			
			foo();
			// 结果:
			// a = undefined
			// b = undefined
			// Array []
		如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined




[二、变量作用域与解构赋值]

1、如果一个变量实在函数内部定义的,他的作用域就在函数内部,外部不可以调用


			function foo() {
			    var x = 1;
			    x = x + 1;
			}
			
			x = x + 2; // ReferenceError! 无法在函数体外引用变量x

 如果两个不同的函数各自申明了同一个变量,那么该变量只在各自的函数体内起作用。换句话说,不同函数内部的同名变量互相独立,互不影响
			function foo() {
			    var x = 1;
			    x = x + 1;
			}
			
			function bar() {
			    var x = 'A';
			    x = x + 'B';
			}


内部可以访问外部的变量,反之,则不可以

		function foo() {
		    var x = 1;
		    function bar() {
		        var y = x + 1; // bar可以访问foo的变量x!
		    }
		    var z = y + 1; // ReferenceError! foo不可以访问bar的变量y!
		}


2、变量提升
 
 JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:
		function foo() {
		    var x = 'Hello, ' + y;
		    console.log(x);//Hello, undefined
		    var y = 'Bob';
		}
		
		foo();

解析:
虽然是strict模式,但语句var x = 'Hello, ' + y;并不报错,原因是变量y在稍后申明了。但是console.log显示Hello, undefined,说明变量y的值为undefined。这正是因为JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值。

javascripts看到的代码为:
			function foo() {
			    var y; // 提升变量y的申明,此时y为undefined
			    var x = 'Hello, ' + y;
			    console.log(x);
			    y = 'Bob';
			}


为了避免此类问题,需要先在函数内部定义所有变量
			function foo() {
			    var
			        x = 1, // x初始化为1
			        y = x + 1, // y初始化为2
			        z, i; // z和i为undefined
			    // 其他语句:
			    for (i=0; i<100; i++) {
			        ...
			    }
			}

3、全局作用域
JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性

'use strict';

var course = 'Learn JavaScript';
alert(course); // 'Learn JavaScript'
alert(window.course); // 'Learn JavaScript'


以变量方式var foo = function () {}定义的函数实际上也是一个全局变量,因此,顶层函数的定义也被视为一个全局变量,并绑定到window对象:

			'use strict';
			
			function foo() {
			    alert('foo');
			}
			
			foo(); // 直接调用foo()
			window.foo(); // 通过window.foo()调用


4、名字空间
为了减少冲突把自己的所有变量和函数绑定到一个全局变量上面;
		// 唯一的全局变量MYAPP:
		var MYAPP = {};
		
		// 其他变量:
		MYAPP.name = 'myapp';
		MYAPP.version = 1.0;
		
		// 其他函数:
		MYAPP.foo = function () {
		    return 'foo';
		};

5、局部作用域
用let替代var可以申明一个块级作用域的变量:
		function foo() {
		    var sum = 0;
		    for (let i=0; i<100; i++) {
		        sum += i;
		    }
		    // SyntaxError:
		    i += 1;//只能在for循环内部访问,因为是块级作用域的变量
		}

6、常量  const 
		const PI = 3.14;
		PI = 3; // 某些浏览器不报错,但是无效果!
		PI; // 3.14

7、解构赋值
	// 如果浏览器支持解构赋值就不会报错:
	var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
	// x, y, z分别被赋值为数组对应元素:
	console.log('x = ' + x + ', y = ' + y + ', z = ' + z);

存在嵌套的赋值:
		let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
		x; // 'hello'
		y; // 'JavaScript'
		z; // 'ES6'

忽略某些元素的赋值:
			let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素
			z; // 'ES6'


对嵌套对象进行赋值:

		var person = {
		    name: '小明',
		    age: 20,
		    gender: 'male',
		    passport: 'G-12345678',
		    school: 'No.4 middle school',
		    address: {
		        city: 'Beijing',
		        street: 'No.1 Road',
		        zipcode: '100001'
		    }
		};
		var {name, address: {city, zip}} = person;
		name; // '小明'
		city; // 'Beijing'
		zip; // undefined, 因为属性名是zipcode而不是zip
		// 注意: address不是变量,而是为了让city和zip获得嵌套的address对象的属性:
		address; // Uncaught ReferenceError: address is not defined


变量名和属性名不一致的赋值:

		var person = {
		    name: '小明',
		    age: 20,
		    gender: 'male',
		    passport: 'G-12345678',
		    school: 'No.4 middle school'
		};
		
		// 把passport属性赋值给变量id:
		let {name, passport:id} = person;
		name; // '小明'
		id; // 'G-12345678'
		// 注意: passport不是变量,而是为了让变量id获得passport属性:
		passport; // Uncaught ReferenceError: passport is not defined


设置默认值:

		var person = {
		    name: '小明',
		    age: 20,
		    gender: 'male',
		    passport: 'G-12345678'
		};
		
		// 如果person对象没有single属性,默认赋值为true:
		var {name, single=true} = person;
		name; // '小明'
		single; // true


声明过的再次赋值报错:
		// 声明变量:
		var x, y;
		// 解构赋值:
		{x, y} = { name: '小明', x: 100, y: 200};
		// 语法错误: Uncaught SyntaxError: Unexpected token =
  原因:
  这是因为JavaScript引擎把{开头的语句当作了块处理,于是=不再合法。
  解决方法是用小括号括起来:

					({x, y} = { name: '小明', x: 100, y: 200});




8、使用场景:
获取当前页面地址和域名:
var {hostname:domain, pathname:path} = location;



[三、方法]

1、对象绑定方法:
			var xiaoming = {
		    name: '小明',
		    birth: 1990,
		    age: function () {
		        var y = new Date().getFullYear();
		        return y - this.birth;
		    }
		};
		
		xiaoming.age; // function xiaoming.age()
		xiaoming.age(); // 今年调用是29,明年调用就变成30了

在一个方法内部,this是一个特殊变量,它始终指向当前对象,也就是xiaoming这个变量。所以,this.birth可以拿到xiaoming的birth属性。
	以对象的方式调用比如:xiaoming.age()        this指向对象xiaoming
	如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window

this只在age方法function 的函数有用,在内部定义的函数this又指向undefined

'use strict';

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        function getAgeFromBirth() {
            var y = new Date().getFullYear();
            return y - this.birth;
        }
        return getAgeFromBirth();
    }
};
xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined

解决方法:
var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function(){
           var that=this;//先拿到this赋值给that
           function function1(){
               var y = new Date().getFullYear();
               return y - that.birth;
    }      return function1();
  }
};
xiaoming.age();//29


2、绑定this指定对象  apply()    call()
			apply()把参数打包成Array再传入;
			call()把参数按顺序传入。
		Math.max.apply(null, [3, 5, 4]); // 5
		Math.max.call(null, 3, 5, 4); // 5
对普通函数调用,我们通常把this绑定为null。

			function getAge() {
			    var y = new Date().getFullYear();
			    return y - this.birth;
			}
			
			var xiaoming = {
			    name: '小明',
			    birth: 1990,
			    age: getAge
			};
			
			xiaoming.age(); // 25
			getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空


3、装饰器

			'use strict';	
			var count = 0;
			var oldParseInt = parseInt; // 保存原函数	
			window.parseInt = function () {
			    count += 1;
			    return oldParseInt.apply(null, arguments); // 调用原函数
			};
			
			// 测试:
			parseInt('10');
			parseInt('20');
			parseInt('30');
			console.log('count = ' + count); // 3



四、高阶函数之map  reduce
传入函数f作为参数
function add(x, y, f) {
    return f(x) + f(y);
}
add(2,5,Math.abs)//x=2,y=5,Math.abs=f

1、map  
		function pow(x) {
		    return x **3;
		};
		var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
		var results = arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81],把函数pow作用于arr的每个元素并返回一个新的Array
		console.log(results);

   使用for循环处理上面的问题:
		    var f = function (x) {
		    return x * x;
		};
		
		var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
		var result = [];
		for (var i=0; i<arr.length; i++) {
		    result.push(f(arr[i]));
		}


2、reduce

练习:利用reduce()求积:

'use strict';
function product(arr) {
   return arr.reduce(function(x,y) { 
   return x*y;
 }
);
}

数字转换成字符串
var arr=[1,5,9]
function prd(arr){
   return arr.reduce(function(c,v){
   return c*10+v;}
)
};
prd(arr)//159


五、高阶函数之fiter

1、filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。
			var arr = [1, 2, 4, 5, 6, 9, 10, 15];
			var r = arr.filter(function (x) {
			    return x % 2 !== 0;//返回奇数
			});
			r; // [1, 5, 9, 15]
			
			把一个Array中的空字符串删掉,可以这么写:
			
			var arr = ['A', '', 'B', null, undefined, 'C', '  '];
			var r = arr.filter(function (s) {
			    return s && s.trim(); // 注意:IE9以下的版本没有trim()方法
			});
			r; // ['A', 'B', 'C']
			

去除重复元素
		'use strict';
		
		var
		    r,
		    arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
		
		r = arr.filter(function (element, index, self) {
		    return self.indexOf(element) === index;
		});
		
		console.log(r.toString());
		去除重复元素依靠的是indexOf总是返回第一个元素的位置,后续的重复元素位置与indexOf返回的位置不相等,因此被filter滤掉了
		
2、回调函数
	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;
	});



筛选素数:
   function get_primes(arr) {
	    var r=arr.filter(function(element, index, self) {
			    if (element <= 3) return element > 1;
			    for (let i = 2; i < element; i++) {
			        if (element % i == 0) return false;
			    }
			    return true;
			});
	 return r;


六、高阶函数之sort

var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
    if (x < y) {
        return 1;
    }
    if (x > y) {
        return -1;
    }
    return 0;
}); // [20, 10, 2, 1]
如果x<y  返回-1,x>y 返回1  升序排列
如果x<y  返回1,x>y 返回-1  降序排列

---此处不是很理解---



七、高阶函数之Array

1、every
  var arr=['apple','banana','orange']
  console.log(arr.every(function(s){
         return s.length>0;
}));//因为所有元素都满足s.length>0
console.log(arr.every(function(s){
	     return `s.toUpperCase()===s;
}))


2、find 查找满足条件的第一个元素
 var arr=['apple','Als','Orange']
console.log(arr.find(function(s){
     return `s.toLowerCase()===s;//全部小写的元素
}));
console.log(arr.find(function(s){
     return `s.toUpperCase()===`s;//全部大写的元素
}))



3、findindex 找到了返回满足条件的第一个元素的索引,没有找到返回-1
var arr = ['Apple', 'pear', 'orange'];
console.log(arr.findIndex(function (s) {
    return `s.toLowerCase() === s;
})); // 1, 因为'pear'的索引是1

console.log(arr.findIndex(function (s) {
    return `s.toUpperCase() === s;
})); // -1

4、forEach  把每个元素依次作用于传入的函数,但不会返回新的数组
  var arr = ['Apple', 'pear', 'orange'];
   arr.forEach(console.log); // 依次打印每个元素


八、闭包   把函数作为结果值返回

 1、function lazy_sum(arr) {
    var sum = function () {
        return arr.reduce(function (x, y) {
            return x + y;
        });
    }
    return sum;
}

当我们调用lazy_sum()时,返回的并不是求和结果,而是求和函数:
var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()

调用函数f时,才真正计算求和的结果:
f(); // 15


闭包实现求次方
		function make_pow(n) {
		    return function (x) {
		        return Math.pow(x, n);
		    }
		}
		



九、箭头函数
1、格式:
			   x => x * x
		上面的箭头函数相当于:
			
			function (x) {
			    return x * x;
			}
         
	 x => {
			    if (x > 0) {
			        return x * x;
			    }
			    else {
			        return - x * x;
			    }
			}

多个参数:
			// 两个参数:
			(x, y) => x * x + y * y
			
			// 无参数:
			() => 3.14
			
			// 可变参数:
			(x, y, ...rest) => {
			    var i, sum = x + y;
			    for (i=0; i<rest.length; i++) {
			        sum += rest[i];
			    }
			    return sum;
			}


如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:

// SyntaxError:
x => { foo: x }

因为和函数体的{ ... }有语法冲突,所以要改为:

// ok:
x => ({ foo: x })



2、this

			var obj = {
			    birth: 1990,
			    getAge: function () {
			        var b = this.birth; // 1990
			        var fn = function () {
			            return new Date().getFullYear() - this.birth; // this指向window或undefined
			        };
			        return fn();
			    }
			};


箭头函数修复了这个问题:
			var obj = {
			    birth: 1990,
			    getAge: function () {
			        var b = this.birth; // 1990
			        var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
			        return fn();
			    }
			};
			obj.getAge(); // 25


箭头函数排序
		arr.sort((x, y) => {
		   return x-y;负数调换位置
		});
		console.log(arr); // [1, 2, 10, 20]


十、generator
1、格式:
		  function* fib(max) {
		    var
		        t,
		        a = 0,
		        b = 1,
		        n = 0;
		    while (n < max) {
		        yield a;
		        [a, b] = [b, a + b];
		        n ++;
		    }
		    return;
		}
执行:
			 var f = fib(5);
			f.next(); // {value: 0, done: false}
			f.next(); // {value: 1, done: false}
			f.next(); // {value: 1, done: false}
			f.next(); // {value: 2, done: false}
			f.next(); // {value: 3, done: false}
			f.next(); // {value: undefined, done: true}

用for...of迭代:
   for (var x of fib(10)) {
       console.log(x); // 依次输出0, 1, 1, 2, 3, ...
}


自增id实例:
 function* next_id(id){
    var id = 0;
    while(1){
			yield ++id;
    }
}


十、标准对象

1、typeof获取对象的类型
		typeof 123; // 'number'
		typeof NaN; // 'number'
		typeof 'str'; // 'string'
		typeof true; // 'boolean'
		typeof undefined; // 'undefined'
		typeof Math.abs; // 'function'
		typeof null; // 'object'
		typeof []; // 'object'
		typeof {}; // 'object'
2、包装对象
		 var n = new Number(123); // 123,生成了新的包装类型object
		var b = new Boolean(true); // true,生成了新的包装类型object
		var s = new String('str'); // 'str',生成了新的包装类型object
因为类型变了。所以:

		typeof new Number(123); // 'object'
		new Number(123) === 123; // false
		
		typeof new Boolean(true); // 'object'
		new Boolean(true) === true; // false
		
		typeof new String('str'); // 'object'
		new String('str') === 'str'; // false

包装对象时缺少关键字new,会按照普通函数处理
		var n = Number('123'); // 123,相当于parseInt()或parseFloat()
		typeof n; // 'number'
		
		var b = Boolean('true'); // true
		typeof b; // 'boolean'
		
		var b2 = Boolean('false'); // true! 'false'字符串转换结果为true!因为它是非空字符串!
		var b3 = Boolean(''); // false
		
		var s = String(123.45); // '123.45'
		typeof s; // 'string'

总结规则:

		不要使用new Number()、new Boolean()、new String()创建包装对象;
		用parseInt()或parseFloat()来转换任意类型到number;
		用String()来转换任意类型到string,或者直接调用某个对象的toString()方法;
		通常不必把任意类型转换为boolean再判断,因为可以直接写if (myVar) {...};
		typeof操作符可以判断出number、boolean、string、function和undefined;
		判断Array要使用Array.isArray(arr);
		判断null请使用myVar === null;
		判断某个全局变量是否存在用typeof window.myVar === 'undefined';
		函数内部判断某个变量是否存在用typeof myVar === 'undefined'。



一、date
1、获取系统当前时间
		var now = new Date();
		now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
		now.getFullYear(); // 2015, 年份
		now.getMonth(); // 5, 月份,注意月份范围是0~11,5表示六月
		now.getDate(); // 24, 表示24号
		now.getDay(); // 3, 表示星期三
		now.getHours(); // 19, 24小时制
		now.getMinutes(); // 49, 分钟
		now.getSeconds(); // 22, 秒
		now.getMilliseconds(); // 875, 毫秒数
		now.getTime(); // 1435146562875, 以number形式表示的时间戳
2、创建指定日期
	   var d = new Date(2015, 5, 19, 20, 15, 30, 123);
	   d; // Fri Jun 19 2015 20:15:30 GMT+0800 (CST)

第二种创建方式:
		var d = Date.parse('2015-06-24T19:49:22.875+08:00');
		d; // 1435146562875
		d.getMonth(); // 5


二、RegExp ---正则匹配---
 1、格式:
 第一种方式是直接通过    /正则表达式/      写出来,
 第二种方式是通过new RegExp('正则表达式')创建一个RegExp对象。

两种写法是一样的:
var re1 = /ABC\-001/;
var re2 = new RegExp('ABC\\-001');//需要处理字符串转义问题
re1; // /ABC\-001/
re2; // /ABC\-001/


var re = /^\d{3}\-\d{3,8}$/;
re.test('010-12345'); // true
re.test('010-1234x'); // false
re.test('010 12345'); // false

RegExp对象的test()方法用于测试给定的字符串是否符合条件。


2、切分字符串

'a b   c'.split(' '); // ['a', 'b', '', '', 'c']正常切分无法识别连续空格
'a b   c'.split(/\s+/); // ['a', 'b', 'c']  正则表达式切分

'a,b, c  d'.split(/[\s\,]+/); // ['a', 'b', 'c', 'd']
'a,b;; c  d'.split(/[\s\,\;]+/); // ['a', 'b', 'c', 'd']

3、分组

var re = /^(\d{3})-(\d{3,8})$/;
re.exec('010-12345'); // ['010-12345', '010', '12345']
re.exec('010 12345'); // null 匹配失败

var re = /^(\d+?)(1*)$/;去除贪婪匹配
re.exec('102311'); // ['102311', '1023', '11']


4、全局搜索 g
var s = 'JavaScript, VBScript, JScript and ECMAScript';
var re=/[a-zA-Z]+Script/g;  //后面的g表示去全局匹配

// 使用全局匹配:
re.exec(s); // ['JavaScript']
re.lastIndex; // 10

re.exec(s); // ['VBScript']
re.lastIndex; // 20

re.exec(s); // ['JScript']
re.lastIndex; // 29

re.exec(s); // ['ECMAScript']
re.lastIndex; // 44

re.exec(s); // null,直到结束仍没有匹配到

三、Json
		number:和JavaScript的number完全一致;
		boolean:就是JavaScript的true或false;
		string:就是JavaScript的string;
		null:就是JavaScript的null;
		array:就是JavaScript的Array表示方式——[];
		object:就是JavaScript的{ ... }表示方式。

1、序列化
		'use strict';
		
		var xiaoming = {
		    name: '小明',
		    age: 14,
		    gender: true,
		    height: 1.65,
		    grade: null,
		    'middle-school': '\"W3C\" Middle School',
		    skills: ['JavaScript', 'Java', 'Python', 'Lisp']
		};

var s = JSON.stringify(xiaoming);
console.log(s);

JSON.stringify(xiaoming, null, '  ');//可以展示好看一点并进行缩进

运行结果:
{
  "name": "小明",
  "age": 14,
  "gender": true,
  "height": 1.65,
  "grade": null,
  "middle-school": "\"W3C\" Middle School",
  "skills": [
    "JavaScript",
    "Java",
    "Python",
    "Lisp"
  ]
}

还可以筛选指定属性:
JSON.stringify(xiaoming, ['name', 'skills'], '  ');
结果:
"{
  "name": "小明",
  "skills": [
    "JavaScript",
    "Java",
    "Python",
    "Lisp"
  ]
}"


传入函数进行处理对象的键值:
		function convert(key, value) {
		    if (typeof value === 'string') {
		        return value.toUpperCase();
		    }
		    return value;
		}
		
		JSON.stringify(xiaoming, convert, '  ');


定义方法toJSON指定序列化的数据

var xiaoming = {
    name: '小明',
    age: 14,
    gender: true,
    height: 1.65,
    grade: null,
    'middle-school': '\"W3C\" Middle School',
    skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
    toJSON: function () {
        return { // 只输出name和age,并且改变了key:
            'Name': this.name,
            'Age': this.age
        };
    }
};

JSON.stringify(xiaoming); // '{"Name":"小明","Age":14}'


2、反序列化 JSON.parse()
	JSON.parse('[1,2,3,true]'); // [1, 2, 3, true]
	JSON.parse('{"name":"小明","age":14}'); // Object {name: '小明', age: 14}
	JSON.parse('true'); // true
	JSON.parse('123.45'); // 123.45

接收一个函数:
		var obj = JSON.parse('{"name":"小明","age":14}', function (key, value) {
		    if (key === 'name') {
		        return value + '同学';
		    }
		    else
		        return value;
		});
		console.log(JSON.stringify(obj)); // {name: '小明同学', age: 14}

十一、面向对象编程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值