闭包高级、对象、构造函数、实例化
(1) 对象
1. 添加
// 1.添加属性
teacher.address = “北京”
// 2. 添加方法
teacher.drink = function(){
console.log(“I am drinking beer”)
}
2. 查找
// 1. 属性查找
teacher.name
// 2. 方法查找
teacher.teach()
3. 删除
// 删除属性
delete teacher.address
// 删除方法
delete teacher.teach
(2) 创建对象方法
1. var obj = new Object();
2. var obj = {}
3. 自定义构造函数
(3) 构造函数
1. 大驼峰与普通函数表面上的区别
2. 只有 new 了构造函数之后才会有实例 在没有执行之前就不存在this,
3. this 指向的是对象
4. 通过一个构造函数实例化出来的两个对象之间没有关系,是完全不同的两个对象
# 构造函数及实例化原理、包装类
(1) 构造函数及实例化原理
1. this
this 没有执行 讨论 this没有意义
this 在函数执行的时候指向 window
没有实例化的时候指向window
当 实例化的时候 this指向 被实例化出来的对象
2. 构造函数实例化过程
// 1)当构造函数被实例化的时候,相当于函数被执行了,会产生AO,会自动先保存一个this对
象(不是空对象)
// 2)new 的时候相当于函数跑完了, function Car(color,brand){ // this = { // //因为this指向实例,所以在外界可
以通过实例进行访问,访问到this中的的属性 // color:color, // brand:brand // } // 3) 在 this中保存了this相对应
的的属性 this.color = color; this.brand = brand; // 构造函数实例化的时候隐式的返回一个引用值,this指向被实
例化出来的对象 //return this }
### (2) 包装类
1. 原始值(string, number, null ,undefined,boolean)没有自己的方法和属性
```js
var a = 123;//原始值
a.len = 3;
//包装类的步骤
//1.new Number(123).len = 3 ;// 将数值通过new Number 转换成数字对象,给这个对象创建一
个len属性 赋值为 3
//2.delete new Number(123).len;//
console.log(a.len);//undefined
// 内置的三种构造函数
new Number() //转换成数字对象
new String() //转换成字符串对象
new Boolean()//转换成布尔对象
# 原型、原型链、闭包立即执行函数、插件开发
(1) 原型 prototype
1. 原型 prototype 其实是 function对象的一个属性,打印出来也是对象
2. 原型 prototype 是定义 构造函数 构造出来的 每个对象的公共祖先
3. 所有被该构造函数构造出来的对象都可以继承原型 prototype 上的属性和方法
4. 自己 this 上有的属性和方法是不会往原型上去查找
5. 当需要参数进行传值的时候一般写在 this中,写死的属性和方法写在原型 prototype上 // 经验
6. 原型中有个默认有个 constructor构造器,指向构造函数本身
function Handphone(color, brand, system){
this.color = color;
this.brand = brand;
this.system = system;
}
Handphone.prototype = {
rom: “64G”,
ram: ‘6G’,
screen: ‘18:9’,
call: function(){
console.log(‘I am calling somebody’)
}
}
var hp1 = new Handphone()
console.log(hp1);// -> 指向一个对象
7. constructor 原型上的 constructor 指向构造函数本身 constructor 是可以通过 Handphone.constructor 进
行修改的
8. proto
proto 属于每一个实例化对象
每个实例化对象的原型的容器,通过proto访问 prototype
9. 当构造函数被实例化new的时候,产生了this 对象,this对象中默认有一个 proto 里面装了原型
prototype
(2) 插件开发
;(function(){
语句
})()
# 原型与原型链深入、对象继承
(1) 原型链
1. 所有的对象都有原型,包括原型本身
2. 沿着proto 往上去找原型上相应的属性,一层一层的往上去继承原型的属性的链条叫做原型链
3. 原型链的顶端是Object的原型
Professor.prototype.tSkill = ‘JAVA’;
function Professor(){}
var professor = new Professor();
// var professor = {proto:Profressor.prototype}
Teacher.prototype = professor;//{proto:Profressor.prototype}
function Teacher(){
this.mSkill = ‘js/jq’;
this.success = {
alibaba:’28’,
tencent:’30’
}
}
var teacher = new Teacher();
// var teacher = {proto:{proto:Profressor.prototype},mkill:’js/jq’}
Student.prototype = teacher;
function Student(){
this.Skill = ‘html’;
}
var student = new Student();
console.log(student.success)
4. 原型链上的增删改原始值只能修改改自己,引用值可以修改但不推荐
Professor.prototype.tSkill = ‘JAVA’;
function Professor(){}
var professor = new Professor();
// var professor = {proto:Profressor.prototype}
Teacher.prototype = professor;//{proto:Profressor.prototype}学
function Teacher(){
this.mSkill = ‘js/jq’;
this.students = 500
}
var teacher = new Teacher();
// var teacher = {proto:{proto:Profressor.prototype},mkill:’js/jq’}
Student.prototype = teacher;
function Student(){
this.Skill = ‘html’;
}
var student = new Student();
student.students += 1;//-> 不会修改原型链上的原始值,会在自己的属性上新建一个值,并
附上计算后的属性
console.log(student, teacher)
(2) 对象继承
1. 声明对象
var obj1 = {}
var obj2 = new Object()// 公司不用这个
使用自定义构造函数,原型是构造函数的原型,构造器指向自定义的构造函数
Object.create(对象或者null),创建对象,自定义原型的功能
2. 不是所有的对象都继承与Object.prototype 如var obj1 = Object.create(null);
# 继承深入、call_apply、圣杯模式、模块化
(1) 继承
function Teacher(){
this.name = ‘Mr.Li’;
this.tSkill = ‘JAVA’;
}
Teacher.prototype = {
pSkill:’js/jq’,
success : {
name:1,
}
}
var t = new Teacher;
function Student(){
this.name = ‘Mr.Wang’
}
Student.prototpye = Teacher.prototype;
// 公共原型
// 这样的继承使得两个原型的指向是同一个地址,一个修改原始值另一也会修改
var s = new Student();
(2) 解决继承(圣杯模式)
1. 定义一个缓冲构造函数
2. 将要Teacher.prototype赋值给缓冲的原型
3. 实例化缓冲实例对象
4. 将实例化的缓冲对象赋值给Student.prototype
var inherit = (function test(){
var Buffer = function(){};
return function(Target, Origin){
Buffer.prototype = Origin.prototype;
Target.prototype = new Buffer();
Target.prototype.constructor = Target;
Target.prototype.super_class = Origin;
}
})()
Teacher.prototype.name = “Mr.Zhang”
function Teacher(){}
function Student(){}
inherit(Student, Teacher);
var t = new Teacher();
var s = new Student();
console.log(t, s)
(2) call_apply
1. 改变this的指向
function Car(brand, color){
this.brand = brand;
this.color = color;
}
var newcar = {};
// Car.call(newcar,’Banz’,’red’)
Car.apply(newcar,[‘Banz’,’red’])
console.log(newcar)
# 对象属性遍历、this、caller_callee
(1) 对象枚举 -> 遍历
var arr = [1, 2, 3, 4, 5, 6]
// 循环一个数组 就是遍历一个数组
for (var i = 0; i < arr.length; i++){
console.log(arr[i]);
}
var car = {
brand: ‘Benz’,
color: ‘red’,
displacement: ‘3.0’,
lang: ‘3’,
width: ‘5’
}
// for…in 既可以遍历对象也可以遍历数组
for (var key in car){
console.log(key)
console.log(key + ‘:’ + car[key])
// javascript 内置的系统 先将 car.key -> car[‘key’]
}
var arr = [1, 2, 3, 4, 5, 6];
for (var i in arr){
console.log(arr[i])
}
(2) 对象.hasOwnProperty(属性名) 排除原型上自定义的属性
function Car(){
this.brand = ‘Benz’,
this.color = ‘red’,
this.displacement = ‘3.0’
}
Car.prototype = {
lang:5,
width:2.5,
}
Object.prototype.name = ‘Object’
var car = new Car();
console.log(car);
for (var key in car){
// console.log(key + ‘:’ + car[key])// for in 在原型链上所有自己定义原型的属性会
全部被打印出来
if(car.hasOwnProperty(key)){ // 使用car.hasOwnProperty 去掉原型链上自定义的属性
console.log(key + ‘:’ + car[key])
}
}
(3) 三种判断数组的方法
1. console.log(a.constructor);
2. console.log(a instanceof Array);
3. console.log(Object.prototype.toString.call(a));
(4) this 的指向
1. 全局的 this 指向 window
2. 预编译的时候 this 指向 window
3. 构造函数实例化的时候 this 指向被实例化出来的对象
4. call/apply 更改 this 的指向
(5) callee/caller
function test(a, b, c){
console.log(arguments.callee.length)
}
test(1, 2, 3)
// arguments.callee 执行到这一句的时候,返回正在被执行的函数对象
// caller 返回的是当前被调用函数的函数引用
#三目运算、对象克隆、浅拷贝、深拷贝
(1) 三目运算
格式
条件 ? 满足条件后执行的语句 // 直接自带 return
: 不满足条件后执行的语句
(2) 浅拷贝
浅拷贝就是将对象中的所有元素复制到新的对象中
浅拷贝对于原始值类型与引用类型的方式有区别
原始值类型字段的值被复制到副本中后,在副本中的修改不会影响源对象对应的值
引用类型的字段被复制到副本中的却是引用类型的引用,而不是引用的对象
在副本中对子元素引用类型的字段值被修改后,源对象的值也将被修改。
var person2 = {};
console.log(person2)
for (var key in person1){
person2[key] = person1[key];
}
person2.name = ‘李四’;
console.log(person1, person2)
(3) 深拷贝
深拷贝也同样是将对象中的所有字段复制到副本对象中
对于子元素的引用类型也是创建并复制
在副本中对子元素引用类型的字段值被修改后,源对象的值不会被修改。
function deep(origin, target){
var toStr = Object.prototype.toString,
arrType = ‘[object Array]’,
target = target || {}; // 防止用户没有传 target
for(var key in origin){ // 循环需要被拷贝的对象
if(origin.hasOwnProperty(key)){ // 判断属性是不是被拷贝对象自身的属性, 剔除
prototype上的属性
if(typeof(origin[key]) === ‘object’ && origin[key] !== null){ // 判断被拷贝对
象的值是不是一个引用值,需要排除null
if(toStr.call(origin[key]) === arrType){ // 判断被拷贝对象的值是不是一个数组
target[key] = [] // 如果是数组 将目标对象的值设为空数组
}else{
target[key] = {}// 如果是对象 将目标对象的值设为空对象
}
deep(origin[key], target[key]);// 递归调用本身
}else{ // 被拷贝对象的值是原始值得时候直接进行拷贝 ,递归的出口
target[key] = origin[key];
}
}
}
return target; // 返回目标对象
}