创建对象的三种方式
ES6前 ,对象不是基于类创建的,而是用一种称为构建函数的特殊函数来定义对象和它们的特征。
- 通过new关键字创建对象
- 通过字面量创建对象
- 通过构造函数创建对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>创建对象的三种方式</title>
</head>
<body>
</body>
<script>
//利用new Object创建对象
let obj1 = new Object();
//利用字面量来创建对象
let obj2 = {};
//利用构造函数来创建对象
function People(name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log('Hello Word');
}
}
//利用构造函数来创建实例化对象
let people1 = new People('尧子陌', '24');
console.log(people1);
console.log(people1.name);
people1.say();
</script>
</html>
构造函数
构造函数是一种特殊的函数,主要用来初始化对象.
即为对象成员变量赋初始值。总之把对象中的公共属性与方法抽取出来,然后封装到这个函数里面
注意事项
1.构造函数用于创建某一类对象,其首字母要大写。
2.构造函数要与new在一起使用才有意义。
new关键字
1.在内存中创建一个新对象
2.让this指向这个新对象
3.执行构造函数的代码,给这个新对象添加属性与方法
4.返回这个新对象(构造函数不需要retern)
静态成员和实例成员
静态成员:在构造函数本体上添加的成员被称为静态成员,只能由构造函数调用
实例成员:在构造函数内部创建的对象成员被称为实例成员,只能由实例化的对象来访问。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>静态成员与实例成员</title>
</head>
<body>
</body>
<script>
//利用构造函数来创建对象
function People(name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log('Hello Word');
}
}
//实例化对象只能通过实例化对象来调用
let people1 = new People('尧子陌', '24');
console.log(people1.name);
people1.say();
//在构造函数上添加的成员被称为静态成员
People.sex = '男';
console.log(People.sex);
</script>
</html>
原型
构造函数很好用 但很浪费内存
每一个构造函数都有一个prototype属性,指向一个对象,利用prototype属性可以共享方法
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>原型</title>
</head>
<body>
</body>
<script>
function People(name, age) {
// 在构造函数内部创建的成员属于实例化成员,只有实例化对象才能调用
this.name = name;
this.age = age;
}
People.prototype.say =function(){
return "hello woord"
}
var People1 = new People('尧子陌', "23");
console.log(People1.say())
var People2 = new People('惊鸿一面','28');
console.log(People2.say());
console.log(People1.say === People2.say);
</script>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原型</title>
</head>
<body>
</body>
<script>
//利用构造函数来创建对象
function People(name, age) {
this.name = name;
this.age = age;
}
// 在原型上定义方法 所有的实例化对象都可以使用此方法
People.prototype.say = function() {
return 'Hello Word'
}
let people1 = new People('尧子陌', '24');
console.log(people1.say());
let people2 = new People('惊鸿', '24');
console.log(people2.say());
console.log(people1.say === people2.say)
</script>
</html>
对象原型
每个对象向都会有一个_proto_属性,指向构造函数中的prototype对象,且与之全等的关系
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>对象原型</title>
</head>
<body>
</body>
<script>
//利用构造函数来创建对象
function People(name, age) {
this.name = name;
this.age = age;
}
// 在原型上定义方法 所有的实例化对象都可以使用此方法
People.prototype.say = function() {
return 'Hello Word'
}
let people1 = new People('尧子陌', '24');
console.dir(People)
//指向构造函数的原型
console.log(people1.__proto__);
// 构造函数的原型等于实例化对象的对象原型
console.log(people1.__proto__ === People.prototype);
</script>
</html>
constructor构造函数
constructor:指向的是引用的构造函数,可以让原型对象重新指向构造函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>constructor构造函数</title>
</head>
<body>
</body>
<script>
//利用构造函数来创建对象
function People(name, age) {
this.name = name;
this.age = age;
}
// 原型
People.prototype = {
//将原型对象采用对象赋值的情况下 constructor的指向会变 需要重新手动改回来
constructor: People,
say: function() {
return 'Hello'
},
eat: function() {
return 'Banner'
}
}
let people1 = new People('尧子陌', '24');
//指向构造函数的原型
console.log(people1.__proto__);
// 构造函数的原型等于实例化对象的对象原型
console.log(people1.__proto__ === People.prototype);
console.log(people1.__proto__.constructor);
console.log(People.prototype.constructor);
</script>
</html>
原型对象 实例对象 构造函数之间的关系
原型链
任何对象都会有_proto_属性,且在js中万物皆对象,由_proto_属性连起来的链条便叫做原型链,且最终值为null
构造函数的原型的_proto_属性指向Object.prototype
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>constructor构造函数</title>
</head>
<body>
</body>
<script>
//利用构造函数来创建对象
function People(name, age) {
this.name = name;
this.age = age;
}
// 原型
People.prototype = {
//将原型对象采用对象赋值的情况下 constructor的指向会变 需要重新手动改回来
constructor: People,
say: function() {
return 'Hello'
},
eat: function() {
return 'Banner'
}
}
let people = new People('尧子陌', '24');
console.log(people.__proto__.__proto__ === People.prototype.__proto__); //true
console.log(People.prototype.__proto__ === Object.prototype); //true
console.log(Object.prototype.__proto__); //null
</script>
</html>
js成员的查找机制
-
当我们访问一个对象的属性与方法的时候,首先看这个对象自身有没有属性与方法。
-
如果没有就开始通过原型对象中的_proto_属性继续查找(Object.prototype)
-
如果还没有,就以此类推继续向上查找,直至值为null的时候
简单而言,就是沿着一条线查找
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原型链成员查找规则</title>
</head>
<body>
</body>
<script>
function Star(uname, age) {
this.uname = name;
this.age = age;
}
Star.prototype.sing = function() {
console.log('会唱歌');
}
Star.prototype.sex = '女';
let YaoZiMo = new Star('尧子陌', '男');
console.log(YaoZiMo.sex);
console.log(Object.prototype.sex);
console.log(YaoZiMo.toString());
Star.prototype.sing();
console.log(Object.prototype.toString());
</script>
</html>
原型对象中的this指向问题
- 构造函数中的this指的是实例化的对象。
- 原型中的this指的是实例化对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原型链成员查找规则</title>
</head>
<body>
</body>
<script>
function Star(uname, age) {
this.uname = uname;
this.age = age;
console.log(this);
}
var that;
Star.prototype.sing = function() {
that = this;
console.log('会唱歌');
}
var YaoZiMo = new Star('尧子陌', '男');
YaoZiMo.sing()
console.log(that === YaoZiMo);
</script>
</html>
扩展内置对象
可以通过原型对象,对原来的内置对象进行扩展自定义的方法。
注意:内置的数组和字符串等内置对象不能给原型对象覆盖;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>扩展原型对象的内置方法</title>
</head>
<body>
</body>
<script>
// 对内置对象扩展自定义的方法
Array.prototype.sum = function() {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum += this[i]
}
return sum;
}
// 查看扩展的原型内置方法
console.log(Array.prototype);
var arr = [1, 2, 3];
console.log(arr.sum());
var arr2 = new Array(10, 20, 30);
console.log(arr2.sum());
</script>
</html>
call()方法
call()方法可以调用函数,并且可以修改this指向,还可以进行传参。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>call()方法</title>
</head>
<body>
</body>
<script>
function fn(x, y) {
console.log('Hello Word');
console.log(this);
console.log(x + y);
}
var obj = {
name: '尧子陌'
}
// call()方法 不仅可以调用函数 而且可改变函数的this值并且传递参数
fn.call(obj, 1, 2)
</script>
</html>
继承
ES6之前并没有跟我们提供extends继承,我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承
借用构造函数继承父类型属性
核心原理:通过call()把父类型的this指向子类型的this,可以实现子类型继承父类型的属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>借助构造函数来实现继承</title>
</head>
<body>
</body>
<script>
//父类构造函数
function Father(name, age) {
// 此时的this指向子类的实例化对象
console.log(this);
this.name = name;
this.age = age;
}
//子类构造函数
function Son(name, age, score) {
//借助call()方法让父类的this指向子类的实例化对象
Father.call(this, name, age);
this.score = score;
}
var son = new Son('尧子陌', '18', '100');
console.log(son);
</script>
</html>
借用原型对象继承父类的方法
思路
-
子类的prototype原型 = new 父类
-
因为父类的实例化对象会另外开辟空间,不会影响父类的原型对象。
-
将子类的constructor重新指向子类的构造函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>借助原型对象类实现继承</title>
</head>
</body>
<script>
//父类构造函数
function Father(name, age) {
// 此时的this指向子类的实例化对象
console.log(this);
this.name = name;
this.age = age;
}
Father.prototype.say = function() {
return 'Hello Word'
}
//子类构造函数
function Son(name, age, score) {
//借助call()方法让父类的this指向子类的实例化对象
Father.call(this, name, age);
this.score = score;
}
//子类的原型对象等于父类的的实例化对象
Son.prototype = new Father();
// 子类的构造函数原型对象的constructor重新指向子类
Son.prototype.constructor = Son;
var son = new Son('尧子陌', '18', '100');
console.log(son.say());
console.log(son);
</script>
</html>
ES6新增数组方法
迭代(遍历)方法:forEach(),map(),filter(),some(),every()
forEach()
array.forEach(function(currentValue,index,arr)
- currentValue:数组当前项的值
- index:数组当前项的索引
- arr:数组对象的本身
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>forEach遍历数组</title>
</head>
<body>
</body>
<script>
// 创建一个数组
let arr = [1, 2, 3];
//求和的变量
var sum = 0;
arr.forEach(function(value, index, array) {
console.log(value);
console.log(index);
console.log(array);
sum += value;
return sum;
})
console.log(sum);
</script>
</html>
filter()
array.filter(funcction(curentValue,index,arr))
注意:主要用来筛选数组,返回的是新数组
- currentValue:数组当前项的值
- index:数组当前项的索引
- arr:数组对象的本身
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>filter()</title>
</head>
<body>
<script>
var arr = [20, 50, 80, 100, 150, 500, 600];
var newArr = arr.filter(function (value, index, array) {
//筛选大于100的数组元素,返回一个新数组
return value > 100;
})
console.log(newArr)
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>filter之筛选数组</title>
</head>
<body>
</body>
<script>
// 创建一个数组
let arr = [100, 500, 800];
//求和的变量
var sum = 0;
var newArr = arr.filter(function(value, index, array) {
return value > 100;
})
console.log(newArr);
</script>
</html>
some()
array.some(funcction(curentValue,index,arr))
注意:主要用来查询数组,返回的是布尔值,当查找到第一个满足条件的数组元素,则停止查找
- currentValue:数组当前项的值
- index:数组当前项的索引
- arr:数组对象的本身
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>some之查询数组</title>
</head>
<body>
</body>
<script>
var arr = ['grren', 'red', 'yellow'];
var flag = arr.some(function(value, index, arr) {
return value == 'yellow'
})
console.log(flag);
</script>
</html>
查询商品案例
核心思路
- 把数据渲染到页面中(forEach)
- 根据价格渲染数据(filter)
- 根据商品名称渲染数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
table {
width: 400px;
border: 1px solid #000;
border-collapse: collapse;
margin: 0 auto;
}
td,
th {
border: 1px solid #000;
text-align: center;
}
input {
width: 50px;
}
.search {
width: 600px;
margin: 20px auto;
}
</style>
</head>
<body>
<div class="search">
按照价格查询: <input type="text" class="start"> - <input type="text" class="end"> <button class="search-price">搜索</button> 按照商品名称查询: <input type="text" class="product"> <button class="search-pro">查询</button>
</div>
<table>
<thead>
<tr>
<th>id</th>
<th>产品名称</th>
<th>价格</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
// 利用新增数组方法操作数据
var data = [{
id: 1,
pname: '小米',
price: 3999
}, {
id: 2,
pname: 'oppo',
price: 999
}, {
id: 3,
pname: '荣耀',
price: 1299
}, {
id: 4,
pname: '华为',
price: 1999
}, ];
//1.获取对应的元素
let tbody = document.querySelector('tbody');
let search_price = document.querySelector('.search-price');
let start = document.querySelector('.start');
let end = document.querySelector('.end')
let product = document.querySelector('.product');
let search_pro = document.querySelector('.search-pro')
//2.将数据渲染到页面中
setDate(data)
function setDate(MyDate) {
tbody.innerHTML = ''
MyDate.forEach(function(value, index, array) {
var tr = document.createElement('tr');
tr.innerHTML = '<td>' + value.id + '</td><td>' + value.pname + '</td><td>' + value.price + '</td>';
tbody.appendChild(tr)
})
}
//2.根据商品查询价格模块
search_price.addEventListener('click', function() {
var newDate = data.filter(function(value, index, array) {
return value.price >= start.value && value.price <= end.value
})
// 再次渲染数据
setDate(newDate)
})
//3.查找商品
search_pro.addEventListener('click', function() {
var arr = [];
data.some(function(value, index, array) {
if (value.pname === product.value) {
arr.push(value)
return true
}
})
setDate(arr)
})
</script>
</body>
</html>
forEach() filter() some()的区别
筛选数组元素的情况下 some()效率更高
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>forEach() filter() some()的区别</title>
</head>
<body>
</body>
<script>
let arr = ['grren', 'yellow', 'red']
// 利用forEach筛选数组元素
arr.forEach(function(value, index, array) {
if (value == 'yellow') {
console.log('已找到元素');
return true
}
console.log('forEach');
})
// 利用filter筛选元素
arr.filter(function(value, index, array) {
if (value == 'yellow') {
console.log('已找到元素');
return true
}
console.log('filter');
})
// 利用some筛选元素
arr.some(function(value, index, array) {
if (value == 'yellow') {
console.log('已找到元素');
return true
}
console.log('some');
})
</script>
</html>
字符串方法
trim()
trim()方法可以去除字符串两侧的空白
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>trim()</title>
</head>
<body>
<input type="text">
<button>提交</button>
<div></div>
</body>
<script>
var str = ' andy ';
console.log(str.length);
var str1 = str.trim();
console.log(str1);
console.log(str1.length);
var input = document.querySelector('input');
var bth = document.querySelector('button');
var box = document.querySelector('div');
bth.addEventListener('click', function() {
var str2 = input.value.trim();
if (str2 === '') {
alert('内容为空')
} else {
box.innerHTML = str2
}
})
</script>
</html>
对象方法
Object.keys()
Object.keys():将目标对象的所有属性保存为数组
Object.keys(obj)
- 效果类似for…in
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Object.keys()</title>
</head>
<body>
</body>
<script>
// Object.keys():可将目标对象所有的属性保存为数组
var obj = {
name: '尧子陌',
age: 24,
sex: '男'
}
console.log(Object.keys(obj));
</script>
</html>
Object.defineProperty()
定义新属性或修改为原来的属性 :Object.defineProperty(obj,prop,descriptor)
- obj:必需 目标对象
- prop:必需:定义或修改属性的名字
- descriptor:必需,目标属性所必需有的属性
descriptor说明
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Object.defineProperty()</title>
</head>
<body>
</body>
<script>
var obj = {
id: 'zero',
name: '尧子陌',
age: '25',
}
// 新增属性
Object.defineProperty(obj, 'sex', {
value: '男'
})
console.log(obj);
Object.defineProperty(obj, 'id', {
//不允许id属性被修改
writable: false
})
Object.defineProperty(obj, 'address', {
enumerable: false,
writable: false,
configurable: false
})
console.log(Object.keys(obj));
</script>
</html>