JS学习技巧
js中不方便调试,但是自从谷歌浏览器等新增了调试,js调试已经不是特别难的事情了
debugger
在代码中加入debugger;
,在谷歌浏览器中按F12,将会把代码断在代码中
在debugger中查看变量的方式:
1)鼠标移动到变量名称上面,即可以查看变量的属性,类似IDEA
2)类似IDEA或者eclipse的watch功能,右边的watch中有个加号,将变量名(或者表达式)输入,按回车即可查看变量
3)在Console端输入变量名或者表达式,按回车即可查看变量
Source里面直接断点
在source里面,找到相应的js直接打断点
Console
用的最多的console如下:
console.log(arr);
console.debug(arr);
console.warn(arr);
console.error(arr);
其他少用的如下:
console.dir(arr); //显示一个对象所有的属性和方法
console.dirxml(info); //用来显示网页的某个节点(node)所包含的html/xml代码
console.assert() //断言,类似Junit的Assert
console.profile() //性能分析
查看变量的方法
console.log打印变量,然后查看变量的__proto__
,比如打印一个Array的变量如下:
可以看到Array有如下方法:concat、copyWithin、entries、fill、filter、find、findIndex、indexOf等方法
constructor是表示构造方法,类似Java的构造方法
ES6代码技巧
let、const、var
let和const都是ES6新版本的js语言规范出来的定义
- 使用var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象;
- 使用let声明的变量,其作用域为该语句所在的代码块内,不存在变量提升;
- 使用const声明的是常量,在后面出现的代码中不能再修改该常量的值。
new Set()
ES6中新增了数据结构Set,用来对Array去重复
let arr = [1, 2, 3, 4];
arr = arr.concat([1, 3]); //arr值为:[1, 2, 3, 4, 1, 3]
let set = new Set(arr);
let newArr = Array.from(set);
console.log(newArr); //newArr值为:[1, 2, 3, 4]
Object.assign()
ES6提供的扩展方法,用于对象的合并拷贝
let obj1 = {a : 1};
let obj2 = {b : 2};
let obj3 = Object.assign({}, obj1, obj2);
console.log(obj3); //{a:1, b:2}
map()
map()方法用于遍历数组,有返回值,可以对数组的每一项进行操作并生成一个新的数组,可以代替for和forEach循环,简化代码
如下给数组里面的每一个对象乘以10
let arr = [1, 2, 3, 4, 5];
let newArr = arr.map((e, i)=> e * 10);
console.log(newArr); //[10, 20, 30, 40, 50]
filter()
filter同样用于遍历数组,就是过滤数组,在每一项元素后面触发一个回调函数,通过判断,保留或移除当前项,最后返回一个新的数组,如:
let arr = [1, 2, 3, 4, 5];
let newArr = arr.filter((e, i)=> e % 2 === 0); //取模,过滤余数不为0的数
console.log(newArr); //[2, 4]
some()
some()方法也是用于遍历数组,在每一项元素后面触发一个回调函数,只要一个满足条件就返回true,否则返回false,类似||
let arr = [{result: true}, {result: false}, {result: false}];
//let newArr = arr.some((e, i) => e.result);
let newArr = arr.some(function(e, i) {return e.result});
console.log(newArr);
every()
every()
和some()
功能一致,完全相反,类似&&,只要一个不满足条件就返回false,否则返回true
||运算符
巧妙的使用||运算符我们可以给变量设置默认值
…运算符
ES6用于解构数组的方法,用于快速获取数组的参数
let [num1, num2, ...nums] = [1, 2, 3];
console.log(num1); //1
console.log(num2); //2
console.log(nums); //[3]
let [num3, ...numN] = [4, 5, 6, 7];
console.log(num3); //4
console.log(numN); //[5, 6, 7]
=>缩减代码量
=>
箭头函数允许你省略参数两边的括号,函数体的花括号,甚至return关键词。代替function用,这个在Python语言大量用到了这种方法,另外Java8也使用了Lambda表达式,与之相类似
比如我们原来在写一个js方法,传入两个参数,返回两个参数的乘积,如下:
function multiply(a, b) {
return a * b;
}
console.log(multiply(2, 3)); //6
使用=>
简化代码,如下:
var multiply = (a, b) => a * b;
console.log(multiply(2, 3)); //6
Java中的Lambda如下:
// 3. 接受2个参数(int类型),并返回他们的和
(int x, int y) -> x + y;
Call和Apply
Call
Call:call方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或者方法
如:
var foo = {
value : 1
};
function bar() {
console.log(this.value);
}
bar.call(foo); //1
衍生,当bar有参数时如下:
var foo = {
value : 1
};
function bar(name) {
console.log(this.value);
console.log(name);
}
bar.call(foo, '111');
//1
//111
重要:
- call改变了this的指向,指向了foo
- bar函数执行
问题:
为了了解原理和深入理解,如果我们不用call,怎么达到这个效果?
Function.prototype.callCopy = function(context) {
context.func = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments['+i+']');
}
eval('context.func('+args+')');
delete context.func; //删除,为了不增加原有对象的属性
};
var foo = {
value : 1
};
function bar(name, firstName) {
console.log(this.value);
console.log(name);
console.log(firstName);
}
bar.callCopy(foo, 'Nick', 'Wu')
js的function是有返回值的,如果要实现带返回值的,就将执行后的效果,赋予到一个临时变量去,然后return出去
代码:
Function.prototype.callCopy = function(context) {
context.func = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments['+i+']');
}
var result = eval('context.func('+args+')');
delete context.func; //删除,为了不增加原有对象的属性
return result;
};
var foo = {
value : 1
};
function bar(name, age) {
return {
value : this.value,
name : name,
age : age
};
}
console.log(bar.callCopy(foo, 'Nick', 21));
至此,完成了call函数的模拟,加深了对call的理解
Apply
应用某一对象的一个方法,用另一个对象替换当前对象。
解析:
如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。
例子:
var foo = {
value : 1,
sayHello : function() {
console.log(this.value);
}
};
var bar = {
value : 3
}
foo.sayHello.apply(bar); //3
也可如下:
function Foo() {
this.value = 1,
this.sayHello = function() {
console.log(this.value);
}
};
function Bar() {
this.value = 3;
}
var foo = new Foo();
var bar = new Bar();
foo.sayHello.apply(bar); //3
分析:如上代码的意思是,将foo的sayHello方法应用到bar对象去,原本bar是没有sayHello方法的,但是这里也执行了sayHello方法(这里并不是将value赋值,而是将整个对象放到sayHello的this中去)
模拟实现Apply
Function.prototype.applyCopy = function(context, arr) {
var context = Object(context) || window;
context.func = this;
var result;
if(!arr) {
result = context.func();
} else {
var args = [];
for(var i = 0, len = arr.length; i < len; i++) {
args.push('arr['+i+']');
}
result = eval('context.func('+args+')');
}
delete context.func;
return result;
};
var foo = {
value : 1,
sayHello : function(num) {
return this.value * num;
}
};
var bar = {
value : 3
};
console.log(foo.sayHello.apply(bar, [10])); //30
console.log(foo.sayHello.applyCopy(bar, [10])); //30
我们可以使用call和apply解决很多面向对象的东西。
比如实现继承:
function Animal(name){
this.name = name;
this.showName = function(){
console.log(this.name);
}
}
function Cat(name){
Animal.call(this, name);
}
var cat = new Cat("Black Cat");
cat.showName();
比如:js的两个Array实现addAll组合到一起,这里就有几种实现方式了
1)定义一个新变量,然后使用concat拼接,这种方式多使用了一个变量
var arr1 = arr1.concat(arr2);
2)使用apply,不需要定义新变量,如下:
Array.prototype.push.apply(arr1,arr2);