五、Js对象
-
对象为引用数据类型:若是直接赋值,相当于赋值该对象的地址
-
对象是通过new构造出来的,彼此之间都是不一样的
-
对象的key都是字符串类型
-
如何查找属性/方法:
- 每一个将函数自带一个原型(
prototype
) - 每一个对象拥有一个对象原型(
__proto__
) - new 对象:该对象构造函数的原型指向对象的原型
function fn() {} let obj = new fn() console.log(fn.prototype === obj.__proto__)
- 查找顺序:原型链
- 对象本身
- 构造函数
- 对象原型
- 构造函数原型
- 对象上一层原型
function fn(){ this.a = 'this.a' } // 2 fn.prototype.a = 'prototype.a' // 4 let obj = new fn() obj.a = 'obj.a' // 1 obj.__proto__.a = '__proto__.a' // 3 Object.prototype.a = 'Object.prototype.a' // 5 console.log(obj.a) // 顺序:obj、this、__proto__、prototype、Object
- 每一个将函数自带一个原型(
考题1:
var o = { b: 'bb' }
var obj = { a:1, 'zs': 'hey' }
obj[o] = '123' // obj = { a:1, 'zs': 'hey', [object Object] = '123' }
for (var k in obj) {
console.log(typeof k) // string
}
考题2:
var a = {}
var b = { k: 'b' }
var c = { k: 'c' }
a[b] = '123' // b将被转为字符串[object Object]
a[c] = '456' // c转为字符串并覆盖b,c与b都属于同一个key:[object Object]
console.log(a[b]) // 456
1、this指向
- 普通函数
-
普通函数:this指向window
function A() {console.log(this)} //window
-
普通函数闭包:this指向window
function A() { return function(){ console.log(this) }} //window
-
考题1:
-
返回什么?
-
是否执行函数体中的代码?
function fn(){
console.log('111')
console.log(this)
return 'aaa'
}
console.log(fn) // 打印函数体:function fn(){} -- 未执行
console.log(fn()) // 返回对象 -- 执行:this = window
console.log(new fn()) // 新对象fn{} -- 执行:this = fn{}
考题2:
// 声明:
function foo(){
getName = function(){ console.log(1) } // 全局window
return this
}
foo.getName = function(){ console.log(2) }
foo.prototype.getName = function(){ console.log(3) }
var getName = function() { console.log(4) }
function getName() { console.log(5) }
// 执行:
foo.getName() // 2 -- foo函数未执行,直接查找函数本身
getName() // 4 -- getName声明大于函数,若是变量提升就该输出5
foo().getName() //1 -- 执行foo函数,等于将this = window返回,相当于window.getName()
getName() // 1 -- 上一行的getName变成全局覆盖
new foo.getName() // 2 -- 根据对象原型链去查找(先看对象本身,再找原型),在foo函数中的getName是window的所以不采用
考题3:
var o = {
a: 10,
b: {
// a: 1, -- 若添加此行,下面的this.a = 1
fn: function(){
console.log(this) // b
console.log(this.a) // b.a = undefined
}
}
}
o.b.fn() // undefined
考题4:
name = 'ByteDance'
function A() { this.name = 123 }
A.prototype.getA = function () {
console.log(this)
return this.name + 1
}
let a = new A() // 对象
let fnA = a.getA // 未执行:this = window
console.log(fnA()) // ByteDance1
let fnB = a.getA() // 执行:this = a(A{name: 123})
console.log(fnB) // 124
考题5:
var len = 10
function fn(){ return this.len + 1 }
var obj = { len: 5, test1: function(){ return fn() } } // 执行:this指向window
obj.test2 = fn // 未执行 -- 相当于:obj.test2 = function(){return this.len+1}
console.log(obj.test1()) // 11
console.log(fn() === obj.test2()) // false:test2的this指向obj,而fn指向window
console.log(obj.test1() == obj.test2()) // false:同理
2、原型链
-
原型能解决的问题:对象共享属性、方法(继承机制)
- new 构造函数:而构造函数不能共享属性、方法,因此需要用到prototype
注意:js中new后面不是类名,而是构造函数
-
原型存在体:
-
函数原型(显式):
prototype
-
对象原型(隐式):
__proto__
proto 对比 prototype:proto是每个实例都有的属性(实例没有prototype),可以访问构造函数的prototype属性(proto与prototype指向的是同一个对象)
function Fn() {} console.log(Fn().prototype) //{constructor:f} console.log(new Fn().prototype) //undefined console.log(new Fn().__proto__) //{constructor:f}
-
-
原型链:原型都连接起来,原型链的最顶端是
null
原型链中对象查找属性/方法顺序:
-
对象本身查找
-
构造函数中查找
-
对象的原型
-
构造函数的原型中
-
当前原型的原型中查找
-