JS篇
变量
- 声明变量的方式
var、let、const
- 多个变量尽量用同一个var声明
var a = 10,
b = 20,
c = 30;
- 变量命名规则:以字母、下划线、符号开头;可以包含数字、字母、下划线、;不可以使用系统的关键字和保留字作为变量的命名
数据类型
- 原始值:
number、string、boolean、undefined、null、Symbol
undefined:变量经过声明但是没有赋值
null:占位
- 引用值数据类型:
Object、Array、function、Date、regExp
var arr = [1, 2];
var arr1 = arr;
arr.push(3);
console.log(arr);
console.log(arr1);
arr = [3, 4];
console.log(arr); [3, 4]
console.log(arr1); [1, 2, 3]
操作符
+
- 算术运算、字符串链接
- 任何数据加上一个字符串都等于一个字符串
()优先级最高,=优先级最低
++、--
a = a + 1;
a++;
a += 1;
var a = 1;
b = a++ + 1;
console.log(b);
console.log(a);
b = ++a + 1;
console.log(a, b);
%、/、*
console.log(1 % 0);
console.log(1 / 0); Infinity
>、<
console.log('A' > 'a');
console.log('10' > '8');
&& || !
undefined、null、"", 'false', NaN, 0转换为boolean值都是false
&&(找假值就结束):前面表达式的值转换boolean值为false直接返回前面的值,否则返回后面表达式的值,依次下去直到遇到假或者执行完所有表达式
var a = 3 && 5;
var b = 0 && 5;
||(找到真值就结束):前面表达式的值转换成boolean值为true,直接返回前面表达式的值,否则直接返回后面表达式的值
var a = 1 || 2;
var b = 0 || 4;
var c = 0 || 'false';
undefined && -1 + NaN + "";
typeof(a);
引用类型
数组
var arr1 = new Array(10);
console.log(arr1);
console.log(arr1.length);
var arr2 = new Array(10, 2, 3);
console.log(arr2.lenght);
console.log(arr2);
打印斐波那契数列
var num = parseInt(prompt(''));
var firstNum = 1,
secondNum = 1,
thirdNum;
if(num > 2){
for(var i = 1; i < num - 2; i++){
thirdNum = firstNum + secondNum;
firstNum = secondNum;
secondNum = thirdNum;
}
console.log(thirdNum);
}else{
console.log(1);
}
数字反序输出
var num = parseInt(prompt(''));
var reverseNum = Number(num.split('').reverse().join(''));
输出100以内的质数
var count = 0;
for(var i = 1; i < 100; i++){
for(var j = 1; j <= Math.sqrt(i); j++){
if(i % j === 0){
count++;
}
}
if(count === 1){
console.log(i);
}
count = 0;
}
switch() case
switch(n){
case 1:
console.log(1);
break;
case 2:
console.log(2);
break;
}
typeof
- 输出的都是字符串类型
- 可以得到
number、string、function、object、boolean、undefined
var num = 123;
console.log(typeof(typeof(num)));
Number、parseInt、parseFloat、toFixed
Number(null);
Number(undefined);
Number('a');
Number(true);
Number(false);
Number('123');
- parseInt(a, b); a: 参数,b:进制
parseInt(8, 5);
parseInt(10, 5);
parseInt(123.4);
parseInt(true);
parseInt(false);
parseInt('123.4');
parseInt('123adfs');
parseFloat('123.12');
parseFloat('123.12sdfsdf');
var num = 123.123;
num.toFixed(1);
toString
var a = 3;
a.toString(2);
a.toString();
charAt()
const str = 'adasf';
console.log(str.charAt(0));
console.log(str[0]);
获取字符串字节长度
str.charCodeAt(i):返回字符串i位置的字符的 Unicode 编码
function getStrLength(str){
var count = 0;
var len = str.lenght;
for(var i = 0; i < len; i++){
if(str.charCodeAt(i) <= 255){
count += 1;
}
if(str.charCodeAt(i) > 255){
count += 2;
}
}
reutrn count;
}
function getStrLenght(str){
var len = str.length;
var count = len;
for(var i = 0; i < len; i++){
if(str.charCodeAt(i) > 255){
count ++;
}
}
return count;
}
隐式转换
isNaN(12);
isNaN('asd');
undefined == null;
NaN == NaN;
函数
函数声明
function func(a, b, c){
arguments.length;
func.length;
a = 3;
console.log(arguments[0]);
arguments[1] = 4;
console.log(b); 4
c = 5;
console.log(arguments[2]);
}
func(1, 2)
函数表达式
var func = function test(){
}
console.log(func);
console.log(test);
console.log(func.name)
var func = function (){
}
console.log(func.name);
预编译
- 函数声明整体提升;变量声明提升
- 任何变量未经声明直接使用,此变量就为全局
window所有
function test(){
var a = b = 123;
}
windown.a;
windown.b;
test()
var a = 123;
windown.a;
预编译过程按照以下过程
- 创建AO对象
- 找形参和变量声明,将变量声明和形参作为AO的属性名
- 将形参和实参统一
- 在函数体里找函数声明,值赋予函数体
1、
function test(a){
console.log(a);
var a = 123;
console.log(a);
function a(){}
console.log(a)
var b = function(){}
console.log(b)
function d(){}
}
test(1)
GO: {
test:undefined => function test(){}
}
AO: {
a: undefined => 1 => function a(){},
b: undefined => ,
d: undefined => function d(){},
}
2、
global = 100;
function fn(){
console.log(global);
global = 200;
console.log(global);
var global = 300;
}
GO: {
global: 100,
fn: function fn(){}
}
AO: {
global: undefined
}
3、
var x = 1,y = z = 0;
function add(n){
return n = n + 1;
}
y = add(x);
function add(n){
return n = n + 2;
}
z = add(x);
console.log(x, y, z);
GO:{
x: undefined,
y: undefined,
z: undefined,
add: undefined, => function add(n){return n = n + 1} => function add(n){return n = n + 3}
}
作用域、作用域链
闭包
- 当内部函数被保存到外部时,将会生成闭包
- 闭包会导致原有作用域链不释放,造成内存泄漏
1、
function test(){
var num = 100;
return function b(){
num ++;
console.log(num);
}
}
var func = test();
func();
func();
2、
function test(){
var num = 100;
function add(){
num ++;
console.log(num);
}
function reduce(){
num --;
console.log(num);
}
return [add, reduce];
}
var func = test();
func[0]();
func[1]();
function debounce(callback, dely){
var timer = null;
return function(){
clearInterval(timer);
var argus = arguments;
var _this = this;
timer = setTimeout(function(){
callback.apply(_this, argus);
},dely || 500)
}
}
function throttle(callback, dely){
var timer = null;
return function(){
if(timer){
return false;
}
var argus = arguments;
var _this = this;
timer = setTimeout(function(){
callback.apply(_this, argus)
timer = null;
},dely || 500)
}
}
立即执行函数
(function(){}());
(function(){})();
function(param){...}(1)
function(param){...};
(1);
function print(){
var arr = [];
for(var i = 0; i < 10; i++){
arr[i] = function(){
console.log(i)
}
}
return arr;
}
var printNum = print();
for(var j = 0;j < 10; j ++){
printNum[j]();
}
function print(){
var arr = [];
for(var i = 0; i < 10; i ++){
(function(j){
arr[j]=function(){
console.log(j);
}
}(i))
}
return arr;
}
var printNum = print();
for(var j = 0;j < 10; j ++){
printNum[j]();
}
function test(){
var liCollection = document.getElementByTagName('li');
var lenght = liCollection.length;
for(var i = 0; i < lenght; i ++){
(function(j){
liCollection[j].onclick = function(){
console.log(j)
}
}(i))
}
return liCollection;
}
,操作符
- 先看前面表达式再看后面表达式,再把后面表达式计算结果返回
1、
var a = (1 - 1, 2 + 1);
2、
var f = (
function a(){
return '1';
},
function b(){
return 1;
}
)();
typeof(f);
3、
var a = 1;
if(function f(){}){
x += typeof f;
}
console.log(x);
对象、包装类
对象
1、字面量
var a = {};
2、构造函数
var b = new Object();
3、自定义
function Car(name){
this.width = 400;
this.height = 200;
this.name = name;
}
var car1 = new Car('宝马');
var car2 = new Car('大众');
console.log(car1.name, car2.name);
4、构造函数创建的对象相互独立
function Person(){
var a = 0;
function func(){
a ++;
console.log(a);
}
this.add = func;
}
var person1 = new Person();
person1.add();
person1.add();
var person2 = new Person();
person2.add();
包装类
1、length 的截断作用
var arr = [1, 2, 3, 4];
arr.length = 2;
console.log(arr);
2、对于原始数据调用一个不存在的属性
var str = 'abc';
console.log(str.lenght);
console.log(str);
var test = typeof(str);
if(test.length === 6){
test.assign = '这是一个属性';
}
console.log(test.assign);
原型、原型链
原型
- 原型是function对象的一个属性,它定义了构造函数构造出的对象的公有祖先。通过该构造函数构造的对象可以继承该原型的属性和方法。原型也是对象
- 利用原型的特点和概念,可以提取公有属性
- 对象如何查看原型:隐式属性
__proto__
- 对象如何查看构造函数:
constructor
- 看看下面这个基本例子
Person.prototype.lastName = 'html';
Person.prototype.say = function(){
console.log('say')
}
function Person(){
this.lastName = 'css';
}
var person1 = new Person();
var person2 = new Person();
person1.say();
- 我们来尝试修改原型属性
var obj = {
name: 'html',
}
Person.prototype.name = 'css';
function Person(){
}
var person = new Person();
person.name;
person.__proto__ = obj;
person.name;
- 我们先来看看下面这个对象操作,再看看
4和5的区别,a.name = 'xxx'是操作a里面的ame属性,如果是a = {}那就是给a重新开辟一块空间,注意这两者区别。
var a = {
name: 'aaa',
}
var b = a;
console.log(b.name);
a.name = 'bbb';
console.log(b.name);
a = {
name: 'ccc',
}
console.log(b.name);
console.log(a.name);
- 改变
prototype上属性的值
Person.prototype.name = 'aaa';
function Person(){};
var person = new Person();
console.log(person.name);
Person.prototype.name = 'bbb';
console.log(person.name);
- 给
prototype重新赋值,由于__proto__的地址已经固定了
Person.prototype.name = 'aaa';
function Person(){};
var person = new Person();
console.log(person.name);
Person.prototype = {
name: 'bbb',
}
console.log(person.name);
- 换个位置,为什么
5和6会出现差异呢,这是因为__proto__要new Person();的时候才生成,生成person的时候Person.prototype已经改变;再看看7就明白了
Person.prototype.name = 'aaa';
function Person(){};
Person.prototype = {
name: 'bbb',
}
var person = new Person();
console.log(person.name);
- 先生成
person1,改了prototype再生成person2
Person.prototype.name = 'aaa';
function Person(){};
var person1 = new Person();
console.log(person1.name);
Person.prototype = {
name: 'bbb',
}
var person2 = new Person();
console.log(person1.name);
console.log(person2.name);
- 指定原型
- 绝大多数对象的最终都会继承自
Object.prototype
Object.create(null);没有原型
- 判断变量类型
Object.prototype.toString().call(123)--->'[Object Number]'
var obj = {
name: 'aaa',
age: 18
}
var person = Object.create(obj);
console.log(person.name);
- 重写原型方法
var num = 1;
num.toString();
Number.prototype.toString = function(){
return 100;
}
num.toString();
- 自身没有到原型链上找
var bar = {a:'002'};
function print(){
bar.a = 'a';
Object.prototype.b = 'b';
return function inner(){
console.log(bar.a);
console.log(bar.b);
}
}
print()();
继承
- 共享原型
Son.prototype = Father.prototype;
function inherit(Target, Origin){
Target.prototype = Origin.prototype;
}
- 圣杯模式
function Son(){}
function Father(){}
function inhert(Target, Origin){
function F(){};
F.prototype = Origin.prototype;
Target.prototype = new F();
Target.prototype.constructor = Target;
Target.prototype.uber = Origin.prototype;
}
inherit(Son, Father);
const son = new Son();
const father = new Father();
- 私有化变量
function Person(name, age){
var preAge = 25;
this.name = name;
this.age = age;
this.say = function(){
console.log(preAge);
}
this.changeAge = function(){
this.age = preAge;
}
}
var person = new Person('cc', 18);
命名空间
- 管理变量,防止污染全局,适用于模块化开发
obj.name--->隐式转换为obj['name']
对象枚举
for in 能拿到原型上的属性,但是不会拿到顶端Object.prototype上的东西
in操作符能拿到原型上的属性,包括Object; 'name' in Object; // true
hasOwnProperty判断属性是否是自身的
var obj = {
name: 'aaa',
age: 18,
}
for(var key in obj){
if(obj.hasOwnProperty(key)){
console.log(key);
console.log(obj[key]);
}
}
判断数据类型
instanceof
var obj = {};
var arr = [];
obj instanceof Object;
arr instanceof Object;
arr instanceof Array;
constructor
obj.constructor;
arr.constructor;
toString
Object.prototype.toString.call(obj);
Object.prototype.toString.call(arr);
Object.prototype.toString.call(123);
this
- 函数预编译过程
this指向window
- 全局作用域里面this指向window
- call和apply可以改变this指向
- obj.func(),func()中this指向obj
1、
var foo = 123;
function test(){
var foo = 456;
this.foo = 789;
console.log(foo);
}
test();
console.log(foo);
2、
var foo = 123;
function test(){
this.foo = 456;
console.log(foo);
}
var obj = new test();
obj.foo;
call/apply改变this指向
- 相同点:都用来改变
this指向
- 不同点:传参方式不同,
call接收参数列表,apply接收一个数组
call
function Person(){
this.name = 'aaa';
this.age = 18;
}
var person = new Person();
console.log(person);
var obj = {};
Person.call(obj, 'bbb', 20);
console.log(obj);
apply
function Person(name, age){
this.name = name;
this.age = age;
}
function Student(name, age, mobile){
this.mobile = mobile;
Person.apply(this, [name, age])
}
var student = new Student('student', 18, '13333333333');
console.log(student);
arguments
function test(){
console.log(arguments.callee);
console.log(arguments.callee === test);
}
test()
function test(){
demo()
}
function demo(){
console.log(demo.caller);
}
test()
拓展
- 深克隆
function deepClone(origin){
var target;
if(typeof(origin)==='object'){
if(origin instanceof Array){
target = [];
origin.forEach(e=>target.push(deepClone(e)));
return target;
}else if(origin instanceof Object){
target = {};
for(var key in origin){
target[key] = deepClone(origin[key]);
}
return target;
}
}
return origin;
}
以下数组方法改变原数组
push()
Array.prototype.mypush = function(){
var argus = [...arguments];
argus.forEach(e=>this[this.length] = e);
}
pop()删除数组最后一位
Array.prototype.mypop = function(){
var len = this.length;
var lastValue = this[len - 1];
this.length = len - 1;
reutrn lastValue;
}
shift()删除数组第一位
unshift()向数组前面添加数据
reverse()
const arr = [1, 2, 3];
arr.reverse();
console.log(arr);
splice(从第几位开始(数字为负从后往前),截取多少长度,添加新的数据)
const arr = [1, 2, 3];
const a = arr.splice(0, 2);
console.log(a);
console.log(arr);
sort
- 返回大于0的数,后面的数放前面
- 返回值为负数,前面的数放在前面
- 为0不动
- 符合冒泡排序算法
- a=1, b=2,3,1
const arr = [1, 2, 3, 1];
arr.sort(function(a,b){
return a-b;
})
乱序
const arr = [1, 2, 3, 1];
arr.sort(()=>{
return Math.random() - 0.5;
})
以下方法不改变原数组
concat
const arr1 = [1];
const arr2 = [2];
const arr3 = arr1.concat(arr2);
console.log(arr1);
console.log(arr2);
toString()
const arr = [1, 2, 3];
arr.toString();
console.log(arr);
slice(a,b) [a,b)左闭右开
const arr = [1, 2, 3, 4];
console.log(arr.slice(0, 2));
slice(a, b) [a,b),左闭右开
Array.prototype.myslice=function(a,b){
const len = this.length;
const arr = [];
for(let i = a; i < b;i+=1){
arr.push(this[i]);
}
return arr;
}
join
const arr= [1 , 2 ,3];
const arr1 = arr.join('-');
console.log(arr1);
split
const str = '1-2-3';
const arr = str.split('-');
console.log(arr);
数组去重
const arr = [1, 1, 1, 2, 2, 2, 'a', 'a'];
Array.prototype.unique = function(oldArr){
const newArr = [];
const obj = {};
this.forEach(e=>{
if(obj[e] === undefined){
obj[e] = 123;
newArr.push(e);
}
})
return newArr;
}