js 面向对象
类和对象
与 java 大致相同
// 所有的方法不要加 function , 不需要逗号分隔
class Star {
constructor(uname) {
this.uname = uname;
}
sing(song) {
console.log(this.uname + '在唱' + song);
}
}
var ldh = new Star('刘德华');
ldh.sing('冰雨');
类的继承
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
sum() {
console.log(this.x + this.y);
}
}
class Son extends Father {
constructor(x, y) {
super(x, y);
}
}
var son = new Son(12, 13);
继承中的属性或方法查找的就近原则
class Father {
say() {
return '我是爸爸';
}
}
class Son extends Father {
say() {
console.log(super.say() + '的儿子');
}
}
var son = new Son();
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
add() {
console.log(this.x + this.y);
}
}
class Son extends Father {
constructor(x, y) {
// super 必须放在第一行 在子类this之前调用
super(x, y);
this.x = x;
this.y = y;
}
sub() {
console.log(this.x - this.y);
}
}
var son = new Son(3, 4);
son.add();
son.sub();
注意点:
- 在ES6中没有变量提升,所以必须先定义类,才能通过类实例化对象。
- 类里面的共有属性和方法一定要加this使用。
- 类里面的this指向问题。
- constructor 里面的this指向实例对象,方法里面的this指向这个方法的调用者。
var that;
class Star {
constructor(uname, age) {
that = this;
this.uname = uname;
this.age = age;
this.btn = document.querySelector('button');
// 这里的this指实例对象
this.btn.onclick = this.sing;
}
sing() {
// 这里的this 谁调用就指向谁
// 用that转存了this
console.log(that.uname + '在唱歌');
}
}
var ldh = new Star('刘德华', 18);
构造函数和原型
构造函数的方式
function Star(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.sing = function(song) {
console.log(song);
}
}
var obj = new Star('刘德华', 60, '男');
obj.sing('冰雨'); //直接调用了方法 打印出冰雨
// 实例成员的访问只能用实例对象访问
console.log(obj.age); //60
// 静态成员 的添加与访问 只能通过构造函数来访问
Star.height = 170;
console.log(Star.height); //170
console.log(obj.height); //undefined
原型对象
构造函数的问题:相同的方法会开辟不同的内存空间,导致浪费
解决:通过原型对象来共用函数
function Star(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
var ldh = new Star('刘德华', 60, '男');
var zxy = new Star('张学友', 62, '男');
// 原型对象实现共用
Star.prototype.sing = function() {
console.log(this.name + '唱歌');
}
console.log(ldh.sing == zxy.sing); //true
ldh.sing();
zxy.sing();
对象原型
// 对象都有一个属性__proto__指向构造函数的prototype原型对象
// 其意义在于为对象查找提供方向,但其属于非标准属性,所以实际开发中不能进行赋值等操作
console.log(ldh.__proto__);
// 方法查找如java 子有方法先用子,没找到用父的方法
原型constructor 函数
// 以对象的形式赋值原型里的方法时 要重新指定 constructor 的指向
Star.prototype = {
constructor: Star,
sing: function() {
console.log(this.name + '在唱歌');
},
dance: function() {
console.log(this.name + '在跳舞');
}
}
console.log(Star.prototype.constructor);
console.log(ldh.__proto__.constructor);
原型链
// Star 原型对象的 __proto__ 指向 Object 的原型对象
console.log(Star.prototype.__proto__ == Object.prototype); // true
// Object 的原型对象的 __proto__ 指向空
console.log(Object.prototype.__proto__); //null
对象成员查找规则
function Star(name, age) {
this.name = name;
this.age = age;
}
var ldh = new Star('刘德华', 60);
var zxy = new Star('张学友', 62);
// 给原型对象赋值,生成的实例对象就能往上查找
//Star.prototype.sex = '男';
// 给Object 原型对象赋值 同样的效果
Object.prototype.sex = '男';
// 就近原则
ldh.sex = '女';
console.log(ldh.sex);
// Object 的方法
console.log(ldh.toString());
扩展内置对象
Array.prototype.sum = function() {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum += this[i];
}
return sum;
}
var arr = [3, 5, 7];
console.log(arr.sum()); //15
call 方法
function fn(x, y) {
console.log(this.name);
console.log(x + y);
}
var o = {
name: 'andy'
}
// 第一个参数是改变方法调用者,即this指向
// 后几个参数即 方法的形参
fn.call(o, 1, 2);
通过call方法实现继承
function Father(uname, age) {
this.uname = uname;
this.age = age;
}
function Son(uname, age, score) {
Father.call(this, uname, age);
this.score = score;
}
var son = new Son('李四', 18, 91);
console.log(son);
继承,添加方法相关
function Father(uname, age) {
this.uname = uname;
this.age = age;
}
Father.prototype.money = function() {
console.log(100000);
};
function Son(uname, age, score) {
Father.call(this, uname, age);
this.score = score;
}
// Son.prototype = Father.prototype; 这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
Son.prototype = new Father();
// 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
Son.prototype.constructor = Son;
// 这个是子构造函数专门的方法
Son.prototype.exam = function() {
console.log('孩子要考试');
}
var son = new Son('刘德华', 18, 100);
console.log(son);
console.log(Father.prototype);
console.log(Son.prototype.constructor);
ES5新增方法
数字方法
forEach() map() filter() some() every()
forEach()
var arr = [3, 4, 5];
var sum = 0;
arr.forEach(function(value, index, array) {
console.log(value);
console.log(index);
console.log(array); // 返回数组本身
sum += value;
})
console.log(sum);
filter() 返回符合条件的新数组
var arr = [3, 4, 5];
// array 数组本身
var arr2 = arr.filter(function(value, index, array) {
//return value >= 4;
return index > 1;
})
console.log(arr2);
some()
// 查找是否有满足条件的元素 布尔值
var arr = [3, 4, 5, 6];
var flag = arr.some(function(value, index, arr) {
return value > 4;
})
console.log(flag);
foreach 与 some 的区别
some 找到后就会停止循环 return true 的时候停止
foreach 会一直寻找
every() 判断是否都满足
const arr= [
{id: 1, name: '西瓜', state: true},
{id: 2, name: '香蕉', state: false},
{id: 3, name: '菠萝', state: true}
]
// 后面就是表达式,进行判断 true or false ,全部满足则返回 true,否则返回 false
const res = arr.every(item => item.state);
console.log(res);
reduce() 按提供的 reducer 函数来处理 (每次减少,累计处理,不就是一个 reducer 吗)
const res = arr.filter(item => item.state).reduce((sum, curr) => {
return sum += curr.price * curr.count;
}, 0);
console.log(res);
字符串方法
str.trim() 去除两边的空格
var str = ' andy ';
console.log(str);
console.log(str.trim());
Object.keys(obj) 获取所有的键,并返回成一个数组
var obj = {
id: 1,
pname: '小米',
price: 1999,
num: 2000
}
var arr = Object.keys(obj);
console.log(arr);
arr.forEach(function(value) {
console.log(value);
})
Object.defineProperty(obj, prop, descriptor) 不能覆盖原有写上的
descriptor 的说明, 其以对象形式书写
- value:设置属性的值,默认为undefined
- writable:值是否可以重写。true | false 默认为false
- enumerable:目标属性是否可以被枚举。true | false 默认为false
- configurable:目标属性是否可以被删除或是否可以再次修改特性 true | false 默认为false
var obj = {
id: 1,
pname: '小米',
price: 1999,
num: 2000
};
// 第三个参数必须写
Object.defineProperty(obj, 'id', {});
obj.id = 2;
console.log(obj.id);
// 不能被遍历出来
Object.defineProperty(obj, 'address', {
value: '中国山东蓝翔技校',
enumerable: false
});
console.log(Object.keys(obj)); //['id', 'pname', 'price', 'num']
Object.defineProperty(obj, 'address', {
value: '中国山东蓝翔技校',
enumerable: false,
// 不能被删除 并且不允许再修改第三个参数里的特性
configurable: false
});
console.log(obj);
console.log(Object.keys(obj));
函数
// 了解即可 函数也是个实例
var f = new Function('a', 'b', 'console.log(a + b)');
f(1, 2);
几种调用方法 与this指向
// 1.普通函数
function fn() {
console.log(this); // window
}
fn();
// 2.对象的函数
var o = {
say: function() {
console.log(this); //o对象
}
}
o.say();
// 3.构造函数
function Star(name) {
this.name = name;
console.log(this); //ldh对象
}
var ldh = new Star('lisi');
// 4.绑定事件函数
btn.onclick = function() {
console.log(1); // btn对象
}
// 5.定时器函数
setInterval(function() {
console.log(1); //window
}, 1000);
// 6.立即执行函数
(function(name){
console.log(1); //window
})(name)
改变this指向
call() 方法同上笔记 主要用来实现继承
apply() 方法 参数一为调用对象,参数二为数组
var arr = [3, 5, 12, 34, 9];
// 这里的第一个参数指函数的调用对象 第二个参数必须为数组
var max = Math.max.apply(Math, arr);
console.log(max);
bind(thisArg, arg1, arg2, …) 不会调用函数,改变this指向 返回改变了指向的函数拷贝
function fn(x, y) {
console.log(this);
console.log(x + y);
}
var o = {
name: 'andy'
};
// 改变函数指向,并返回
var f = fn.bind(o, 1, 2);
f(); // { name: 'andy' } 3
var btns = document.querySelectorAll('button');
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
this.disabled = true;
setTimeout(function() {
this.disabled = false;
}.bind(this), 2000);
}
}
严格模式
// 使用严格模式
<script>
'use strict'
</script>
<script>
(function () {
'use strict'
})()
</script>
<script>
// 使用严格模式的函数
function fn() {
'use strict'
}
function fn2() {
}
</script>
变量规定:变量先声明,再使用 不能使用delete删除
this指向
- 全局作用域this变为undefined,原先是window
- 由于第一条,构造函数不加new用不了
函数变化
- 不能有重名的参数
- 函数必须声明在顶层,如 if, for 中不能再套函数
高阶函数
它接收函数作为参数或者将函数作为返回值输出
// 作为参数传递
function fn(a, b, callback) {
console.log(a + b);
callback && callback();
}
fn(2, 3, function() {
console.log('事后抽烟');
})
闭包
闭包(closure) 指有权访问另一个函数作用域中的变量的函数
延伸了变量的作用范围。
function fn() {
var num = 10;
// 这个函数就是闭包
return function() {
console.log(num);
}
}
var f = fn();
f();
// 闭包实现的绑定 li
var lis = document.querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
(function(i) {
lis[i].onclick = function() {
console.log(i);
}
})(i)
}
浅拷贝
Object.assign(目标,原对象) // 只拷贝一层,内层对象不拷贝
深拷贝
正则表达式
// 创建方法
var regexp = new RegExp(/表达式/);
var regexp = /表达式/;
// 测试表达式
var regexp = /abc/; // 只要含有 abc 就为true
console.log(regexp.test('adsabcdasf')); //true
// 边界符
var regexp = /^abc/; // 必须以abc开头
var regexp = /abc$/; // 必须以abc结尾
var regexp = /^abc$/; // 必须精确匹配
// 方括号表选择
var regexp = /[abc]/; // 有abc任意一个
var regexp = /^[abc]$/; // abc 三选一
var regexp = /[a-z]/; //a-z 范围
var regexp = /[^a-z]/; // 方括号内部 ^ 表示取反
// 量词类 在后面加
var regexp = /^a+$/; // 出现一次或很多次
var regexp = /^a*$/; // 零次或很多次
var regexp = /^a?$/; // 零次或一次
var regexp = /^3{3}$/; // 限定三次
var regexp = /^3{3,}$/; // 三次或更多次
var regexp = /^3{3,12}$/; // 三次到十二次
// 小括号优先级
var regexp = /^(abc){3}$/; // abc这三个字符重复三次
预定义类
预定义类 | 说明 |
---|---|
\d | 相当于[0-9] |
\D | 零到九以外的数字 |
\w | 任意字母数字下划线[A-Za-z0-9] |
\W | 上述以外的 |
\s | 匹配空格(包括换行符、制表符、空格符)[\t\r\n\v\f] |
\S | 上述以外的 |
字符替换
var ta = document.querySelector('textarea');
ta.onblur = function() {
var result = ta.value.replace(/gay|离谱/g, '**');
ta.value = result;
}
// /gay|离谱/[switch] 可选值g:替换所有 i:忽略大小写 gi:全局加忽略大小写
ES6
let 声明块级作用域变量
不存在变量提升
console.log(a); //会报错
let a = 1;
暂时性死区
var num = 1;
if (true) {
console.log(num); //报错,用了let声明num相当于外面的num没了
let num = 2;
}
const 变量 不可变
- 具有块级作用域
- 必须赋初值
解构赋值
// 数组解构
let [a, b, c] = [1, 2, 3];
// 一一对应赋值 a,b,c 得到 1,2,3
// 对象解构
let {name, age} = {name: '张三', age: 20};
console.log(name);
console.log(age);
// 用新的变量名
let {name: myname, age: myage} = {name: '张三', age: 20};
console.log(myname);
console.log(myage);
箭头函数
const fn = () => {
console.log(1);
}
fn();
// 只有一句代码 省略大括号与 return
const sum = (num1, num2) => num1 + num2;
console.log(sum(1, 2));
// 形参只有一个 可以省略小括号
const print = e => console.log(e);
print(1); // 1
const obj = {name: '张三'};
function fn() {
console.log(this);
// 箭头函数不一样,有自己的this指向,指向的是定义位置上下文的this,即函数作用域里
return () => {
console.log(this);
}
}
const resFn = fn.call(obj);
resFn(); // 两个obj,而没有window
// 因为是在对象里的箭头函数,对象里没有独立作用域,箭头函数是被指定在全局作用域上,即window上
var obj = {
age: 20,
say: () => {
console.log(this); // window
}
}
obj.say();
剩余参数
// 取出剩下的所有参数
const sum = (first, sceond, ...args) => {
let total = 0;
args.forEach(e => total += e);
return total;
}
console.log(sum(10, 20, 40)); // 40
// 取出剩下的所有参数
const sum = (first, ...args) => {
let total = 0;
args.forEach(e => total += e);
return total;
}
console.log(sum(10, 20, 40)); // 60
// 剩余参数与解构配合
let arr = ['jase', 'didi', 'pici'];
let [s1, ...s2] = arr;
console.log(s1); // jase
console.log(s2); // ['didi', 'pici']
扩展运算符
// 扩展运算符
let arr = [1, 2, 3];
console.log(...arr); // 1 2 3 ...ary 为 1,2,3
let arr1 = [1, 2, 4];
let arr2 = [2, 5, 8];
// 方法一
let arr3 = [...arr1, ...arr2];
console.log(arr3);
// 方法二
arr1.push(...arr2);
console.log(arr1);
// 利用扩展运算符转换为数组
let divs = document.querySelectorAll('div');
console.log(divs); // NodeList(5) [div, div, div, div, div] 伪数组
let arr = [...divs];
console.log(typeof(arr));
console.log(arr); // [div, div, div, div, div] 数组
Array的扩展方法
from();
// 这是一个伪数组
let arrLike = {
'0': 'lis2',
'1': 'lis2',
'2': 'lis3',
'length': 3
}
console.log(arrLike);
// 转换为数组
let res = Array.from(arrLike);
console.log(res); // ['lis2', 'lis2', 'lis3']
// 对值进行处理 并返回
let arrLike = {
'0': '2',
'1': '3',
'2': '4',
'length': 3
}
let res2 = Array.from(arrLike, item => item * 2);
console.log(res2);
find();
// 找出第一个符合条件的
let ary = [{
id: 1,
name: 'lisi'
}, {
id: 2,
name: 'whwu'
}]
// 在数组中查找某ID的对象
let res = ary.find(item => item.id == 2);
console.log(res);
findIndex();
let arr = [1, 3, 4, 11];
// 在数组中查找某满足条件的第一个数索引
let res = arr.findIndex(item => item > 3 );
console.log(res); // 2
includes();
let arr = [1, 3, 4, 11];
// 在数组中查找是否包含某元素
let res = arr.includes(3);
console.log(res); // true
String 扩展方法
模板字符串
let who = {
name: 'zhangsan',
age: 18,
sex: '男'
};
// 反引号
let name = `
<div>${who.name}</div>
<div>${who.age}</div>
<div>${who.sex}</div>
`;
console.log(name);
// 可以调用函数
function fn() {
return '桑桑';
}
let str = `this is ${fn()}`;
console.log(str); // this is 桑桑
// 开头与结尾的判断
let str = 'hello jack 1098';
console.log(str.startsWith('hello'));
console.log(str.endsWith('1098'));
console.log('s'.repeat(5)); // sssss
// set 数组去重
let set = new Set([1, 1, 2, 3]);
console.log(set);
let arr = [...set];
console.log(arr);
// set 的方法
set.add() set.delete() set.has() set.clear()
// set 遍历
const set = new Set([1, 1, 2, 3]);
set.forEach(e => console.log(e)) //1,2,3