Object 对象
JavaScript 的设计是一个简单的基于对象的范式。一个对象就是一系列属性的集合,一个属性包含一个名和一个值。一个属性的值可以是函数,这种情况下属性也被称为方法。除了浏览器里面预定义的那些对象之外,你也可以定义你自己的对象。
在javascript中,一个对象可以是一个单独的拥有属性和类型的实体。我们拿它和一个杯子做下类比。一个杯子是一个对象(物体) ,拥有属性。杯子有颜色,图案,重量,由什么材质构成等等。同样,javascript对象也有属性来定义它的特征。
Object 是 JavaScript 的一种 数据类型 。它用于存储各种键值集合和更复杂的实体。Objects
可以通过 new Object()
Object.create()
方法,或者使用 对象字面量 的方式创建
对象和属性
一个 javascript 对象有很多属性。一个对象的属性可以被解释成一个附加到对象上的变量。对象的属性和普通的 javascript 变量基本没什么区别,仅仅是属性属于某个对象。
- 属性:事物的特征,在对象中用属性来表示(常用名词)
- 方法:属性的行为,在对象中用方法来表示(常用动词)
创建对象
let obj = new Object();
let obj = Object();
let obj = {};
function Car() {
}
let c = new Car()
定义方法
对象的属性值可以是任意类型,也可以是一个函数.如果对象的属性值是一个函数,这个函数我们称为是对象的方法.调用函数称为调用对象的方法.
一个方法 是关联到某个对象的函数,或者简单地说,一个方法是一个值为某个函数的对象属性。定义方法就像定义普通的函数,除了它们必须被赋给对象的某个属性。
var myObj = {
myMethod: function (params) {
},
// 或者 这样写也可以
myOtherMethod(params) {
}
};
使用对象
const obj = {}
// 添加
obj.name = 'tom'
obj.age = 23
// 读取
console.log(obj.name)
console.log(obj["age"])
// 删除
delete obj.name
delete obj["age"]
工厂模式
function fun(cName) {
let obj = new Object()
obj.name = cName
return obj
}
let obj1 = fun('tom')
let obj2 = fun('jerry')
in
如果指定的属性在指定的对象或其原型链中,则 in
运算符返回true
。
let obj = {name: 'tom'}
console.log('name' in obj)
枚举一个对象的所有属性
从 ECMAScript 5 开始,有三种原生的方法用于列出或枚举对象的属性:
for...in
循环 该方法依次访问一个对象及其原型链中所有可枚举的属性。
for (variable in object) {
statement
}
Object.keys(o)
该方法返回对象o
自身包含(不包括原型中)的所有可枚举属性的名称的字符串数组。
Object.keys(obj)
Object.getOwnPropertyNames(o)
该方法返回对象o
自身包含(不包括原型中)的所有属性(无论是否可枚举)的名称的字符串数组。
Object.getOwnPropertyNames(obj)
原型和原型链
原型
每一个函数都有一个属性叫做prototype
(显式原型),该属性指向的是一个对象,这个对象就是原型对象
如果函数作为一个构造函数去调用,那么它所创建的实例中会有一个隐含的属性(__proto__
,隐式原型)指向函数的显式原型(prototype
)
实例的隐式原型__prpto__
指向函数的显示原型prototype
原型对象就相当于一个公共的区域,可以被所有的该类实例所共享。所有我们可以将实例中共有的属性统一存储到原型中,这样我们只需创建一个属性(方法),即可使所有实例拥有该属性(方法)
原型链
为什么设计原型:继承、让对象的属性和方法实现共享
函数:prototype
,对象:__ptoto__
原型链:每一个对象都有原型__proto__
,这个原型还有自己的原型,最终形成了原型链,原型链的最顶端是null
如果要查找对象的属性或方法,先在对象中查找,如果没有找到,去对象的原型中找,如果还没找到,去对象的原型的原型中去找,直到找不到,返回undefined
当访问一个对象的属性时,JS会首先在对象自身中寻找
- 如果找到了,则使用
- 如果没找到,则去对象的原型(
__proto__
)中寻找 - 如果找到了,则使用,没找到继续去原型的原型中寻找,以此类推
- 直到找到
Object
的原型,它是所有原型的原型,它的原型是null
- 如果找到
Object
的原型,依然没有则返回undefined
定义一个类时,如果属性和方法是对象独有的,就直接在构造函数中设置
如果属性和方法是公共的,每一个对象的值都是相同的,可以通过原型来添加
继承
原型链继承
儿子继承父亲Child.prototype = new Parent()
优点:共享属性和方法
缺点:无法给父构造函数传递参数
面试题
function Foo() {
getName = function () {
alert(1)
}
return this
}
Foo.getName = function () {
alert(2)
}
Foo.prototype.getName = function () {
alert(3)
}
var getName = function () {
alert(4)
}
function getName() {
alert(5)
}
// **优先级**:变量 > 函数 > 形参 > 变量提升
Foo.getName() // 2
getName() // 4
// 全局getName = function(){alert(1)}
Foo().getName() // 1
getName() // 1
new Foo().getName() // 3
构造函数继承
每次生成一个对象,对象本身的属性和方法不共享
优点:可以向父构造函数传递参数
缺点:不可以共享属性和方法
call/apply/bind
function Parent() {
this.name = 'tom'
this.arr = [1, 2, 3]
}
function Child() {
// 让Parent的this指向对象
Parent.call(this)
}
const obj1 = new Child()
const obj2 = new Child()
obj1.arr[0] = 10
console.log(obj1.arr) // [10, 2, 3]
console.log(obj2.arr) // [1, 2, 3]
组合继承
原型链继承+借用构造函数继承
既可以传递参数,也可以实现该有的共享性
function Parent(name) {
this.name = name
this.arr = [1, 2, 3]
}
function Child(name) {
// 借用构造函数
Parent.call(this, name)
}
Parent.prototype.run = function () {
}
// 原型
Child.prototype = new Parent()
const obj1 = new Child('张三')
const obj2 = new Child('李四')
obj1.arr[0] = 10
console.log(obj1)
console.log(obj2)
console.log(obj1.run === obj2.run)
JS作用域
作用域
作用的区域或者作用范围,JS没有块级作用域,只有函数作用域
全局作用域:在全局作用域下写的变量:没有区别,都属于window对象的属性
局部作用域:在局部作用域写变量
作用域链
从当前作用域逐级向上查找
从当前作用域开始找,找不到向外继续找,直到找到window,找不到报错
变量提升
JS会提升var声明的变量和函数,移动到当前作用域的开头
优先级:变量 > 函数 > 形参 > 变量提升
JS严格模式-递归-闭包
严格模式
use strict
开启严格模式
使用方式:
- 针对整个文件,全局严格模式:文件的第一行写:
'use strict'
- 针对单个函数,局部严格模式:函数的第一行写:
'use strict'
作用:
- 变量声明:var | window ,
num = 10
报错 - 禁止
this
关键字指向全局对象 - 函数不能有重名的形参
闭包
什么是闭包?
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围), 这样的组合就是闭包(closure)。 也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
闭包是一个函数加上到创建函数的作用域的连接,闭包“关闭”了函数的自由变量
- 有两个函数,作用域是连接关系(scope)
- 变量不自由,会停留在内存中,不会销毁
闭包可以做什么?无意间共享环境
new操作符具体做了什么?
- 创建一个对象
new Object()
- 原型赋值(指向同一个原型对象):
对象.__proto__ = Fun.prototype
- 改变this指向:
Fun.call(obj)