js面向对象

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();

注意点:

  1. 在ES6中没有变量提升,所以必须先定义类,才能通过类实例化对象。
  2. 类里面的共有属性和方法一定要加this使用。
  3. 类里面的this指向问题。
  4. 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);
image-20211116134759707

原型链

image-20211116135330208
// 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);
image-20211116151525879 image-20211116151655675
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); 
    }
}

严格模式

image-20211116195530822
// 使用严格模式
<script>
    'use strict'
</script>
<script>
    (function () {
    'use strict'
	})()
</script>

<script>
    // 使用严格模式的函数
    function fn() {
    	'use strict'
	}
    function fn2() {
    }
</script>

变量规定:变量先声明,再使用 不能使用delete删除

this指向

  1. 全局作用域this变为undefined,原先是window
  2. 由于第一条,构造函数不加new用不了

函数变化

  1. 不能有重名的参数
  2. 函数必须声明在顶层,如 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;
}
image-20211117154111605

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值