目录
- 1. 实现链式操作
- 2. 对象
- 2.1 通过[]访问属性名
- 2.2 对象枚举
- 2.2.1 遍历数组
- 2.2.2 遍历对象
- 2.3 hasOwnProperty
- 2.4 instanceof ⭐⭐
- 2.4.1 例子
- 2.4.2 判断是否是数组的4种方式
- 2.4.3 让 arr 调用 Object 上的 toString
- 2.5 Object.defineProperty
- 3. this
- 3.1 普通函数中的 this
- 3.2 构造函数中的 this
- 3.3 call, apply
- 3.4 总结
- 4. callee, caller
- 4.1 callee
- 4.2 caller
- 5. 面试题
1. 实现链式操作
每个函数return this
var sched = {
wakeup: function(){
console.log('Running');
return this;
},
morning: function(){
console.log('Go shopping');
return this;
},
noon: function(){
console.log('Having a rest');
return this;
},
afternoon: function(){
console.log('Studying');
return this;
},
evening: function(){
console.log('Walking');
return this;
},
night: function(){
console.log('Sleeping');
return this;
}
}
sched.wakeup().morning.().afternoon().evening().night();
2. 对象
2.1 通过[]访问属性名
[] 里面放字符串
var myLang = {
No1: 'HTML',
No2: 'CSS',
No3: 'JavaScript',
myStudingLang: function(num){
console.log(this[`No${num}`]);
}
}
myLang.myStudingLang(1);
最早的 JS 引擎 都是通过 obj[‘name’] 访问的,
后来有了 . 语法,实际上访问 obj.name ,内部隐式的转换为 obj[‘name’](chrome v8 引擎不一定是这么做的)
2.2 对象枚举
枚举:一组有共同特性的集合
JavaScript 的枚举实际上就是对象,有枚举就有遍历,是相辅相成的。
枚举 -> 遍历:在一组信息,按顺序一个一个的去获取其信息的过程
for-in 既可以遍历对象,也可以遍历数组
2.2.1 遍历数组
var arr = [1, 2, 3, 4, 5];
// 这个循环的过程就叫遍历的过程
// 方式1
for(var i = 0; i < arr.length; i++){
console.log(arr[i]);
}
// 方式2
for(var i in arr){
console.log(arr[i]);
}
2.2.2 遍历对象
var car = {
brand: '马自达', // key : value
color: 'white',
displacement: '2.0'
}
for(var key in car){
console.log(key + ': ' + car[key]);
// car.key 不行原因: car.key -> car['key'] -> undefined
console.log(car.key); // undefined
}
2.3 hasOwnProperty
功能:排除原型上的自定义属性
var obj = {
name: 'Tom',
age: 30
}
obj.hasOwnProperty('name') // true
例1
function Car(){
this.brand = '马自达';
this.color = 'white';
this.displacement = '2.0';
}
Car.prototype = {
lang: 5,
width: 2.5
}
Object.prototype.name = 'Object';
var car = new Car();
console.log(car);
for(var key in car){ // 原型链上的自定义属性也会被打印出来
// 找对象自身的属性,而不找原型上的所有属性
if(car.hasOwnProperty(key)){
console.log(key + ': ' + car[key]);
}
}
var car = {
brand: '马自达',
color: 'white',
}
// 隐式的在找 car['displacement']
console.log('displacement' in car); // false
hasOwnProperty 是排除原型的,但是 in 是不排除的
function Car(){
this.brand = '马自达';
this.color = 'white';
this.displacement = '2.0';
}
Car.prototype = {
displacement: '3.0'
}
var car = new Car();
console.log('displacement' in car); // true
2.4 instanceof ⭐⭐
判断对象是否是该构造函数实例化出来的
A 对象的原型里到底有没有B构造函数的原型,在原型链上,只要B实例化出来的对象,它的原型和A对象原型链上重合的都是true
2.4.1 例子
function Car(){}
var car = new Car();
function Person(){}
var p = new Person();
console.log(car instanceof Car); // true
console.log(p instanceof Car); // false
console.log(car instanceof Object); // true
console.log([] instanceof Array); // true
console.log([] instanceof Object); // true
console.log({} instanceof Object); // true
2.4.2 判断是否是数组的4种方式
var a = [];
// 1.
console.log(a.constructor);
// 2.
console.log(a instanceof Array);
// 3.
var str = Object.prototype.toString, // 缓存方法
trueTip = '[object Array]';
str.call(a) === trueTip; // call 更改 this 指向
console.log(str); // [object Array]
分析:
Object.prototype = {
toString: function(){
this.toString(); // call(a) 就相当于 a.toString
}
}
// 4.
Array.isArray(a); // true
2.4.3 让 arr 调用 Object 上的 toString
var arr = new Array(1, 2, 3);
console.log(arr); // [1, 2, 3]
console.log(arr.toString()); // 1, 2, 3
// 让 arr 调用 Object 上的 toString
Object.prototype.toString.call(arr); // [object Array]
2.5 Object.defineProperty
实现下面条件,打印内容⭐
if(a == 1 && a == 2 && a == 3) {
console.log('You win!!');
}
答:相等性判断 会经过 toString
// 方法1
var a = {
_a: 0,
toString() {
return ++this._a;
}
};
if(a == 1 && a == 2 && a == 3) {
console.log('You win!!');
}
变形:
// get set -> getter setter
// window -> a
var _a = 0;
Object.defineProperty(window, 'a', {
get(){
return ++_a;
}
})
if(a === 1 && a === 2 && a === 3) {
console.log('You win!!');
}
变形:
var obj = {
_a: 0,
get a(){ // 语法糖
return ++this._a
}
}
// 或者
var obj = {
_a: 0
}
Object.defineProperty(obj, 'a', {
get(){
return ++obj._a;
}
})
if(obj.a === 1 && obj.a === 2 && obj.a === 3) {
console.log('You win!!');
}
3. this
3.1 普通函数中的 this
- 在普通函数中,只要没有实例化这个函数, this 是默认指向 window 的;
- this 在全局范围内也是指向 window 的
// 函数内部的 this
function test(b) {
this.d = 3; // 相当于 window.d = 3,相当于直接 d = 3
var a = 1;
function c(){}
}
test(123);
console.log(d); // == this.d == window.d
分析:
AO = {
arguments: [123], // 形参和实参一一对应的时候会存进 arugments 中
this: window, // 预编译的时候 this 默认指向 window
b: undefined -> 123,
a: undefined,
c: function c(){}
}
1. 在普通函数中,只要没有实例化这个函数, this 是默认指向 window 的;
2. this 在全局范围内也是指向 window 的
3.2 构造函数中的 this
构造函数的 AO,GO
function Test(){
// var this = {
// __proto__: Test.prototype
// }
this.name = '123';
}
var test = new Test();
分析:
AO = {
this: window ->
{ // 实例化的时候被覆盖了
name: '123',
__proto__: Test.prototype,
}, // 这就形成了原型链
}
GO = {
Test: function Test(){...},
test: {
name: '123',
__proto__: Test.prototype,
}
}
3.3 call, apply
function Person(){
this.name = 'Tom';
this.age = 18;
}
function Programmer(){
Person.apply(this);
this.work = 'Programming';
}
var p = new Programmer();
console.log(p);
3.4 总结
- 全局 this -> window
- 预编译函数 this -> window
- apply,call 改变 this 指向
- 构造函数的 this 指向实例化对象
4. callee, caller
4.1 callee
arguments.callee 实参列表当中的一个属性
function test(a, b, c){
// 打印的是正在被执行的函数对象
console.log(arguments.callee); // arguments 实参所指向的函数是谁,就打印谁
// 通过 arguments.callee 找到对应的函数,然后再打印它的长度,
// 相当于打印 test.length
console.log(arguments.callee.length);
console.log(test.length); // 形参的长度
console.log(arguments.length); // 实参的长度
}
test(1, 2, 3)
arguments.callee 在哪个函数就指向哪个函数
function test1(){
// arguments.callee 在哪个函数就指向哪个函数
console.log(arguments.callee);
function test2(){
console.log(arguments.callee);
}
test2()
}
test1();
例子:用递归的方式累加 n 位数
function sum(n) {
if(n <= 1) {
return 1;
}
return n + sum(n - 1);
}
var res = sum(10);
console.log(res);
// 用立即执行函数实现
var sum = (function(n){
if(n <= 1) {
return 1;
}
return n + arguments.callee(n - 1);
})(10);
console.log(sum);
4.2 caller
'use scrict';
test1();
function test1(){
test2();
}
function test2(){
// 返回当前被调用函数的函数引用
console.log(test2.caller); // 调用当前函数的函数引用
}
5. 面试题
- 打印结果是什么
function foo(){
// 传 null ,没有改变 this 指向
bar.apply(null, arguments); // 相当于执行 bar(arguments)
}
function bar(){
console.log(arguments);
}
foo(1, 2, 3, 4, 5);
// [1, 2, 3, 4, 5]
所有的函数执行都有一个 call ,
如bar() -> bar.call(arugments)-> bar(arguments)
- JS 的 typeof 可能返回的值有哪些?
七种
object, boolean, string, number, undefined, function, symbol
注意: typeof(null) = object
- 执行结果是什么?
function b(x, y, a){
arguments[2] = 10;
alert(a); // 10
}
b(1, 2, 3);
function b(x, y, a){
a = 10;
alert(arguments[2]); // 10
}
b(1, 2, 3);
实参和形参是映射关系,一一对应
- 打印结果?
var f = (
function f() {
return 1;
},
function g() {
return 2;
}
)
console.log(typeof f); // function g(){..}
var f = (
function f() {
return 1;
},
function g() {
return 2;
}
)()
console.log(typeof f); // 'number'
- 结果
undefined == null; // true
undefined === null; // false
isNaN('100'); // false
parseInt('1a') == 1; // true
- 打印结果
function isNaN1(num){
var res = Number(num);
// NaN 不等于任何东西,包括它本身
if(res == NaN){
return true;
} else {
return false
}
}
console.log(isNaN1('abc')) // false
// ----- 改写 -----
function isNaN1(num){
var res = Number(num) + '';
// NaN 不等于任何东西,包括它本身
if(res == 'NaN'){
return true;
} else {
return false
}
}
console.log(isNaN1('abc')) // true
- 执行结果:{} == {},是否相等,为什么,怎么做?⭐
{} == {}; // false ⭐
因为引用值对比的是地址,两个空对象保存在不同的地址中
修改:
先声明一个对象,再把这个对象赋值给新对象,这个时候它们就相等了
var obj = {};
var obj1 = obj;
obj == obj1;
- 打印结果是什么?
var a = '1';
function test(){
var a = '2';
this.a = '3';
console.log(a);
}
test(); // '2'
new test(); // '2'
console.log(a); // '3'
AO = {
a: undefined -> '2',
this: -> window
-> {
a: 3,
__proto__: test.prototype
}
}
GO = {
a: undefined -> 1 -> 3,
}
- 打印结果是什么?
var a = 5;
function test(){
a = 0;
console.log(a);
console.log(this.a);
var a;
console.log(a);
}
test(); // 0 5 0
new test(); // 0 undefined 0