一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情。
编程语言
- 面向对象 OOP( java js php c++ 等等)
- 面向过程 POP (c)
面向对象编程
面向对象编程主要包括三大类
- 对象:万物皆对象(泛指)
- 类:对“对象”的划分(按照其功能结构特点划分 比如 人可以分为 男人和女人)
- 实例:类中的具体事物
JS 本身是基于面向对象开发出来的编程语言,所以我们使用 JS 的时候要有面向对象的思维方式处理问题
-
内置类
-
每一种数据类型都有一个所属的内置类:Number(每个数字,NaN 都是它的实例) Sting/Boolean / Array 等等。。。。
-
每一种 DOM 元素也有自己所属的类
window -> Window -> WindowProperties -> EventTarget -> Object
document -> HTMLDocument -> Document -> Node -> EventTarget -> Object
.......
学习数组,首先分析一个数组(实例),研究清楚这个实例特征后(结构特点以及常用方法),再遇到其他数组,也按照相同的机制处理
-
-
自定义类
创建一个函数 fn
- fn() 普通函数执行(堆栈机制)
- new fn() 构造函数(堆栈机制 + 面向对象机制)
// 分析一下自定义类的机制过程
function Fn(x, y) {
let total = x + y;
this.x = x;
this.y = y;
}
let result = new Fn(10, 20);
console.log(result);
new 函数(): 构造函数执行,和普通函数的区别
- 相似点
- 一样是把函数执行(传递参数也一样)
- 形成私有上下文
- 变量提升
- 不同点
- new 执行,浏览器会在当前上下文中,默认创建一个对象(实例对象)
- 在初始化this的时候,this执行这个实例
- 代码中编写 this.xxx = xxx 的操作,都是给实例对象设置私有属性
- 除了this.xxx = xxx 其余的操作全部和实例对象没有关系
- 函数如果没有返回值,或者返回值是基本类型,则默认返回创建的实例对象,如果返回的是引用类型,那么以返回的引用类型为主
构造函数执行(函数被称为类,返回结果被成为实例)
function Fn() {
/*
* EC(FN)
* 初始创建Fn找个类的一个实例对象 0x000
* 初始THIS:this->0x000
*/
let total = 0; //上下文的私有变量 和实例对象没有必然的联系
this.x = 10; //this.xxx=xxx 都是给实例对象设置的私有属性和方法
this.y = 20;
this.say = function () { //0x000.say=0x100 0x001.say=0x101
console.log('SAY');
};
/* 如果不设置返回值,或者返回值是一个基本类型值,默认都会把实例对象 0x000 返回;如果手动返回的是一个引用数据类型值,则以自己返回的为主; */
// return {
// name: 'zhufeng'
// };
}
let f1 = new Fn(); //->0x000
let f2 = new Fn; //->0x001 new执行的时候,如果类不需要传递实参吗,可以不用加小括号(不加小括号,叫做无参数列表new;设置小括号,叫做带参数列表new;除了师是否传递参数的区别,在运算的优先级上也有区别? new Fn->19 new Fn()->20)
// 每一次new都是把函数重新执行(重新形成一个新的私有上下文、重新创建一个实例对象、代码重新执行...)
// console.log(f1, f2, f1 === f2); //=>false
检测成员
检测成员是否属于这个对象或者是否属于这个对象的私有属性
- in :检测成员是否属于这个对象(
'dd' in window
)检测公有属性和私有属性,如果存在则为true - hasOwnProperty:检测成员的私有属性(
f1.hasOwnProperty('say')
)只有私有属性才为true
如何检测一个成员是公有属性而不是私有属性
// obj:要检测的对象
// attr:要验证的成员
function hasPubProperty(obj, attr) {
// 思路一:是它的属性 但是还不是私有的,那么一定是公有的「BUG:如果某个属性即使私有的,也是公有的,则检测出来的结果是不准确的」
// return (attr in obj) && (!obj.hasOwnProperty(attr));
// 思路二:真正的思路应该是检测原型上的属性,因为原型上的属性都是公有的
// Object.getPrototypeOf:获取当前对象的原型
let proto = Object.getPrototypeOf(obj);
while (proto) {
// 依次查找原型链,直到找到Object.prototype为止
if (proto.hasOwnProperty(attr)) {
return true;
}
proto = Object.getPrototypeOf(proto);
}
return false;
}
题目
第一题
function C1(name) {
if (name) {
this.name = name;
}
}
function C2(name) {
this.name = name;
}
function C3(name) {
this.name = name || "join";
}
C1.prototype.name = "Tom";
C2.prototype.name = "Tom";
C3.prototype.name = "Tom";
alert(new C1().name + new C2().name + new C3().name);
第二题
let n = 10;
let m = n.plus(10).minus(5);
console.log(m); //=>15(10+10-5)
第三题
// 使用es6 语法 class 修改下面的代码
function Modal(x, y) {
this.x = x;
this.y = y;
}
Modal.prototype.z = 10;
Modal.prototype.getX = function () {
console.log(this.x);
};
Modal.prototype.getY = function () {
console.log(this.y);
};
Modal.n = 200;
Modal.setNumber = function (n) {
this.n = n;
};
let m = new Model(10, 20);
第四题
let obj = {
2: 3,
3: 4,
length: 2,
push: Array.prototype.push,
};
obj.push(1);
obj.push(2);
console.log(obj);
第五题
var a = ?;
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
答案和分析
// 第一题
// C1 new C1().name 没有传入name 因为有if判断,所以C1没有私有属性name,这个时候要向原型上查找 所以为 Tom
// C2 c2也没有传入name 但是还是设置this.name = undefined 所以 C2是undefined
// C3 C3添加了一个或 所以this.name = "join"
// 最后字符串拼接 答案是 Tomundefinedjoin
// 第二题
// 检查是不是数字
var validate = function validate(x) {
x = +x;
return isNaN(x) ? 0 : x;
};
Number.prototype.plus = function plus(x) {
x = validate(x);
// this都是对象数据类型的值 this->10/new Number(10)
return this + x;
};
Number.prototype.minus = function minus(x) {
x = validate(x);
return this - x;
};
let n = 10;
let m = n.plus(10).minus(5);
console.log(m); //=>15(10+10-5)
// 第三题
class Modal {
constructor(x, y) {
this.x = x;
this.y = y;
}
getX() {
console.log(this.x);
}
getY() {
console.log(this.xy);
}
static n = 200;
static setNumber(n) {
this.n = n;
}
}
Modal.prototype.z = 10;
// 第四题
let arr = [10, 20];
arr.push(30);
// Array.prototype.push 每次都向数组最后一位添加一位,并且数组累加
Array.prototype.push = function (value) {
// this == arr
// 把value 放在数组最后一位 this[this.length] = value
// length 累加
// 返回累加后的数组长度
};
let obj = {
2: 3,
3: 4,
length: 2,
push: Array.prototype.push,
};
obj.push(1); // this == obj value=1 length长度是2因为对象里面有定义length obj[2] = 1 obj.length = 3
obj.push(2); // this == obj value=2 obj[3] = 2 obj.length = 4
console.log(obj); // {2:1,3:2,length:4,push:function}
// 第五题 a = ? 才符合判断
/*
=== 绝对相等 必须类型和值都相等才可以相等
== 相等 左右两边类型不同,会先转化为相同的类型再比较
对象 == 字符串 对象转字符串
null == undefined 相等 但是和其他值都不相等
NaN == NaN false NaN 和谁都不相等
其他的都是转化为数字比较
对象 转 数字或者字符串
先调取属性 Symbol.toPrimitive
没有这个属性 再去调取valueOf 获取原始值(基本类型)
没有原始值 再去调用toString 变成字符串
如果最后是转化成数字 再去调用Number 把字符串转化为数字
*/
let obj = {};
var a = {
i: 0,
};
// Symbol.toPrimitive 可以替换为 valueOF 或者 toString 本质上都一样
a[Symbol.toPrimitive] = function (hint) {
// this==a
return ++this.i;
};
a.valueOf = function (hint) {
// this==a
return ++this.i;
};
a.toString = function (hint) {
// this==a
return ++this.i;
};
// 数据劫持
// + 在全局上下文中基于var/function声明变量,相当于给window设置对应的属性 -> window.a
// + Object.defineProperty劫持对象中某个属性的获取和设置等操作
var i = 0;
Object.defineProperty(window, "a", {
get() {
// 获取window.a的时候触发getter函数
return ++i;
},
// set(value) {
// // 设置window.a属性值的时候触发setter函数
// }
});
if (a == 1 && a == 2 && a == 3) {
console.log("OK");
}