链式操作
如是实现「对象.方法.方法.方法」这样的链式反操作呢?
可以在方法内返回对象的形式。
var sched = {wakeup: function () {console.log("跑步");return this;},morning: function () {console.log("去购物");return this;},noon: function () {console.log("休息一下");return this;},};sched.wakeup().morning().noon();
对象相关的方法和属性
for…in…
:::info
for...in...方法可以用来遍历对象。
:::
var car = {brand: "Benz",color: "red",displacement: "3.0",lang: 5,width: 2.5,};for (const key in car) {console.log(car[key]); // "Benz" "red" "3.0" 5 2.5}
**for...in...**遍历会把对象原型上的属性都打印出来!!!
Object.prototype.name = "TestPrototypeAttribute"var car = {brand: "Benz",color: "red",displacement: "3.0",lang: 5,width: 2.5,};for (const key in car) {console.log(car[key]); // "Benz" "red" "3.0" 5 2.5 TestPrototypeAttribute}
**ECMAScript**中对象的属性是无序的,所有可枚举的属性都会返回一次,但返回的顺序可能会因浏览器而异。
如果for...in...循环要迭代的变量是null或undefined,则不执行循环体。
for...in...也可以用来遍历数组:
var arr = [1, 2, 3, 4, 5];for (const key in arr) {console.log(key); // 1 2 3 4 5}
obj.hasOwnProperty()
:::info
Object的原型方法。hasOwnProperty()用来判断实例对象本身是否包含某个属性(该方法不会到原型上进行查询)
:::
var obj = {name: "job",age: 32,};console.log(obj.hasOwnProperty(obj.name)); // true
Object.prototype.name = "Object";Car.prototype = {lang: 5,width: 2.5,};function Car() {this.brand = "Benz";this.color = "red";this.displacement = "3.0";}var car = new Car();console.log(car); // Car {brand: 'Benz', color: 'red', displacement: '3.0'}// 如果不用 hasOwnProperty() 方法然后遍历 car 实例对象的属性for (const key in car) {console.log(car[key]); // "Benz" "red" "3.0" 5 2.5 Object}// 使用 hasOwnProperty() 方法判断属性是否属于实例对象本身for (const key in car) {// 只要实例化对象本身的属性if (car.hasOwnProperty(key)) {console.log(car[key]); // "Benz" "red" "3.0"}}
in 语句
:::info
in用来判断实例对象是否包含某个属性,该语句和hasOwnProperty最大的区别就是in语句会到实例对象的原型上查找属性(会到原型上寻找)
:::
var car = {brand: "Benz",color: "red",};// 类似 car["displacement"]console.log("displacement" in car); // false
Car.prototype.displacement = "3.0";function Car() {this.brand = "Benz";this.color = "red";}var car = new Car();console.log("displacement" in car); // true
instanceof 语句
:::info
instanceof语句用来判断某个对象是否是某个构造函数的实例对象。(类似A对象的原型里到底有没有B构造函数的原型,原型链的关系)
:::
instanceof 的原理
function Car() {}var car = new Car();console.log(car instanceof Car); // trueconsole.log(car instanceof Object); // trueconsole.log([] instanceof Array); // trueconsole.log([] instanceof Object); // trueconsole.log({} instanceof Object); // true
所以这就导致了关系不是特别的明确,因为任何对象的原型链顶端都是Object.prototype
更靠谱的方式是调用Object.prototype.toString()方法。
var a = [];console.log(a.constructor);console.log(a instanceof Array);console.log(Object.prototype.toString.call(a)); // 使用 call 改变 this 指向为 aif(Object.prototype.toString.call(a) === "[object Array]"){alert("是数组!")}
因为Array构造函数重写了toString方法,所以我们只能调用Object.prototype.toString()方法。
this 指向
再谈谈this指向的问题
普通函数内部的this默认指向window
function test(b) {var a = 1;var b = b;function c() {}this.d = 3; // window.d = 3}test(123);console.log(d); // 3,函数外部是可以直接访问到 d 变量的// 预编译的过程/*** AO = {* this: window,* argument: [123]* a: undefind,* b: undefind, => 123* c: function* }* GO = {* d: 3* }*/
构造函数内部的this指向实例化对象
function Test() {this.name = 123;}var test = new Test();/*** 实例化对象的执行过程** 1、创建 this 对象* var this = {}** 2、赋值原型* var this = {__proro__: Test.prototype}** 3、属性赋值* var this = {__proro__: Test.prototype, name: 123}** 4、返回 this 并指向实例化对象**/// 预编译的过程/*** Test 函数的 AO = {* this: {window 对象} => {__proro__: Test.prototype, name: 123}* }* GO = {* Test: function* test: undefind => {name: 123}* }*/
callee
:::info
callee的作用是指向当前所在函数的引用
:::
function test(a, b, c) {console.log(arguments.callee); // 指向当前所在的函数// ƒ test(a, b, c) { ... }console.log(arguments.callee.length); // 3,形参的长度console.log(test.length); // 3,形参的长度console.log(arguments.length); // 2,实参的长度}test(1, 2);
function test1() {// 指向 test1 函数的引用console.log(arguments.callee);// ƒ test1() {// console.log(arguments.callee);// function test2() {// console.log(arguments.callee);// }test2()}function test2() {// 指向 test2 函数的引用console.log(arguments.callee);// ƒ test2() {// console.log(arguments.callee);// }}test2()}test1()
某些时候在使用立即执行函数+递归时比较有用,比如实现函数实现 n-1 的累加
// 普通函数的实现方式function test1() {console.log(arguments.callee);function test2() {console.log(arguments.callee);}test2()}test1()// 立即执行函数的实现方式var sum = (function (n) {if (n <= 1) {return 1;}// 当不知道函数名的时候如何递归?// 可以调用 callee 属性来拿到当前函数的引用return n + arguments.callee(n - 1);})(10);console.log(sum)
caller
:::info
caller属性返回函数被调用是所在的函数的引用
:::
test1();function test1() {test2();}function test2() {// 返回当前被调用 test2 函数的函数引用// 必须放到一个执行函数内,放到全局无效console.log(test2.caller);}// 放在全局下无效test3()function test3() {console.log(test3.caller); // null}
