basic
undefined 是类型也是值
let firstname = undefined;
let selectedcolor = null;
typeof firstname
<“undefined”
typeof selectedColor
<“object”
这里是object了
关于falsy类假
// undefined
// null
// 0
// false
// ‘’
// NaN
除了这些都是类真truthy
false||‘asdf’
‘asdf’ 发现第二个为类真就返回了
for in 和 for of 用法
const person = {
name: ‘Tom’,
age: 30
};
for ( let key in person )
console.log(key, person[key]);
const colors = {‘r’,‘g’,‘b’};
for ( let index in colors )
console.log(index, colors[index]);
for ( let color of colors )
console.log(color);
object
使用Factory来创建object
function createCircle(radius){
return {
radius, // 省略了赋值
draw(){ // 省略了function关键字
console.log(‘draw’);
}
};
}
const circle1 = createCircle(1);
console.log(circle1);
使用Constructor 来创建object,使用new,更像C++(像个狗屁)
function Circle(radius){// 注意大写,像个class似的……
this.radius = radius; // 2. this指向这个空对象
this.draw = function(){
console.log(‘draw’);
}
// 3.return this
}
const circle = new Circle(1); // new发生以下3步隐式行为
// 1. new 就是建立一个空对象,等同 const x = {};
动态object,添加属性和方法
const circle ={ // 虽然是const还是可以添加或者删除属性的哦
radius : 1
};
// const 的object只是这样赋值会报错 circle = {};
// add
circle.color = ‘red’;
circle.draw = function() {}
// delete
delete circle.color;
delete circle.draw;
使用call调用函数
function Circle®{
this.radius = r;
this.draw = funciton(){
consolr.log(‘draw’); // `` 反引号用于多行
}
}
Circle.call( {},1 ) // call函数调用,和下面一行作用一样
const another = new Circle(1);
值类型和引用类型
javascript引用类型是object function array 这3个,其他都是值类型。
这里注意和csharp区别,脑内不要套用class和struct的对应关系。
let x = {value:10}; // 使用对象
let y = x; // = 对于值和引用的意义不同
x.value = 20; // x 和 y 的value 都是20
函数实参,往往用到引用传递
let obj = { value : 10 }; // value会被改变,如果使用number就不会了。
function increase( obj ){
obj.value ++;
}
increase(obj);
如何枚举、克隆(深拷贝)一个对象
for (let key of Object.keys(circle))
console.log(key);
for (let entry of Object.entries(circle))
console.log(entry);
可以使用这种方式来,克隆对象。但现代一般使用的是assign。
const another = Object.assign( {
color : ‘yellow’
},circle );
拆分操作符,也可以克隆
const another = { …circle }; // 拆分到一个新对象里再赋值
Math、String、Date,常用内置对象使用,需要熟悉文档
JavaScript里有2种String
当对string类型变量使用“.”的话javascript就会把string转换为对象。
=== 符号用于2个object
let a1 = new Address( ‘a’,‘b’ );
let a2 = new Address( ‘a’,‘b’ );
let a3 = a1;
console.log( a1 === a2 ); // false 内存地址不同
console.log( a1.aa === a2.aa && a1.bb === a2.bb ); // true
Arrays
常规操作数组、添加、删除、清空
const numbers = [3,4];
//add
numbers.push(5,6);
numbers.unshift(1,2);
numbers.splice(2,0,‘a’,‘b’); // 1, 2, ‘a’, ‘b’, 3, 4, 5, 6
//remove
numbers.pop();
numbers.shift();
numbers.splice(2,1); //从第二个开始删掉1个
//empty
numbers = [];
在数组中查找
1.值的数组
indexof、 include
2.引用的数组
没有include,要使用find
const courses = [
{id:1, name:‘a’},
{id:2, name:‘b’},
];
const course = courses.find( function(course) {
return course.name === ‘a’;
});
=>简写函数
上面的查找函数,由于只有一个参数、函数体只有一行,最终可简写为:
const course = courses.find( course => course.name === ‘a’ );
去掉了function; (); {}; return; 这4个
如何清空数组
let numbers = [1,2,3,4];
let another = numbers;
// 1 如果有其他引用,其实数组还存在
numbers = [];
// 2 推荐
numbers.length = 0;
// 3 复杂
numbers.splice(0,numbers.length);
// 4 低效
while ( numbers.length > 0 )
numbers.pop();
combine and slice数组
const first = [{id:1}]; // 注意对象的话,只是combine了索引
const second = [4,5,6];
const combined = first.concat(second);
first[0].id = 10;
const slice = combined.slice();
console.log(combined); // combine中0的id也变成了10
console.log(slice);
The spread operator
const first = [1,2,3];
const second = [4,5,6];
const combined = […first,‘a’,…second,‘b’];
Testing the Element
const number = [1,2,3];
const allPositive = numbers.every(function(value)
return value >= 0;
);
const numbers = [1,-1,2,3];
const filtered = numbers.filter( n=> n >=0 );
Function
2种定义函数的方式
// 声明
walk();// 由于js执行时函数定义都提前hoisting,所以可以调用
function walk(){
console.log(‘walk’);
}
// 表达式
run();// is not defined,无法调用
let run = function(){
console.log(‘run’);
}
let move = run;
arguments对象
function sum(){
let total = 0;
for ( let value of arguments )
total += value;
return total;
}
console.log(sum(1,2,3,4,5,10));
rest operator例子
区别spread operator
必须是最后参数,参数默认值也要从后面开始
function sum( discount,…prices ){
const total = prices.reduce( (a,b) => a + b );
return total * ( 1 - discount );
}
console.log(sum(0.1,20,30,40));
getter setter例子
const person = {
firstName : ‘Mosh’,
lastName: ‘Hamedani’,
get fullName(){
return ${person.firstNmae} ${person.lastName}
;
},
set fullName( value ){
const parts = value.split( ’ ’ );
this.firstName = parts[0];
this.lastName = parts[1];
}
};
person.fullName = ‘John Smith’;
let vs var定义变量作用域的区别
使用var定义的变量作用域是函数体,而不是程序块
全世界几乎所有语言都不是这样的
var 是 function-scoped
es6加入let const 是block-scoped
function start(){
for ( var i = 0; i < 5; i ++ )
console.log(i);
console.log(i);// 如果用let定义i,这里会报错
}
start();
被添加到window对象了!
var color = ‘red’; // 添加了,覆盖了
let age = 30; // 这个没事
function sayHi(){ // 添加了,覆盖了
console.log(‘Hi’);
}
this指向谁
this 引用了执行当前函数的对象的实例。
如果这个函数是对象的一部分,也就是方法那this就指向这个对象。
否则他不是对象的一部分,那this就指向全局对象(浏览器的window)
但看看以下这个情况:
const video = {
title:‘name’,
tags:[‘a’,‘b’,‘c’],
showTags(){
this.tags.forEach( function( tag ) {
console.log(this,tag); // 由于回调函数,this指全局对象
});
}
};
video.showTags();
那么如何修改呢,使用forEach的第二个参数thisArg传入对象的this。
showTages(){
this.tags.forEach(function(tag){
console.log(this.title,tag);
},this);
}
那么如果没有this参数呢
showTages(){
const self = this;// 定义一个self
this.tags.forEach(function(tag){
console.log(self.title,tag);
});
}
可以使用call apply bind
function playVideo( a, b){
console.log(this);
}
// 使用call的第一个参数
playVideo.call( { name : ‘Tom’ },1,2 );
// 类似的apply,区别参数用数组
playVideo.apply( { name : ‘Tom’ },[1,2] );
// bind方案
const video = {
title:‘name’,
tags:[‘a’,‘b’,‘c’],
showTags(){
this.tags.forEach( function( tag ) {
console.log(this.title,tag);
}.bind(this)); // bind在函数体后
}
};
video.showTags();
或者更新的=>,所以为了解决回调的this问题应该用=>
const video = {
title:‘name’,
tags:[‘a’,‘b’,‘c’],
showTags(){
this.tags.forEach( tag => { // 箭头函数里this和外面一样的
console.log(this.title,tag);
});
}
};