跳到主要内容

对象属性遍历

练习

function Car(brand, color, displacement) {
this.brand = brand;
this.color = color;
this.displacement = displacement;
this.getInfo = function () {
return `排量为${this.displacement}${this.color}${this.brand}`;
};
}

function Person(options) {
Car.apply(this, [options.brand, options.color, options.displacement]);
this.name = options.name;
this.age = options.age;
this.introduce = function () {
console.log(`年龄${this.age}岁,${this.name}买了一辆${this.getInfo()}`);
};
}

const person = new Person({
brand: '奔驰',
color: '红色',
displacement: '3.0',
name: '张三',
age: '25',
});
person.introduce();
console.log(person);

链式操作

当方法返回当前对象 (this) 时,可以实现链式调用其他方法。在 JavaScript 中,对象作为引用值传递,因此每个方法返回对象的引用,使得类支持链式调用。

const schedule = {
wakeUp() {
console.log('起床');
return this;
},
morning() {
console.log('去购物');
return this;
},
noon() {
console.log('午休');
return this;
},
afternoon() {
console.log('学习');
return this;
},
evening() {
console.log('散步');
return this;
},
night() {
console.log('睡觉');
return this;
},
};

schedule.afternoon().morning().noon().night().evening();

拼接数字

JavaScript 引擎最初支持 obj['name'] 语法,后来点语法出现后,内部会隐式转换为 obj['name']

const myLanguages = {
No1: 'HTML',
No2: 'CSS',
No3: 'JavaScript',
getStudyingLanguage(num) {
console.log(this[`No${num}`]);
},
};
myLanguages.getStudyingLanguage(1);

const obj = {
name: '123',
};

console.log(obj['name']);

对象枚举

枚举是具有共同特性的数据集合,遍历是按顺序获取集合中每一项的过程。在 JavaScript 中,遍历和枚举紧密相关。

遍历数组

const array = [1, 2, 3, 4, 5];
for (let i = 0; i < array.length; i++) {
console.log(array[i]);
}
const array = [1, 2, 3, 4, 5];
for (const index in array) {
console.log(array[index]);
}

访问内部属性

const car = {
brand: '奔驰',
color: '红色',
displacement: '3.0',
};

for (const key in car) {
// 遍历对象的内部属性
console.log(key);
// 使用 car[key] 访问属性值
console.log(`${key}: ${car[key]}`);
}

打印原型链上的所有属性

function Car() {
this.brand = '品牌';
this.color = '红色';
this.displacement = '3.0';
}
Object.prototype.owner = '车主';
Car.prototype.language = 'JavaScript';
Car.prototype.width = 2.5;

const car = new Car();
for (const key in car) {
console.log(`${key}: ${car[key]}`);
}

hasOwnProperty

hasOwnProperty 方法用于判断对象自身是否具有指定属性,不会检查原型链上的属性。

const car = {
brand: '奔驰',
color: '红色',
displacement: '3.0',
};
Car.prototype.language = 'JavaScript';
Car.prototype.width = 2.5;

for (const key in car) {
if (car.hasOwnProperty(key)) {
console.log(`${key}: ${car[key]}`);
}
}

in 判断属性

in 运算符用于判断属性是否存在于对象中,包括原型链上的属性。

const car = {
brand: '奔驰',
color: '红色',
};

console.log('color' in car); // true

function Car() {
this.brand = '奔驰';
this.color = '红色';
}
Car.prototype.displacement = '3.0';

const myCar = new Car();

console.log('displacement' in myCar); // true

instanceof

instanceof 用于判断对象是否由特定构造函数创建。

function Car() {}
const car = new Car();

function Person() {}
const person = new Person();

console.log(car instanceof Car); // true
console.log(person instanceof Car); // false
console.log(person instanceof Object); // true
console.log([] instanceof Array); // true
console.log([] instanceof Object); // true
console.log({} instanceof Object); // true

使用 toString() 检测对象类型

const array = [];
console.log(array instanceof Array); // true

const toString = Object.prototype.toString;
const arrayTag = '[object Array]';

if (toString.call(array) === arrayTag) {
console.log('是数组');
} else {
console.log('不是数组');
}

this

this 的指向根据函数的调用方式不同而不同。

  1. 普通函数:全局的 this 指向 window
  2. 预编译函数:this 指向 window
  3. call/apply:可以改变 this 的指向。
  4. 构造函数:this 指向实例化后的对象。
  5. this 在执行期决定指向,不稳定。
  6. 箭头函数:this 指向父环境的 this,较为稳定。

普通函数内部的 this

function test() {
this.d = 3;
var a = 1;

function inner() {}
}
test();

// 全局变量 d 被赋值为 3
console.log(d); // 3
console.log(this.d); // 3
console.log(window.d); // 3

构造函数的 this

function Test() {
this.name = '张三';
}
const instance = new Test();

console.log(instance.name); // 张三

call/apply

function Person(name, age) {
this.name = name;
this.age = age;
}

function Programmer(name, age) {
Person.apply(this, [name, age]);
this.profession = '程序员';
}

const programmer = new Programmer('李四', 28);
console.log(programmer);

callee/caller

callee

arguments.callee 返回正在执行的函数对象。适用于递归调用。

function test(a, b, c) {
console.log(arguments.callee.length); // 3
console.log(test.length); // 3
console.log(arguments.length); // 实际传入参数个数
console.log(arguments.callee);
}
test(1, 2);

递归累加 n 位数

function sum(n) {
if (n <= 1) {
return 1;
}
return n + arguments.callee(n - 1);
}
const result = sum(10);
console.log(result); // 55

caller

caller 返回调用当前函数的函数引用。

function test1() {
test2();
}

function test2() {
console.log(test2.caller); // 输出 test1 函数
}

test1();

严格模式下的 caller

在严格模式下,callercallee 不可用。

'use strict';
function test1() {
test2();
}
test1();

function test2() {
console.log(test2.caller); // TypeError
}

练习题

arguments

function foo() {
bar.apply(null, arguments);
}

function bar() {
console.log(arguments);
}
foo(1, 2, 3, 4, 5);
// 输出 Arguments(5) [1, 2, 3, 4, 5]

typeof 可能返回的值

typeof 运算符可能返回以下值:

  • "object"(包括 null
  • "boolean"
  • "number"
  • "string"
  • "undefined"
  • "function"
const f =
(function () {
return '1';
},
function () {
return 2;
});
console.log(typeof f); // "function"
const f = (function () {
return '1';
},
function () {
return 2;
})();
console.log(typeof f); // "number"

形参和实参的映射关系

形参与实参之间存在映射关系,修改形参会影响 arguments 对象。

function example(x, y, a) {
a = 10;
console.log(arguments[2]);
}
example(1, 2, 3); // 输出 10

比较

console.log(undefined == null); // true
console.log(undefined === null); // false
console.log(isNaN('100')); // false
console.log(isNaN('abc')); // true
console.log(parseInt('1') == 1); // true
console.log(parseInt('1abc') == 1); // true

isNaN 的实现原理

function isNaNCustom(value) {
const result = Number(value);
return result !== result;
}

console.log(isNaNCustom('abc')); // true
console.log(NaN === NaN); // false

空对象比较

console.log({} == {}); // false

const obj = {};
const obj1 = obj;
console.log(obj1 === obj); // true

全局和局部作用域

var a = '1';

function test() {
var a = '2';
this.a = 3;
console.log(a);
}
test(); // 输出 '2'
new test(); // 输出 '2'
console.log(a); // 输出 '3'

var b = '5';

function testScope() {
var b = '0';
console.log(b); // 0
console.log(this.b); // 5
}