对象的创建方式
1.1字面量方式
var obj = {}
1.2普通模式
var Person=new Object()
Person.name='yhb'
Person.age=20
Person.speak=function(){
console.log('hello');
}
console.log(Person);
缺点:
- 因为是基于 Object 基类创建,所以无法获知对象的具体类型
- 初始化成员非常麻烦
1.3构造函数方式
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>创建自定义的构建函数(创建对象 )</title>
<script type="text/javascript">
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
}
// 第一种写法:
var person=new Person('张三',23,'软件开发');
alert('姓名为:' person.name ',年龄为:' person.age ',职位是:' person.job);
// 第二种写法:
var person1=new Person();
person1.name='王五';
person1.age=20;
person1.job='软件技术系';
alert('姓名为:' person1.name ',年龄为:' person1.age ',职位为:' person1.job);
</script>
</head>
<body>
</body>
</html>
缺点:每个函数都会开辟一块新的内存,造成内存浪费
实例化对象的原型链和构造函数的原型链
易错点:
(1)p1是手动创建的,没有constructor属性,p1.constructor是访问的Person.prototype上的constructor属性;
(2)Function是自己创建的自己,Function.constructor指向自己;
(3)Object对象是Function创建的;
(4)每个构造函数、普通函数和Function都有自己的prototype属性;
(5)Function.proto指向Object.prototype,Object.prototype的proto指向null
1.1.proto_和prototype的区别:
prototype属性是一个静态属性,
_proto_属性是一个实例属性。
prototype表示类的原型对象,_proto_表示原型对象中定义的内部属性[prototype]的值。
类的每一个实例都有一个_proto_属性,用于引用创建它的构造方法的prototype属性,也就是该类的原型对象,即存在如下等式:(new Array(“abc”)).proto===Array.prototype (Array(“abc”)为Array的实例)
关于protohe prototype的几个概念
- 构造函数有一个原型对象,通过 prototype 获取
- 基于构造函数创建对象后,每个对象都有一个私有的 proto 属性,指向兑现的构造函数的原型对象
- 基于上面两点,构造函数 prototype 属性与对象的 proto 属性指向的是同一个对象
__proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype
2.2 constructor构造函数
对象原型( proto)和构造函数(prototype)原型对象里面都有一个属性 constructor 属性 ,constructor 我们称为构造函数,因为它指回构造函数本身。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function Car(brand){
this.brand=brand
}
Car.prototype={
//原型对象重新赋值
constructor:Car,
drive:function(){
console.log("drive");
},
start:function(){
console.log("start");
},
stop:function(){
console.log("stop");
},
run:function(){
console.log("run");
}
}
console.log(Car.prototype)
var c1 = new Car()
c1.drive()
</script>
</body>
</html>
constructor 主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
2.4构造函数实例和原型对象三角关系
- 构造函数的prototype属性指向了构造函数原型对象
- 实例对象是由构造函数创建的,实例对象的__proto__属性指向了构造函数的原型对象
- 构造函数的原型对象的constructor属性指向了构造函数
2.6原型对象中this指向
构造函数中的this和原型对象的this,都指向我们new出来的实例对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
/**
* 1)在构造函数中,this指代的是创建的构造函数的对象实例
* 2)在构造函数的原型对象中,this同样指代的是创建的构造函数的对象实例
*/
function Car(bran){
this.brand=bran
console.log(this);
}
Car.prototype.run=function(){
console.log(this);
}
var c1=new Car("MAD")
var c2=new Car("PHP")
c1.run()
c2.run()
</script>
</body>
</html>
call方法调用:
- call 可以调用函数
- call 可以修改this的指向,使用call()的时候 参数一是修改后的this指向,参数2,参数3…使用逗号隔开连接
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function Person(name,sex,add){
this.name=name
this.sex=sex
this.add=add
}
function Chinese(name,sex,add,hukou){
Person.call(this,name,sex,add) //调用继承Person的指向对象
this.hukou=hukou
}
var c1=new Chinese('ms','nan',18,'beijing')
console.log(c1)
</script>
</body>
</html>
1.1.proto_和prototype的区别:
prototype属性是一个静态属性,
_proto_属性是一个实例属性。
prototype表示类的原型对象,_proto_表示原型对象中定义的内部属性[prototype]的值。
类的每一个实例都有一个_proto_属性,用于引用创建它的构造方法的prototype属性,也就是该类的原型对象,即存在如下等式:(new Array(“abc”)).proto===Array.prototype (Array(“abc”)为Array的实例)
实例化对象的原型链和构造函数的原型链
易错点:
(1)p1是手动创建的,没有constructor属性,p1.constructor是访问的Person.prototype上的constructor属性;
(2)Function是自己创建的自己,Function.constructor指向自己;
(3)Object对象是Function创建的;
(4)每个构造函数、普通函数和Function都有自己的prototype属性;
(5)Function.proto指向Object.prototype,Object.prototype的proto指向null
关于protohe prototype的几个概念
- 构造函数有一个原型对象,通过 prototype 获取
- 基于构造函数创建对象后,每个对象都有一个私有的 proto 属性,指向兑现的构造函数的原型对象
- 基于上面两点,构造函数 prototype 属性与对象的 proto 属性指向的是同一个对象
__proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype
call方法调用:
- call 可以调用函数
- call 可以修改this的指向,使用call()的时候 参数一是修改后的this指向,参数2,参数3…使用逗号隔开连接
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function Person(name,sex,add){
this.name=name
this.sex=sex
this.add=add
}
function Chinese(name,sex,add,hukou){
Person.call(this,name,sex,add) //调用继承Person的指向对象
this.hukou=hukou
}
var c1=new Chinese('ms','nan',18,'beijing')
console.log(c1)
</script>
</body>
</html>
4.1数组方法foreach遍历数组
arr.forEach(function(value, index, array) {
//参数一是:数组元素
//参数二是:数组元素的索引
//参数三是:当前的数组
})
//相当于数组遍历的 for循环 没有返回值
4.2数组方法filter过滤数组
<script>
var arr = [21, 38, 13, 50, 13, 17];
var newArr = arr.filter(function(value, index,array) {
//参数一是:数组元素
//参数二是:数组元素的索引
//参数三是:当前的数组
return value >= 20;
});
console.log(newArr);//[66,88] //返回值是一个新数组
</script>
4.3数组方法some
some 查找数组中是否有满足条件的元素
var arr = [10, 30, 4];
var flag = arr.some(function(value,index,array) {
//参数一是:数组元素
//参数二是:数组元素的索引
//参数三是:当前的数组
return value < 3;
});
console.log(flag);//false返回值是布尔值,只要查找到满足条件的一个元素就立马终止循环
4.4筛选商品案例
1.定义数组对象
var data = [{
id: 1,
title: '小米',
price: 3999
}, {
id: 2,
title: 'oppo',
price: 999
}, {
id: 3,
title: '荣耀',
price: 1299
}, {
id: 4,
title: '华为',
price: 1999
}, {
id: 5,
title: '小米',
price: 3999
}, {
id: 6,
title: 'oppo',
price: 999
}, {
id: 7,
title: '荣耀',
price: 1299
}, {
id: 8,
title: '华为',
price: 1999
},];
2.使用forEach遍历数据并渲染到页面中
function setData(pro_data) {
document.querySelector('tbody').innerHTML=''
pro_data.forEach(function (item) {
var tr = `
<tr>
<td>${item.id}</td>
<td>${item.title}</td>
<td>${item.price}</td>
</tr>
`
document.querySelector('tbody').insertAdjacentHTML('beforeend', tr)
})
}
根据价格筛选数据
- 获取到搜索按钮并为其绑定点击事件
/** 商品筛选功能
* 1)页面加载时加载所有商品
* 2)用户输入了哪些数据,就按照这些条件进行筛选
*
*/
var btn_filter = document.querySelector('#btn_filter')
var start_price = document.querySelector('#start_price')
var end_price = document.querySelector('#end_price')
var title = document.querySelector('#title')
3.筛选信息
btn_filter.addEventListener('click', function () {
var newData = data.filter(function (item) {
var new_start_price = start_price.value != '' ? start_price.value : 0
var new_end_price = end_price.value != '' ? end_price.value : Infinity
var new_title = title.value != '' ? title.value : item.title
return item.price >= new_start_price && item.price <= new_end_price && item.title == new_title
})
console.log(newData);
setData(newData)
})
5.项目演示:
4.5 some和forEach区别
- 如果查询数组中唯一的元素, 用some方法更合适,在some 里面 遇到 return true 就是终止遍历 迭代效率更高
- 在forEach 里面 return 不会终止迭代
some和filter和foreach之间的关系:
- filter():返回一个符合func条件的元素数组。筛选条件,把数组符合条件的放在新的数组里面返回。新数组和原来的数组长度不一定一样。
- some():返回一个boolean,判断是否有元素是否符合func条件。数组里面所有的元素有一个符合条件就返回true。
- every():返回一个boolean,判断每个元素是否符合func条件。数组里面所有的元素都符合才返回true。
- forEach():没有返回值,只是针对每个元素调用func 。循环数组。和for的用法一样的。
4.6 模拟一个String字符串的trim方法,去除字符串两端的空格。
var str = ' hello '
console.log(str.trim()) //hello 去除两端空格
var str1 = ' he l l o '
console.log(str.trim()) //he l l o 去除两端空格
4.7 获取对象的属性名
- 字面量方式创建对象
var person = {
name: '李白',
age: 20,
gender: '男',
address: '北京'
}
var result = Object.keys(person)
console.log(result);
- 构造函数创建对象
function Person(name,age){
this.name=name
this.age=age
}
var person = new Person('杜甫', 18)
var result = Object.keys(person)
console.log(result);
- 根据类创建对象
class Person {
constructor(name, age,gender) {
this.name = name
this.age = age
this.gender=gender
}
}
var person = new Person('杜甫', 18,'女')
var result = Object.keys(person)
console.log(result);
4.8 Object.defineProperty
const object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42,
writable: false
});
object1.property1 = 77;
// throws an error in strict mode
console.log(object1.property1);
// expected output: 42
语法:
Object.defineProperty(obj,prop,descriptor)
- obj:定义属性的对象。
- prop:要定义或修改的属性的名称或 symbol 。
- descriptor:要定义或修改的属性描述符
- 返回值:被传递给函数的对象
- 数据描述符:主要用来描述属性的值、是否可以枚举、是否可以更改属性的值、是否可以删除属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
'use strict'
var obj = {}
// obj.name='yhb'
// console.log(obj);
Object.defineProperty(obj, 'age', {
value: '18',
configurable: true, // 属性可以删除
writable: true, // 属性的值可以更改
enumerable: true // 属性可以被枚举出来
})
console.log(obj);
// 修改属性的值
obj.age = 20
console.log(obj);
console.log(Object.keys(obj));
// delete obj.age // 从 obj 对象中删除 age 属性
// console.log(obj);
Object.defineProperty(obj, 'gender', {
get: function () {
return 'hello'
},
set: function (newValue) {
console.log(newValue);
}
})
console.log(obj.gender);
obj.gender='女'
</script>
</body>
</html>
这两种描述符都是对象。它们共享以下可选键值(默认值是指在使用 Object.defineProperty()
定义属性时的默认值):
-
configurable
当且仅当该属性的
configurable
键值为true
时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。 默认为false
。 -
enumerable
当且仅当该属性的
enumerable
键值为true
时,该属性才会出现在对象的枚举属性中。 默认为false
。
数据描述符还具有以下可选键值:
-
value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。 默认为 undefined。
-
writable
当且仅当该属性的
writable
键值为true
时,属性的值,也就是上面的value
,才能被赋值运算符改变。 默认为false
。
单击绑定案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<p>{{title}}</p>
</div>
<button>修改</button>
<script src="/vue.js"></script>
<script>
obj.title='添加'
document.querySelector('button').addEventListener('click',function(){
obj.title='显示'
})
</script>
</body>
</html>
var obj = {}
var nodes = document.querySelector('#app').children
var title_node = null
console.log(nodes);
Array.from(nodes).forEach(function (item) {
if (item.innerHTML == '{{title}}') {
title_node = item
}
})
Object.defineProperty(obj, 'title', {
set: function (newValue) {
title_node.innerHTML = newValue
}
})