面向对象基本概念
-
封装:能够将一个实体的信息、功能、响应都封装到一个单独对象中的特性。
由于JavaScript没有public、private、protected这些关键字,但是可以利用变量的作用域来模拟public和private封装特性
<script>
var Person = (function() {
var name = '张三';
return {
getName: function() {
return name;
}
}
})();
console.log(Person.name); // undefined
console.log(Person.getName()); // hello
</script>
- 继承:在不改变源程序的基础上进行扩充,原功能得以保存,并且对子程序进行扩展,避免重复代码编写
- 多态:允许将子类类型的指针赋值给父类类型的指针;原生JS是弱类型语言,没有多态概念
JavsScript中面向对象的一些概念:
- 类class: ES5以前就是构造函数,ES6中有class
- 实例instance和对象object:构造函数创建出来的对象一般称为实例instance
- 父类和子类:JavaScript也可以称为父对象和子对象
对象属性
属性
- Object.prototype Object 的原型对象,不是每个对象都有prototype属性
- Object.prototype.proto 不是标准方法,不鼓励使用,每个对象都有
__proto__
属性,但是由于浏览器实现方式的不同,__proto__
属性在chrome、firefox中实现了,在IE中并不支持,替代的方法是Object.getPrototypeOf() - Object.prototype.constructor:用于创建一个对象的原型,创建对象的构造函数
特性名称 | 描述 | 默认值 |
---|---|---|
value | 属性的值 | undfined |
writable | 是否可以修改属性的值,true表示可以,false表示不可以 | true |
enumerable | 属性值是否可枚举,true表示可枚举for-in, false表示不可枚举 | true |
configurable | 属性的特性是否可配置,表示能否通过delete删除属性后重新定义属性 | true |
特性名称 | 描述 | 默认值 |
---|---|---|
set | 设置属性时调用的函数 | undefined |
get | 写入属性时调用的函数 | undefined |
configurable | 表示能否通过delete删除属性后重新定义属性 | true |
enumerable | 表示能否通过for-in循环返回属性 | true |
方法
- Object.prototype.toString() 返回对象的字符串表示
- Object.prototype.hasOwnProperty() 返回一个布尔值,表示某个对象是否含有指定的属性,而且此属性非原型链继承,也就是说不会检查原型链上的属性
- Object.prototype.isPrototypeOf() 返回一个布尔值,表示指定的对象是否在本对象的原型链中
- Object.prototype.propertyIsEnumerable() 判断指定属性是否可枚举
- Object.prototype.watch() 给对象的某个属性增加监听
- Object.prototype.unwatch() 移除对象某个属性的监听
- Object.prototype.valueOf() 返回指定对象的原始值
- 获取和设置属性
- Object.defineProperty 定义单个属性
- Object.defineProperties 定义多个属性
- Object.getOwnPropertyDescriptor 获取属性
- Object.assign() 拷贝可枚举属性 (ES6新增)
- Object.create() 创建对象
- Object.entries() 返回一个包含由给定对象所有可枚举属性的属性名和属性值组成的 [属性名,属性值] 键值对的数组,数组中键值对的排列顺序和使用for…in循环遍历该对象时返回的顺序一致
- Object.freeze() 冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象
- Object.getOwnPropertyNames() 返回指定对象的属性名组成的数组
- Object.getPrototypeOf 返回该对象的原型
- Object.is(value1, value2) 判断两个值是否是同一个值 (ES6 新增)
- Object.keys() 返回一个由给定对象的所有可枚举自身属性的属性名组成的数组,数组中属性名的排列顺序和使用for-in循环遍历该对象时返回的顺序一致
- Object.setPrototypeOf(obj, prototype) 将一个指定的对象的原型设置为另一个对象或者null
- Object.values 返回一个包含指定对象所有的可枚举属性值的数组,数组中的值顺序和使用for…in循环遍历的顺序一样
prototype和__proto__
对象类型 | prototype | proto |
---|---|---|
函数对象 | Yes | Yes |
普通对象 | No | Yes |
- 只有函数对象具有
prototype
这个属性 prototype
和__proto__
都是js在定义一个对象时的预定义属性prototype
被实例的__proto__
指向__proto__
指向构造函数的prototype
<script>
const a = function(){}
const b = {}
console.log(typeof a) // function
console.log(typeof b) // object
console.log(typeof a.prototype) // object
console.log(typeof a.__proto__)// function
console.log(typeof b.prototype) // undefined
console.log(typeof b.__proto__) // object
</script>
<script>
const Dogs = function(name) {
this.name = name;
}
Dogs.prototype.DogName = function() {
return this.name
}
const jinmao = new Dogs('jinmao');
console.log(jinmao); //返回对象
console.log(jinmao.DogName());//返回jinmao
</script>
原型继承
原型继承就是利用原型链来实现继承
<script>
function Summer() {
this.SummerName = 'Sum';
}
Summer.prototype.getSummerName= function(){
return this.SummerName;
}
function Sub () {
this.SubNmae='SubNmae';
}
Sub.prototype = new Summer();
Sub.prototype.getSubName = function (){
return this.SubNmae;
}
var SS = new Sub();
console.log(SS.getSubName()); //输出SubNmae
console.log(SS.getSummerName()); //输出Sum
</script>
<script>
function Summer() {
this.SummerName = 'Sum';
}
Summer.prototype= function(){
return this.SummerName;
}
function Sub () {
this.SubNmae='SubNmae';
}
Sub.prototype = new Summer();
Sub.prototype = function (){
return this.SubNmae;
}
var SS = new Sub();
console.log(SS); //返回对象
</script>
构造函数继承
<script>
var person = {
name: '张三',
};
var name = 'window';
var getName = function(){
console.log(this.name);
}
getName() // 输出window
getName.call(person) // 输出张三
</script>
<script>
function person(name) {
this.name = name;
}
function username(name, age) {
name = name;
person.call(this, name);
this.age = age;
}
var ch = new username('张三', 28);
console.log(ch.name); //输出张三
console.log(ch.age); //输出28
</script>
类
<script>
class Person{ //创建类
constructor(name,age){
this.name=name
this.age=age
}
}
var ch=new Person('张三',18)
console.log(ch);
</script>
<script>
//类的继承 extends 关键字左边是子类,右边是父类
class Father{
constructor(name){
this.name='father'
}
speak(){
console.log('我是父类');
}
}
class Son extends Father{
}
var son=new Son()
console.log(son.name);
son.speak()
</script>
<script>
class Father{
constructor(name){
this.name='father'
}
speak(){
console.log('我是父类');
}
}
class Son extends Father{
say(){
console.log('我是子类');
}
}
var son=new Son()
console.log(son.name);
son.speak() //继承父类的
son.say() //子类自己的
</script>
<script>
//构造函数的继承
//子类会自动继承父类的构造函数
//如果父类中没有声明构造函数,也会有一个默认的无参构造函数,这个函数子类也会继承
//如果父类中有声明了构造函数,子类中也声明了构造函数,则在子类的构造函数中编写代码之前,一定要使用super关键字调用父类的构造方法
class Father{
constructor(name){
this.name=name
}
speak(){
console.log('我是父类');
}
}
class Son extends Father{
constructor(name,age) {
super(name)
this.age=age
}
say(){
console.log('我是子类');
}
}
var son=new Son('张三',23)
console.log(son.name,son.age);
</script>
<script>
//继承中,如果子类和父类有相同名的方法,则会使用自己的,而不使用父类中的
class Father{
constructor(name){
this.name=name
}
say(){
console.log('我是父类');
}
}
class Son extends Father{
constructor(name,age) {
super(name)
this.age=age
}
say(){
console.log('我是子类');
}
}
var son=new Son()
son.say() //输出我是子类
</script>
call方法
- call 可以调用函数
- call 可以修改this的指向,使用call()的时候 参数一是修改后的this指向,参数2,参数3…使用逗号隔开连接
<script>
function f1(){
console.log('输出了');
}
f1.call()
</script>
<script>
function f1() {
console.log(this); // this指window 在call调用函数后指向变化为Person
}
function Person() {
this.name = name;
}
var per = new Person();
f1.call(per);
</script>
<script>
//子类构造函数继承父类构造函数中的属性
function Parent(name,age){
console.log(this);
this.name=name
this.age=age
}
function Chinese(name,age,sex){
Parent.call(this,name,age)
this.sex=sex
}
new Parent('张三',23)
new Chinese('李四',25,'男')
</script>
数组方法forEach遍历数组
<script>
var arr=[5,6,7,8]
arr.forEach(function(value, index, arr) {
console.log(value)
})
</script>
数组方法filter过滤数组
<script>
var arr = [5, 6, 7, 8, 9, 10];
var news = arr.filter(function(value, index,arr) {
return value >= 8;
});
console.log(news); //[8,9,10]
</script>
数组方法some
<script>
var arr = [10, 20, 30];
var news = arr.some(function(value,index,arr) {
return value < 9;
});
console.log(news);//返回值是false,只要查到一个满足条件的就终止循环了
</script>
<script>
var arr = [10, 20, 30];
var news = arr.some(function(value,index,arr) {
return value > 20;
});
console.log(news);//返回值是true
</script>
trim方法去除字符串两端的空格
var a = ' hello ';
console.log(a.trim()) //hello 去除两端空格
var b = ' w o r l d ';
console.log(b.trim()) //w o r l d 去除两端空格
获取对象的属性名
<script>
var person = {
name: '张三',
age: 19,
sex: '男'
};
var result = Object.keys(person)
console.log(result)//[name,age,sex]
</script>
商品筛选案例
var tbody = document.querySelector('tbody') //获取页面tbody
//先定义数组对象
var data = [{
id: 1,
pname: '小米10',
price: 5999
}, {
id: 2,
pname: 'oppoReno4',
price: 2999
}, {
id: 3,
pname: '荣耀30s',
price: 3299
}, {
id: 4,
pname: '华为畅享10s',
price: 1999
}, {
id: 5,
pname: '华为mate40',
price: 5999
},{
id: 6,
pname: '华为P40',
price: 3999
}, {
id: 7,
pname: '金立',
price: 999
}, ];
//forEach 循环data数组对象,赋值给tbody
data.forEach(function(value) {
var tr = document.createElement('tr'); //动态创建tr
tr.innerHTML = '<td>' + value.id + '</td><td>' + value.pname + '</td><td>' + value.price + '</td>'; //给tr赋值
tbody.appendChild(tr); //将tr添加到tbody中
});
var btn = document.querySelector('button') //获取button按钮
btn.addEventListener('click', function() { //添加监听事件
var f_price = document.querySelector('.f_price').value //获取输入最低价格
var l_price = document.querySelector('.l_price').value //获取输入最高价格
var phone = document.querySelector('.phone').value //获取输入的品牌名
tbody.innerHTML = '' //将tbody内容清空
data.forEach(function(value) { //forEach 循环data数组对象
if (value.price < l_price && value.price > f_price) { //添加判断条件
var tr = document.createElement('tr'); //动态创建tr节点
tr.innerHTML = '<td>' + value.id + '</td><td>' + value.pname + '</td><td>' + value.price + '</td>'; //动态添加内容
tbody.appendChild(tr); //将内容添加到页面tbody中
}
if (f_price == '' && l_price == '') { //如果价格没输入则走这个语句,上面不执行
if (value.pname.indexOf(phone) >= 0) { //模糊查询次数,如果查到有符合的则执行
var tr = document.createElement('tr'); //动态创建tr节点
tr.innerHTML = '<td>' + value.id + '</td><td>' + value.pname + '</td><td>' + value.price + '</td>'; //动态添加内容
tbody.appendChild(tr); //将内容添加到页面tbody中
}
}
});
})